Here's the code for the Python add-in I was referring to. Keep in mind that it is meant to work with our own data, so it would require significant changes to perform similarly with someone else's data.
#ShieldToolAddin.py
#By Kerry Alley 2013-03-12
#Vermont Agency of Transportation
#
#Python Add-In for ArcMap 10.1, 10.2
#
#SELECT_ROAD (button)
#When activated, will select features within 20 map-meters of the mouse click on the map.
#The features are selected only from the top-most layer with the GDB_HMS.HMSADMIN.rdsmall_arc
# data source, regardless of layer name.
#
#CREATE_SHIELD (button)
#Requires that a single rdsmall_arc feature already be selected
#User makes a single click on the map to indicate the location of the highway shield, and
# makes a double-click where the leader line extending from the highway shield will end.
#Both a point feature and a line feature are created, with relevant attributes transferred
# from the selected rdsmall_arc feature.
#There is an un-commentable option in this script that sets the length of the leader line to
# a fixed length, for uniformity.
#
#NOTE: This addin works "normally" if there is not an active editing session in ArcMap, but if
# there is an active editing session, the addin "crashes" at the call to stopEditing(). The
# features will still be created, but the screen will not refresh if there is a pre-existing
# editing session active.
import arcpy, time, os, math
import pythonaddins
class SelectRoadClass(object):
"""Implementation for ShieldToolAddinA_addin.tool (Tool)"""
def __init__(self):
self.enabled = True
self.shape = "NONE"
def onMouseDownMap(self, x, y, button, shift):
#start_time = time.time() #only used to compare run-times of different versions of the script
arcpy.env.overwriteOutput = True
rdsmall_dataSource = r"GDB_HMS.HMSADMIN.rdsmall_arc"
mxd = arcpy.mapping.MapDocument('current')
flag_rdsmall = 0 #flag_rdsmall is used to flag the first occurence of a layer having the desired dataSource in TOC
for lyr in arcpy.mapping.ListLayers(mxd):
if lyr.supports("dataSource"):
if str(lyr.dataSource).endswith(rdsmall_dataSource) and not flag_rdsmall:
rdsmall_lyr = lyr
flag_rdsmall = 1
point = arcpy.Point()
point.X = x
point.Y = y
pointGeometry = arcpy.PointGeometry(point)
arcpy.SelectLayerByLocation_management(rdsmall_lyr, "WITHIN_A_DISTANCE", pointGeometry, "20 Meters", "NEW_SELECTION")
#print time.time() - start_time, "seconds"
class CreateShieldClass(object):
"""Implementation for ShieldToolAddinB_addin.tool (Tool)"""
def __init__(self):
self.enabled = True
self.cursor = 3
self.shape = "LINE"
def onLine(self, line_geometry):
#start_time = time.time() #only used to compare rough run-times of different versions of the script
arcpy.env.overwriteOutput = True
#Hard-wiring the exact feature classes that will be edited with shield tool.
shield_points_dataSource = r"GDB_HMS.HMSADMIN.hms_shields_points"
shield_arcs_dataSource = r"GDB_HMS.HMSADMIN.hms_shields_arcs"
rdsmall_dataSource = r"GDB_HMS.HMSADMIN.rdsmall_arc"
mxd = arcpy.mapping.MapDocument('current')
#for new shields to appear in current mxd, this script must refer to layers in the current mxd
lyrs = arcpy.mapping.ListLayers(mxd)
flag_points = 0
flag_arcs = 0
flag_rdsmall = 0
for lyr in arcpy.mapping.ListLayers(mxd):
if lyr.supports("dataSource"):
if str(lyr.dataSource).endswith(shield_points_dataSource) and flag_points == 0:
shield_points_lyr = lyr
flag_points = 1
if str(lyr.dataSource).endswith(shield_arcs_dataSource) and flag_arcs == 0:
shield_arcs_lyr = lyr
flag_arcs = 1
if str(lyr.dataSource).endswith(rdsmall_dataSource) and flag_rdsmall == 0:
rdsmall_lyr = lyr
flag_rdsmall = 1
if not (shield_points_lyr and shield_arcs_lyr and rdsmall_lyr):
print "Must have 3 layers in this mxd: shield points, shield arcs, and rdsmall"
#only allow shield creation if a single road arc is selected
num_road_arcs = int(arcpy.GetCount_management(rdsmall_lyr).getOutput(0))
print "%s rdsmall arc(s) selected" %num_road_arcs
if num_road_arcs == 1:
workspace = rdsmall_lyr.workspacePath #(refers to .sde file in DatabaseConnections)
arcpy.env.workspace = workspace
edit = arcpy.da.Editor(workspace)
edit.startEditing(True, True) #with undo, multiuser mode
#identify maximum SHI_GRP_ID value currently used in shields feature class
max_id = sorted(arcpy.da.SearchCursor(shield_points_lyr.dataSource, "SHI_GRP_ID"), reverse = 1)[0][0]
#print max_id + 1
#collect selected road arc attributes
rdsmall_values = sorted(arcpy.da.SearchCursor(rdsmall_lyr, ["UA", "FAID_S", "CTCODE", "RTNUMBER", "AOTCLASS"]))
#uncomment the last line of this block of code to turn off the truncation of the leader line
#determine line coordinates, slope, and truncated line geometry based on first and last point.
a_pt = line_geometry.firstPoint
b_pt = line_geometry.lastPoint
slope = (b_pt.Y - a_pt.Y)/(b_pt.X - a_pt.X)
theta = math.atan(slope)
#fixed_length = 150.
fixed_length = 185.
if b_pt.X - a_pt.X < 0:
x = fixed_length * math.cos(theta) * -1
y = fixed_length * math.sin(theta) * -1
else:
x = fixed_length * math.cos(theta)
y = fixed_length * math.sin(theta)
point = arcpy.Point()
point.X = a_pt.X + x
point.Y = a_pt.Y + y
array = arcpy.Array()
array.add(line_geometry.firstPoint)
array.add(point)
fixed_line = arcpy.Polyline(array)
#To remove the constraint of fixed shield arc lengths, uncomment the following line:
fixed_line = line_geometry #this line reverts the fixed_line to the original input geometry
#create shield point feature and populate attributes
new_points_Cur = arcpy.da.InsertCursor(shield_points_lyr, ["SHAPE@XY", "UA", "FAID_S", "CTCODE", "RTNUMBER", "AOTCLASS", "SHI_GRP_ID", "INSET", "ISVISIBLE", "SUBINSET"])
test = (fixed_line.firstPoint,) + tuple(rdsmall_values) + (max_id + 1,)
test_tuple = ((test[0].X, test[0].Y), test[1][0], test[1][1], str(test[1][2]), str(test[1][3]), test[1][4], test[2], "N", 1, "N")
#test_tuple = ((test[0].X, test[0].Y), rdsmall_values[0], str(rdsmall_values[2]), str(rdsmall_values[3]), rdsmall_values[4], max_id + 1, "N", 1, "N")
edit.startOperation()
new_points_Cur.insertRow(test_tuple)
edit.stopOperation()
del new_points_Cur
#create shield arc feature and populate SHI_GRP_ID, CTCODE, UA, INSET, ISVISIBLE, and SUBINSET fields
new_arc_Cur = arcpy.da.InsertCursor(shield_arcs_lyr.dataSource, ["SHAPE@", "SHI_GRP_ID", "CTCODE", "UA", "INSET", "ISVISIBLE", "SUBINSET"])
edit.startOperation()
new_arc_Cur.insertRow([fixed_line, max_id + 1, str(rdsmall_values[0][2]), rdsmall_values[0][0], "N", 1, "N"])
edit.stopOperation()
del new_arc_Cur
edit.stopEditing(True) #save changes (doesn't work if an editing session is open in ArcMap, but )
arcpy.SelectLayerByAttribute_management(rdsmall_lyr, "CLEAR_SELECTION")
arcpy.RefreshActiveView()
else:
print "Shield Not Created"
print "Must select a single arc from rdsmall"
#print time.time() - start_time, "seconds"