# Determining angle for polyline geometries that share a point

With help I've written code to determine the angle between two line geometries. However, the code assumes each line extends into infinity and doesn't account for the shared point. Thus an angle of 150 can be returned as 30, or 20 can be returned as 160. I can't come up with a way of refining my code to return the proper angle.

Here's the code:

``````def AngleFromLines (lines):
#lines is a python list of line geometries that share a vertex
for line1 in lines:
for line2 in lines:
if line1 == line2:
continue
line1StPnt, line1EndPnt = LineToXYs (line1) #get start and end xys for first line
line2StPnt, line2EndPnt  = LineToXYs (line2)#get start and end xys for second line
angle1 = GetAngle (line1StPnt, line1EndPnt) #calculate declination
angle2 = GetAngle (line2StPnt, line2EndPnt) #calculate declination
angle = abs (angle1 - angle2) #angle between points - doesn't take into account shared point
#further code not shown....

def LineToXYs (line): #return first and last coordinates
firstX, firstY = (line.firstPoint.X, line.firstPoint.Y)
lastX, lastY = (line.lastPoint.X, line.lastPoint.Y)
return [(firstX, firstY), (lastX, lastY)]

def GetAngle (p1, p2):
x1, y1 = p1
x2, y2 = p2
dX = x2 - x1
dY = y2 - y1

AngleFromLines ([lineGeom1, lineGeom2]) #lineGeom* = arcpy polyline geometry object
``````

Example, where the angle is calculated as 39 instead of the desired result of 141. • What is your reference system? clockwise or anticlockwise? I wonder why you use -dY in `math.atan2 (-dY, dX)`. A picture might help. My guess is that you should use a MOD operator instead of a ABS function in line 11, but only guessing Nov 2, 2017 at 19:21

It turns out that the order of points matter. You must always subtract the X from the shared point from the point that is not shared. Here's the code:

``````def GetAngle (p1, p2):
x1, y1 = p1
x2, y2 = p2
dX = x1 - x2
dY = y1 - y2

def LineToXYs (line): #return first and last coordinates
firstX, firstY = (line.firstPoint.X, line.firstPoint.Y)
lastX, lastY = (line.lastPoint.X, line.lastPoint.Y)
return [(firstX, firstY), (lastX, lastY)]

def AngleFromLines (lines):
#lines is a python list of line geometries that share a vertex
for line1 in lines:
for line2 in lines:
if line1 == line2:
continue
line1Pnts = LineToXYs (line1)
line2Pnts  = LineToXYs (line2)
firstPnt = [p for p in line1Pnts if not p in line2Pnts] 
midPnts = [p for p in line1Pnts if p in line2Pnts]
if not midPnts:
continue
midPnt = midPnts 
lastPnt = [p for p in line2Pnts if not p in line1Pnts] 
angle1 = GetAngle (firstPnt, midPnt) #order of points important
angle2 = GetAngle (lastPnt, midPnt) #order of points important
angle = abs (angle1 - angle2)
``````
• You saved my life! I've been trying to get this working for days. I didn't realise that the order matters. Jun 16, 2022 at 21:19

Review the use of `angle = abs (angle1 - angle2)` in line 11. Negative angles have a meaning, you d not want to make 31 when is -31. I thought about trying the function `math.fmod(x, y)` for this operation, it seems return the sing of x. Then, what you want to do seems to me:

``````angle = (angle1 - angle2) % 360
``````