Hi All,
Can you give me some hints (code snippet in Arcpy or ArcObject) on:
for a given point to find the closest point location on a line feature.
Thanks in advance!
George
Solved! Go to Solution.
What license level is available?
What license level is available?
ArcEditor (or "standard" ).
Near—Help | ArcGIS for Desktop Is a good place to start if you have the advanced level (which is why Darren asked). There are several samples of using python code.
if you don't have advanced, then it will take a bit more work.
For a python approach, simply
Assume a start location at the origin, and projected coordinates (values have been translated to the origin to simplify the visuals and the math)
>>> import numpy as np >>> origin = np.array([0,0],dtype="float64") >>> dests = np.array([[1,2],[-3,3],[-4,-4],[1,1],[5,-5]],dtype="float64") >>> deltas = dests - origin >>> distances = np.hypot(deltas[:,0], deltas[:,1]) >>> min_dist = np.min(distances) >>> wh = np.where(distances == min_dist) >>> closest = dests[wh[0]] >>> closest array([[ 1., 1.]]) >>>
line (02) that is the origin
line (03 ) the destinations of the points constituting the polyline
line (04) get the coordinate differences)
line (05) calculate the distances, note the np.hypot uses dy,dx as inputs
line (06) find the minimum distance
line(07) find where the min distance is
line(08) use the position of the min distance to slice the original destinations. ( note wh returns a tuple and you want the first element)
the closest point...obviously is 1,1
see other purely arcpy options.
I'm not sure, but I believe this will only get you the closest vertex, not the closest location on a line (which doesn't necessarily mean a vertex). You need to do some trig in between each vertex. But, I could be missing some of the numpy magic going on here.
I left that part out ... but I will post about it soon. In the interim, George found your solution with the wrong license level worked for him.
Well, I don't believe I answered the question, but maybe thinking about license-levels did the trick...? Anyhow, I'd be interested to see what this looks like through numpy.
will do, the example I gave was for non-sequential points... caught it too late. But if you want to experiment for sequential points consider a polyline consisting of points a,b,c,d and a source point X
I have simplified some checks, but you can incorporate extent checks to see which segments of the polyline contain space that X can project on to. Remember, this is projection onto a segment and not a imaginary line extending from it. So soon, it is an interesting comparison of numpy solution and Near tool
Dan:
I was trying to use your code, since I want to find the minimum distance to the actual vertice points in a polyline with the onMouseDownMap function of an addin tool. Here is the code I tried:
class SplitLineToolClass(object): """Implementation for SplitLine_addin.SplitLinetool (Tool)""" def __init__(self): self.enabled = False self.cursor = 3 # Crosshairs def onMouseDownMap(self, x, y, button, shift): # Pass if not a Left Mouse Button Click if button != 1: pass return addressLines = pythonaddins.GetSelectedTOCLayerOrDataFrame() ## Code that verifies a polyline layer is selected in the TOC desc=arcpy.Describe(addressLines) sr = arcpy.SpatialReference(desc.spatialReference.factoryCode) origin = np.array([x,y],dtype="float64") dests = arcpy.da.FeatureClassToNumPyArray(addressLines, ["SHAPE@X","SHAPE@Y"], "", sr, explode_to_points=True) deltas = dests - origin distances = np.hypot(deltas[:,0], deltas[:,1]) min_dist = np.min(distances) wh = np.where(distances == min_dist) closest = dests[wh[0]] print("Closest Vertice = {0}".format(closest))
However, my adaptation of your code is throwing an error on the line that subtracts the two arrays (deltas = dests - origin on line 18 of the code above). Here is the error:
Traceback (most recent call last):
File ..., line ..., in onMouseDownMap
deltas = dests - origin
TypeError: unsupported operand type(s) for -: 'numpy.ndarray' and 'numpy.ndarray'
When I added print lines for the origin and dest arrays, it showed that the Origin array created by line 16 is a list with a space a number a double space and a number, while the Dest array was a list of tuples containing two numbers separated by a comma and a space. What is the best way to get the two arrays compatible for line 18?
Here is how the arrays printed:
Origin Point = [ 6305489.12520918 2169986.76545799]
Destination Points = [(6305087.957613736, 2169963.2243613005)
(6305515.50958015, 2169962.629874304)
...
(6305742.797839478, 2169860.239002958)]
When I tried the "SHAPE@XY" field instead the result seemed worse:
Destination Point = [([6305087.957613736, 2169963.2243613005],)
([6305515.50958015, 2169962.629874304],)
...
([6305742.797839478, 2169860.239002958],)]