2

I have 3 points p1(x1, y1), p2(x2, y2) and p3(x3, y3). I am trying to calculate angle (in anti-clockwise direction) between these 3 points. I am using following dot product method as provided in multiple blogs and SE sites (like this).

def angle_between(p1, p2, p3):
    x1, y1 = p1
    x2, y2 = p2
    x3, y3 = p3

    v21 = (x1 - x2, y1 - y2)
    v23 = (x3 - x2, y3 - y2)

    dot = v21[0] * v23[0] + v21[1] * v23[1]
    det = v21[0] * v23[1] - v21[1] * v23[0]

    theta = np.rad2deg(np.arctan2(det, dot))

    print(theta)

It is giving me correct angle for any points which are not on the straight line. For example

p1 = (0, 0)
p2 = (1, 0)
p3 = (1, 1)
angle_between(p1, p2, p3) # Prints -90
angle_between(p3, p2, p1) # Prints +90

However, if points are on the straight line, it is giving me same answer

p1 = (0, 0)
p2 = (1, 0)
p3 = (2, 0)
angle_between(p1, p2, p3) # Prints +180
angle_between(p3, p2, p1) # Prints +180

Here I was expecting (p3, p2, p1) to give -180. What am I missing here? If the method I am using is not correct, can someone help me point towards the correct method?

I have tried to use direct cosine law (as given here) but it only provides me angle without any sense of direction of the angle.

Dexter
  • 1,421
  • 3
  • 22
  • 43
  • In second scenario, points are co-liner..your code is producing the correct o/p. – Deepanshu Nov 20 '19 at 11:58
  • 1
    if you are getting the angle in the anticlockwise direction, then why would the sign of the angle matter? – hhaefliger Nov 20 '19 at 13:35
  • @hhaefliger, how will I distinguish between last case then? i.e. when points are in straight line. – Dexter Nov 20 '19 at 14:38
  • Also, check out this solution: https://stackoverflow.com/questions/31630946/get-angle-between-two-2d-lines-with-respect-to-the-direction-of-the-lines?rq=1 – Riccardo Bucco Nov 20 '19 at 14:56

1 Answers1

5

Check out this solution. It always provides positive angles, measured in anti-clockwise direction:

from math import atan2, degrees

def angle_between(p1, p2, p3):
    x1, y1 = p1
    x2, y2 = p2
    x3, y3 = p3
    deg1 = (360 + degrees(atan2(x1 - x2, y1 - y2))) % 360
    deg2 = (360 + degrees(atan2(x3 - x2, y3 - y2))) % 360
    return deg2 - deg1 if deg1 <= deg2 else 360 - (deg1 - deg2)
Riccardo Bucco
  • 13,980
  • 4
  • 22
  • 50
  • Thank you for your answer. +1. However, I still can not distinguish case when 3 points are in same line. I was expecting to give it negative sign when 3 points parsed in reverse order. Does that make sense or there is logical gap in my understanding of this situation? – Dexter Nov 20 '19 at 14:44
  • I think you are misunderstanding. Try to draw three points. Then measure the angle in anti-cloclwise direction, starting from the first segment (p1,p2) and reaching the second segment (p2,p3). If these segments are on the same line, the angle is always 180! – Riccardo Bucco Nov 20 '19 at 14:48
  • I think I got the point. Thank you for your efforts. My existing function is giving correct answer only :) – Dexter Nov 20 '19 at 16:04