[GIS] Calculating angle of polyline at midpoint using Python/ArcPy

arcgis-desktoparcpymathematicspython

Trying to calculate the angle of a line at its mid point using python; this will be used to display flow direction on a water network.

I've developed this script, which works in terms of generating the correct output, however, the angle returned is incorrect. I am currenlty getting some negative values, where I would like to have outputs of 0 to 360, in either an Arithmetic or Geographic format.

#OperationAlligator.py
import arcpy, math, datetime, numpy
from arcpy import env

print ("starting")
start = datetime.datetime.now() # for calculating time of process

#setting the test sources
flowArrow = r"J:\PYTHON\Flow_Direction.gdb\test" # pre-added fields "angle"
pipes = r"J:\PYTHON\Flow_Direction.gdb\Pipes"

#UpdateCursor
rows = arcpy.UpdateCursor(pipes)
updateRows_FlowArrow = arcpy.UpdateCursor(flowArrow)


#housekeeping
arcpy.DeleteFeatures_management(flowArrow)
arcpy.env.overwriteOutput = True


#Creating the physical xy locations in memory
shapeName = arcpy.Describe(pipes).shapeFieldName
for row in rows:
    feat = row.getValue(shapeName)
    x = feat.positionAlongLine(0.51,True).firstPoint.X - feat.positionAlongLine(0.49,True).firstPoint.X
    y = feat.positionAlongLine(0.51,True).firstPoint.Y - feat.positionAlongLine(0.49,True).firstPoint.Y
    radian = math.atan2(y,x)

    degrees = radian * 180 / math.pi
    print degrees
    row.angle = degrees
    rows.updateRow(row)

#Generating the mid point flow arrow
    out_cursor = arcpy.InsertCursor(flowArrow)
    midpoint = feat.positionAlongLine(0.50,True).firstPoint
    outRow = out_cursor.newRow()
    outRow.Shape = midpoint
    outRow.angle = row.angle
    out_cursor.insertRow(outRow)

del rows, row, updateRows_FlowArrow, outRow, out_cursor
print "Done in ",datetime.datetime.now() - start, " seconds"

visual display of the midpoint angle calculation problem

Best Answer

Try replacing

radian = math.atan2((x1 - y1),(x2 - y2))

with

radian = math.atan2((y2 - y1),(x2 - x1))

You should also avoid using the ends of your line segments but rather use the points located just before and after your midpoint

radian = math.atan2((feat.positionAlongLine(0.51,True).firstPoint.Y - feat.positionAlongLine(0.49,True).firstPoint.Y),(feat.positionAlongLine(0.51,True).firstPoint.X - feat.positionAlongLine(0.49,True).firstPoint.X))
Related Question