Rotation angle using 3 points

This is the place for queries that don't fit in any of the other categories.

Rotation angle using 3 points

Postby noebyus » Fri Mar 15, 2013 9:00 pm

What I'm trying to do is find the angle of rotation between lines formed by three consecutive points. These are sequential points, so the direction of rotation matter.
My input is a sequence of pair of coordinates.

My desired output is the rotation angle of each point, where the point would be acting as the vertex of the angle. This angle would be between 1 and 360, where a negative number indicates a rotation to the left, and a positive number a rotation to the right.

I've been struggling with this for weeks, but I'm finally closer to the solution than ever before. I wrote the following script and compared it to the output of the "pathmetrics" function of the program Geospatial Modelling Tool(GME).

Code: Select all
    print "A"+"\t"+"B"+"\t"+"C"+"\t"+"orientation"+"\t"+"angle"+"\t"+"bearing AB"+"\t"+"bearing BC"
    for a in coords:
      ##Find the bearings of AB and BC
      AB=[B[0]-A[0],B[1]-A[1]]          #find the extreme of vector AB
      BearAB=math.atan2(AB[0],AB[1])    #use arctan2 to find the angle
      ABBearDeg=math.degrees(BearAB)    #in degrees
      if ABBearDeg<0:                   #if negative, add 360 in order to obtain the angle in a clockwise direction
       ABBearDeg=360+ABBearDeg          #Bearing AB
      BC=[C[0]-B[0],C[1]-B[1]]          #Do the same for points BC
      if BCBearDeg<0:
       BCBearDeg=360+BCBearDeg          #Bearing BC
     ##Find the angle between the lines
      alfa=BCBearDeg-ABBearDeg          #Obtain the difference between the bearing angles
      if abs(alfa)>180:                 #If greater than 180
       if alfa<0:                        #and negative
        angle=(360+alfa)                   #Direction of rotation is right and angle is obtained by adding 360
        print format(A)+"\t"+format(B)+"\t"+format(C)+"\t"+"right"+"\t"+format(angle)+"\t"+format(round(ABBearDeg,2))+"\t"+format(round(BCBearDeg,2))
       else:                             #If positive
        angle=alfa-360                      #Direction of rotation is left and angle is obtained by substracting 360
        print format(A)+"\t"+format(B)+"\t"+format(C)+"\t"+"left"+"\t"+format(angle)+"\t"+format(ABBearDeg)+"\t"+format(round(BCBearDeg,2))
      else:                            #If the difference was less than 180, then the rotation angle is equal to it
       if angle<0:                     #If negative, left rotation
           print format(A)+"\t"+format(B)+"\t"+format(C)+"\t"+"left"+"\t"+format(angle)+"\t"+format(ABBearDeg)+"\t"+format(round(BCBearDeg,2))
       else:                            #If positive, right rotation
        print format(A)+"\t"+format(B)+"\t"+format(C)+"\t"+"right"+"\t"+format(angle)+"\t"+format(ABBearDeg)+"\t"+format(round(BCBearDeg,2))

While many of the results coincide, others don't.


I've been able to pin-point at with point the error occurs, but I can't figure out why it happens because it depends strictly on pre-set formulas I have no control of.
So, the difference is that (SOMETIMES) my calculations of the bearing of the vectors differs from the one calculated by GME.
The weird part is that it happens only sometimes, and I have no idea what triggers it.

Any ideas of what might be going on?

If you know any other way of calculating angles between lines that incorporate the direction of the movement, do let me know.

Posts: 1
Joined: Fri Mar 15, 2013 8:58 pm

Re: Rotation angle using 3 points

Postby hrs » Sat Mar 16, 2013 1:33 pm

This code is hard to read. Consequently I didn't try to find the bug. I would suggest you read this: because if you use those guide lines you will get more feed back.

The way I would calculate angles would be something like this
Code: Select all
import math

line_1 = [[0., 0.], [1., 1.]]
line_2 = [[1., 1.], [2., 3.]]

def find_angle(line_1, line_2):
    dx_line_1 = line_1[1][0] - line_1[0][0]
    dy_line_1 = line_1[1][1] - line_1[0][1]
    dx_line_2 = line_2[1][0] - line_2[0][0]
    dy_line_2 = line_2[1][1] - line_2[0][1]

    a_line_1 = math.atan2(dx_line_1, dy_line_1)
    a_line_2 = math.atan2(dx_line_2, dy_line_2)
    return (a_line_1 - a_line_2) * 180 / math.pi

print '{:.2f}'.format(find_angle(line_1, line_2))

though it appears you try to do something similar but it's hard to tell, which is the real problem imho.
Posts: 86
Joined: Thu Feb 07, 2013 9:26 pm

Return to General Coding Help

Who is online

Users browsing this forum: Google [Bot] and 7 guests