I am working on a Python Add-In using ArcGIS 10.2.2 where the user can draw lines and the Add-In will add dimension annotation showing length for each segment of the line that is drawn. I can get this working just fine and the text is angled properly, but the OnLine() method does not use snapping in the map. The add-in does however, properly set the snapping (I verified the snapping tolerance in the map and tested with different tolerances) in the map for everything BUT the onLine() method for the tool.
In the ArcObjects help docs, it says this is usually invoked on a OnClick method from the ICommand Interface. I do not know how I could use this in a Python Add-In. Here is my attempt to use comtypes and some custom modules to invoke snapping for my Add-In. Unfortunately, it is not working. Maybe I should attempt this in .NET?
import arcobjects #custom module from arcobjects import elements #custom module import arcpy import pythonaddins import math import comtypes.gen.esriControls as esriControls import comtypes.gen.esriArcMapUI as esriArcMapUI from arcobjects import CType, NewObj, CLSID #custom def midpoint(point_a, point_b): x1 = point_a.X y1 = point_a.Y x2 = point_b.X y2 = point_b.Y # Find midpoint x = (x1 + x2) / 2.0 y = (y1 + y2) / 2.0 return (x, y) def get_angle(xy1, xy2): """Calculate azimuth angle from two points. (Zero is north.)""" # ArcPy point objects x1, y1, x2, y2 = xy1.X, xy1.Y, xy2.X, xy2.Y dx, dy = (x2 - x1, y2 - y1) return math.degrees(math.atan2(dy, dx)) class DrawLine(object): """Implementation for AddMeasurementAnno_addin.tool (Tool)""" def __init__(self): self.enabled = True self.shape = 'Line' self.cursor = 3 # arcobjects get current app (IApplication interface Pointer) self.pApp = arcobjects.GetCurrentApp() self.pDoc = self.pApp.Document self.pMxDoc = CType(self.pDoc, esriArcMapUI.IMxDocument) m_SnappingEnv = NewObj(esriControls.Snapping, esriControls.ISnappingEnvironment) m_SnappingEnv.Enabled = True m_SnappingEnv.IgnoreIMSLayers = True m_SnappingEnv.ShowSnapTips = True m_SnappingEnv.ShowSnapTipBackground = True m_SnappingEnv.Tolerance = 10 m_SnappingEnv.SnappingType = esriControls.esriSnappingTypeVertex + \ esriControls.esriSnappingTypeEndpoint + \ esriControls.esriSnappingTypeEdge print m_SnappingEnv.SnappingType m_Snapper = m_SnappingEnv.PointSnapper m_SnappingFeedback = NewObj(esriControls.SnappingFeedback, esriControls.ISnappingFeedback) m_SnappingFeedback.Initialize(self.pMxDoc, m_SnappingEnv, True) def onLine(self, line_geometry): # Report back mouse position at line endpoint # m_CurrentMouseCoords = self.pMxDoc.CurrentLocation print m_CurrentMouseCoords.X, m_CurrentMouseCoords.Y # loop through geom and grab vertices for part in line_geometry: for i in range(part.count): if i != (part.count - 1): pt1, pt2 = part.getObject(i), part.getObject(i+1) line = arcpy.Polyline(arcpy.Array([pt1, pt2])) length = str(round(line.length,1)) + "'" x, y = midpoint(pt1, pt2) elements.add_text(self.pApp, text=length, name='length', size=9, bold=True, x=x, y=y, angle=get_angle(pt1, pt2), view='data')
Here is what it does in ArcMap, but the distances are not correct because the line was not snapped. Without snapping this Add-In is pretty useless:
And the snap options window:
Has anyone had success in doing this?