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?