ArcGIS 10.1 – Creating Perpendicular Line from Points to Existing Line

arcgis-10.1arcpybasic-license-level

I would like to create perpendicular lines from points to line, similar to this:

Result

I have ArcGIS 10.1, so "queryPointAndDistance" doesn´t work for me, and basic licence level, so I can´t use "Generate Near Table" neither.

I thought about following approach:

  • Coordinates X1Y1 are known (coordinates of the point feature)
  • acquire X2Y2 coordinates of the closest point on the line segment
  • create line feature from X1Y1 to X2Y2
  • new line feature is perpendicular to existing line

I tried to use "distanceTo" method from point feature to line feature, but I was unable to aquire coordinates of the closest point of the line segment (X2Y2), which should be used during "distanceTo" method.
Is it possible to get coordinates of the closest point on the line segment from "distanceTo" method or should I use another approach?

point_feature = "points_select"
line_feature = "line_select"

pointcursor = arcpy.da.SearchCursor(point_feature, ['SHAPE@'])        

for row in pointcursor:
      geometry = pointcursor[0]
      linecursor = arcpy.da.SearchCursor(line_feature, ['SHAPE@'])
      for row in linecursor:
          newgeometry = linecursor[0]
          dist = newgeometry.distanceTo(geometry)
      print dist

Best Answer

It took below script 3 seconds to find 100 nearest points on the line. It uses positionAlongLine method on geometry which I believe available in 10.1

SCRIPT:

import  arcpy, math
from arcpy import env
env.overwriteOutput = True
# LAYERS IN TOC OF MXD
points,pipes,connections="PARC_POINTS","PIPES","CONNECTIONS"
sj=r"in_memory\sj"
# golden section method to find minimum of function below
gr,hypot=(math.sqrt(5)-1)/2,math.hypot
def gss(a,b,tol):
    c=b-gr*(b-a)
    d=a+gr*(b-a)
    while abs(c-d)>tol:       
        fc=f(c);fd=f(d)
        if fc<fd:
            b,d=d,c
            c=b-gr*(b-a)
        else:
            a,c=c,d
            d=a+gr*(b-a)
    return (b+a)/2
# function to minimise
def f(x):
    theP=pipe.positionAlongLine(x).firstPoint
    dist=hypot(x1-theP.X,y1-theP.Y)
    return dist
# find pipe nearest to point. NOTE: field PIPE_ID in pipes is INTEGER!
arcpy.SpatialJoin_analysis(points, pipes, sj, "JOIN_ONE_TO_ONE",
                           "KEEP_ALL", """PIPE_ID "PIPE_ID" true true false 5 Short 0 5 ,First,#,PIPES,PIPE_ID,-1,-1""",
                           "CLOSEST")
curT=arcpy.da.InsertCursor(connections,"Shape@")
# shuffle through points
with arcpy.da.SearchCursor(sj,["Shape@","PIPE_ID"]) as cursor:
    for pG,pipeID in cursor:
        p1=pG.firstPoint
        x1,y1=p1.X,p1.Y
        dq ='"PIPE_ID"=%s'%pipeID
        with arcpy.da.SearchCursor(pipes,"Shape@", dq) as pipeCursor:
            for row in pipeCursor:pipe=row[0];break
        L=pipe.length
# find nearest point on pipe (accurate to 1 cm, see last value)
        chainage=gss(0.0,L,0.01)
        p2=pipe.positionAlongLine(chainage).firstPoint
# and connect original point to it by line
        arr=arcpy.Array([p1,p2])
        perpendicular=arcpy.Polyline(arr)
        curT.insertRow((perpendicular,))

OUTPUT:

enter image description here

I hope script is documented well enough to understand naming conventions and must have field.