This is my first time coding in python, so bear with me. I wrote a script to calculate an analytical solution to find the orientation of a plane based on three points. I'm using ArcGIS 10.1.
# Input points
x1 = float(arcpy.GetParameterAsText(1)) # Point 1
y1 = float(arcpy.GetParameterAsText(2))
z1 = float(arcpy.GetParameterAsText(3))
x2 = float(arcpy.GetParameterAsText(4)) # Point 2
y2 = float(arcpy.GetParameterAsText(5))
z2 = float(arcpy.GetParameterAsText(6))
x3 = float(arcpy.GetParameterAsText(7)) # Point 3
y3 = float(arcpy.GetParameterAsText(8))
z3 = float(arcpy.GetParameterAsText(9))
# Plane equation
A = (y1*z2) + (z1*y3) + (y2*z3) - (z2*y3) - (z3*y1) - (z1*y2)
B = (z2*x3) + (z3*x1) + (z1*x2) - (x1*z2) - (z1*x3) - (x2*z3)
C = (x1*y2) + (y1*x3) + (x2*y3) - (y2*x3) - (y3*x1) - (y1*x2)
D = (z1*y2*x3) + (z2*y3*x1) + (z3*y1*x2) - (x1*y2*z3) - (y1*z2*x3) - (z1*x2*y3)
E = np.sqrt(A**2 + B**2 + C**2)
AZ = np.arctan(A/B) * (180/np.pi) # Preliminary azimuth for dip direction
dip = np.arcsin(-np.cos((np.pi/2) + np.arccos(C/E))) * (180/np.pi) # True dip
# Test for quadrant
alpha = A/E
beta = B/E
# Place dip-direction in proper quadrant
if alpha > 0 and beta > 0:
DD = AZ
elif alpha > 0 and beta < 0:
DD = 180 + AZ
elif alpha < 0 and beta < 0:
DD = 180 + AZ
elif alpha < 0 and beta > 0:
DD = 360 + AZ
# Right-hand rule strike
if DD - 90 < 0:
RHR = 360 + (DD - 90)
else:
RHR = DD - 90
# Centroid coordinates
Cx = (x1+x2+x3)/3
Cy = (y1+y2+y3)/3
Cz = (z1+z2+z3)/3
# Insert centroid point
cursor = arcpy.InsertCursor(arcpy.GetParameterAsText(0)) # Feature class must already exist
row = cursor.newRow()
row.Shape = arcpy.Point(Cx,Cy,Cz)
# Populate table
row.X = Cx
row.Y = Cy
row.Z = Cz
row.DD = DD
row.dip = dip
row.RHR = RHR
cursor.insertRow(row)
del cursor, row
# Refresh MXD
arcpy.RefreshTOC()
arcpy.RefreshActiveView()
This works, except that the user has to hover each point and manually enter the coordinates. Ideally, I would like: (1) the user initially define the target feature layer in a pop-up menu, and hit OK; (2) click on the map to extract the first XY map coordinates; (3) pop-up queries the user for the first Z, hit OK; (4) click on the map to extract the second XY map coordinates; (5) pop-up queries the user for the second Z, hit OK; (6) click on the map to extract the last XY map coordinates; (7) pop-up queries the user for the last Z, hit OK; then (8) the script runs to completion.
I found the ESRI tool tutorial that allows the map XY to be displayed on a message box after a mouse-click:
import arcpy
import pythonaddins
class MC(object):
"""Implementation for MouseClickSample_addin.MCtool (Tool)"""
def __init__(self):
self.enabled = True
self.shape = "NONE" # Can set to "Line", "Circle" or "Rectangle" for interactive shape drawing and to activate the onLine/Polygon/Circle event sinks.
def onMouseDownMap(self, x, y, button, shift):
message = "Your mouse clicked:" + str(x) + ", " + str(y)
pythonaddins.MessageBox(message, "My Coordinates")
I cannot figure out how this Python Add-in can pass the XY variables as input to my script.
-
1You should try implementing this as a Python Add-in. They allow user interaction.Fezter– Fezter2013年10月08日 06:12:20 +00:00Commented Oct 8, 2013 at 6:12
-
@Fezter: The Python Addins I checked out was the Tool, which I got to display the XY coordinates on mouse click, but could do nothing else beyond that (this could be because of my limited knowledge on python); and the Button, which I could not get an XY position on a mouse-click. All the other Addins seem like it didn't fit the kind of UI this script needs.Jefferson– Jefferson2013年10月08日 06:18:58 +00:00Commented Oct 8, 2013 at 6:18
-
This doesn't seem to work for me in Layoutview - I get page coordinates not map coordinates - how can I fix this??dklassen– dklassen2014年08月07日 21:43:53 +00:00Commented Aug 7, 2014 at 21:43
2 Answers 2
You can get the coordinates a mouse click via the onMouseDownMap()
function of the Tool Class for Python add-ins.
The x and y values for onMouseDownMap and onMouseUpMap represent the map coordinates where the button was pressed or released.
Since you are already creating scripts in Python, it's not much more learning to implement this is an add-in. It's a little bit trickier to debug code, but there is some awesome uses for it, as shown in this video, Developing Python Add-ins. If my memory serves, there is an example where they grab the coordinates of the map.
-Edit: Actually, it's this video, around the 40 minute mark. I'd recommend watching both though.
-
That is more promising that anything I've seen! I'll see if I can figure it out from their tutorial.Jefferson– Jefferson2013年10月08日 06:30:15 +00:00Commented Oct 8, 2013 at 6:30
-
@Jefferson, let us know how it turns out. I'll post some code (it's on my school computer) after my class tomorrow if you are still stuck. There's definitely a learning curve.Paul– Paul2013年10月08日 06:41:06 +00:00Commented Oct 8, 2013 at 6:41
-
The second video was very helpful.Richard Fairhurst– Richard Fairhurst2016年03月23日 21:36:37 +00:00Commented Mar 23, 2016 at 21:36
Everything is done through a single toolbar, via 8 tools. Much thanks to Paul for turning me on to those videos. I ended up using 4 combo boxes for text input, 3 tools to store the XY's, and a push button to implement the script.
Toolbar
import numpy as np
import arcpy
import pythonaddins
class Calculate(object):
"""Implementation for ThreePointProblem_addin.calculatebtn (Button)"""
def __init__(self):
self.enabled = True
self.checked = False
def onClick(self):
# Input points
x1 = float(xy1tool.x1) # Point 1
y1 = float(xy1tool.y1)
z1 = float(z1cmb.text)
x2 = float(xy2tool.x2) # Point 2
y2 = float(xy2tool.y2)
z2 = float(z2cmb.text)
x3 = float(xy3tool.x3) # Point 3
y3 = float(xy3tool.y3)
z3 = float(z3cmb.text)
# Plane equation
A = (y1*z2) + (z1*y3) + (y2*z3) - (z2*y3) - (z3*y1) - (z1*y2)
B = (z2*x3) + (z3*x1) + (z1*x2) - (x1*z2) - (z1*x3) - (x2*z3)
C = (x1*y2) + (y1*x3) + (x2*y3) - (y2*x3) - (y3*x1) - (y1*x2)
D = (z1*y2*x3) + (z2*y3*x1) + (z3*y1*x2) - (x1*y2*z3) - (y1*z2*x3) - (z1*x2*y3)
E = np.sqrt(A**2 + B**2 + C**2)
AZ = np.arctan(A/B) * (180/np.pi) # Preliminary azimuth for dip trend
dip = np.arcsin(-np.cos((np.pi/2) + np.arccos(C/E))) * (180/np.pi) # True dip
# Test for quadrant
alpha = A/E
beta = B/E
# Place dip-direction in proper quadrant
if alpha > 0 and beta > 0:
DD = AZ
elif alpha > 0 and beta < 0:
DD = 180 + AZ
elif alpha < 0 and beta < 0:
DD = 180 + AZ
elif alpha < 0 and beta > 0:
DD = 360 + AZ
# Right-hand rule strike
if DD - 90 < 0:
RHR = 360 + (DD - 90)
else:
RHR = DD - 90
# Centroid coordinates
Cx = (x1+x2+x3)/3
Cy = (y1+y2+y3)/3
Cz = (z1+z2+z3)/3
# Insert centroid point
cursor = arcpy.InsertCursor(pointlayercmb.layername) # Feature class must already exist
row = cursor.newRow()
row.Shape = arcpy.Point(Cx,Cy,Cz)
# Populate table
row.X = Cx
row.Y = Cy
row.Z = Cz
row.DD = DD
row.dip = dip
row.RHR = RHR
cursor.insertRow(row)
del cursor, row
# Refresh MXD
arcpy.RefreshTOC()
arcpy.RefreshActiveView()
# Refresh elevations
z1cmb.refresh()
z2cmb.refresh()
z3cmb.refresh()
class Elevation1(object):
"""Implementation for ThreePointProblem_addin.z1cmb (ComboBox)"""
def __init__(self):
self.items = []
self.editable = True
self.enabled = True
self.dropdownWidth = 'WWWWW'
self.width = 'WWWWW'
def onEditChange(self, text):
self.text = text
def refresh(self):
self.value = " "
class Elevation2(object):
"""Implementation for ThreePointProblem_addin.z2cmb (ComboBox)"""
def __init__(self):
self.items = []
self.editable = True
self.enabled = True
self.dropdownWidth = 'WWWWW'
self.width = 'WWWWW'
def onEditChange(self, text):
self.text = text
def refresh(self):
self.value = " "
class Elevation3(object):
"""Implementation for ThreePointProblem_addin.z3cmb (ComboBox)"""
def __init__(self):
self.items = []
self.editable = True
self.enabled = True
self.dropdownWidth = 'WWWWW'
self.width = 'WWWWW'
def onEditChange(self, text):
self.text = text
def refresh(self):
self.value = " "
class PointLayer(object):
"""Implementation for ThreePointProblem_addin.pointlayercmb (ComboBox)"""
def __init__(self):
self.items = []
self.editable = False
self.enabled = True
self.dropdownWidth = 'WWWWWWWWW'
self.width = 'WWWWWWWWW'
self.mxd = arcpy.mapping.MapDocument('Current')
layers = arcpy.mapping.ListLayers(self.mxd)
for layer in layers:
pointlayercmb.items.append(layer.name)
def onSelChange(self, selection):
self.layername = selection
class SelectPoint1(object):
"""Implementation for ThreePointProblem_addin.xy1tool (Tool)"""
def __init__(self):
self.enabled = True
self.cursor = 3
def onMouseDownMap(self, x, y, button, shift):
self.x1 = x
self.y1 = y
print "Point 1: " + str(x) + ", " + str(y)
class SelectPoint2(object):
"""Implementation for ThreePointProblem_addin.xy2tool (Tool)"""
def __init__(self):
self.enabled = True
self.cursor = 3
def onMouseDownMap(self, x, y, button, shift):
self.x2 = x
self.y2 = y
print "Point 2: " + str(x) + ", " + str(y)
class SelectPoint3(object):
"""Implementation for ThreePointProblem_addin.xy3tool (Tool)"""
def __init__(self):
self.enabled = True
self.cursor = 3
def onMouseDownMap(self, x, y, button, shift):
self.x3 = x
self.y3 = y
print "Point 3: " + str(self.x3) + ", " + str(y)
class UpdateLayers(object):
"""Implementation for ThreePointProblem_addin.layersext (Extension)"""
def __init__(self):
# For performance considerations, please remove all unused methods in this class.
self.enabled = True
def itemAdded(self, new_item):
pointlayercmb.items.append(new_item.name)
pointlayercmb.refresh()
def itemDeleted(self, deleted_item):
pointlayercmb.items.remove(deleted_item.name)
pointlayercmb.refresh()
Explore related questions
See similar questions with these tags.