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.

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"

rows = arcpy.UpdateCursor(pipes)
updateRows_FlowArrow = arcpy.UpdateCursor(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

#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

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

visual display of the midpoint angle calculation problem

  • 3
    (1) Your formula for the angle is incorrect. (2) Don't use atan--which only returns angles in [0, pi]--but use instead atan2. (3) Once you have corrected the mistakes you can reduce the result modulo 360 degrees to get it into the desired range.
    – whuber
    Jan 7, 2014 at 3:41

1 Answer 1


Try replacing

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


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))
  • with this change I am now getting a constant value of -135 for all of the midpoints Jan 7, 2014 at 20:25
  • 3
    Cecil, the code in your post still has not corrected the most glaring error: look closely at what gets subtracted from what in the arguments to atan2. By mixing these up, you are going to get two huge values whose arctangent will be very close to 45 degrees plus some integral number of right angles, so it's no surprise that (after the rounding which occurs when results are stored in a table) you wind up with constant values like 45 or 135 = 90 + 45.
    – whuber
    Jan 7, 2014 at 21:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.