How to calculate the angle between a line and the horizontal axis?
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------
Music by Eric Matyas
https://www.soundimage.org
Track title: Horror Game Menu Looping
--
Chapters
00:00 How To Calculate The Angle Between A Line And The Horizontal Axis?
00:31 Accepted Answer Score 398
03:37 Answer 2 Score 52
04:21 Answer 3 Score 2
04:34 Answer 4 Score 1
04:44 Thank you
--
Full question
https://stackoverflow.com/questions/7586...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#c# #python #trigonometry
#avk47
ACCEPTED ANSWER
Score 398
First find the difference between the start point and the end point (here, this is more of a directed line segment, not a "line", since lines extend infinitely and don't start at a particular point).
deltaY = P2_y - P1_y
deltaX = P2_x - P1_x
Then calculate the angle (which runs from the positive X axis at P1 to the positive Y axis at P1).
angleInDegrees = arctan(deltaY / deltaX) * 180 / PI
But arctan may not be ideal, because dividing the differences this way will erase the distinction needed to distinguish which quadrant the angle is in (see below). Use the following instead if your language includes an atan2 function:
angleInDegrees = atan2(deltaY, deltaX) * 180 / PI
EDIT (Feb. 22, 2017): In general, however, calling atan2(deltaY,deltaX) just to get the proper angle for cos and sin may be inelegant. In those cases, you can often do the following instead:
- Treat
(deltaX, deltaY)as a vector. - Normalize that vector to a unit vector. To do so, divide
deltaXanddeltaYby the vector's length (sqrt(deltaX*deltaX+deltaY*deltaY)), unless the length is 0. - After that,
deltaXwill now be the cosine of the angle between the vector and the horizontal axis (in the direction from the positive X to the positive Y axis atP1). - And
deltaYwill now be the sine of that angle. - If the vector's length is 0, it won't have an angle between it and the horizontal axis (so it won't have a meaningful sine and cosine).
EDIT (Feb. 28, 2017): Even without normalizing (deltaX, deltaY):
- The sign of
deltaXwill tell you whether the cosine described in step 3 is positive or negative. - The sign of
deltaYwill tell you whether the sine described in step 4 is positive or negative. - The signs of
deltaXanddeltaYwill tell you which quadrant the angle is in, in relation to the positive X axis atP1:+deltaX,+deltaY: 0 to 90 degrees.-deltaX,+deltaY: 90 to 180 degrees.-deltaX,-deltaY: 180 to 270 degrees (-180 to -90 degrees).+deltaX,-deltaY: 270 to 360 degrees (-90 to 0 degrees).
An implementation in Python using radians (provided on July 19, 2015 by Eric Leschinski, who edited my answer):
from math import *
def angle_trunc(a):
while a < 0.0:
a += pi * 2
return a
def getAngleBetweenPoints(x_orig, y_orig, x_landmark, y_landmark):
deltaY = y_landmark - y_orig
deltaX = x_landmark - x_orig
return angle_trunc(atan2(deltaY, deltaX))
angle = getAngleBetweenPoints(5, 2, 1,4)
assert angle >= 0, "angle must be >= 0"
angle = getAngleBetweenPoints(1, 1, 2, 1)
assert angle == 0, "expecting angle to be 0"
angle = getAngleBetweenPoints(2, 1, 1, 1)
assert abs(pi - angle) <= 0.01, "expecting angle to be pi, it is: " + str(angle)
angle = getAngleBetweenPoints(2, 1, 2, 3)
assert abs(angle - pi/2) <= 0.01, "expecting angle to be pi/2, it is: " + str(angle)
angle = getAngleBetweenPoints(2, 1, 2, 0)
assert abs(angle - (pi+pi/2)) <= 0.01, "expecting angle to be pi+pi/2, it is: " + str(angle)
angle = getAngleBetweenPoints(1, 1, 2, 2)
assert abs(angle - (pi/4)) <= 0.01, "expecting angle to be pi/4, it is: " + str(angle)
angle = getAngleBetweenPoints(-1, -1, -2, -2)
assert abs(angle - (pi+pi/4)) <= 0.01, "expecting angle to be pi+pi/4, it is: " + str(angle)
angle = getAngleBetweenPoints(-1, -1, -1, 2)
assert abs(angle - (pi/2)) <= 0.01, "expecting angle to be pi/2, it is: " + str(angle)
All tests pass. See https://en.wikipedia.org/wiki/Unit_circle
ANSWER 2
Score 52
Sorry, but I'm pretty sure Peter's answer is wrong. Note that the y axis goes down the page (common in graphics). As such the deltaY calculation has to be reversed, or you get the wrong answer.
Consider:
System.out.println (Math.toDegrees(Math.atan2(1,1)));
System.out.println (Math.toDegrees(Math.atan2(-1,1)));
System.out.println (Math.toDegrees(Math.atan2(1,-1)));
System.out.println (Math.toDegrees(Math.atan2(-1,-1)));
gives
45.0
-45.0
135.0
-135.0
So if in the example above, P1 is (1,1) and P2 is (2,2) [because Y increases down the page], the code above will give 45.0 degrees for the example shown, which is wrong. Change the order of the deltaY calculation and it works properly.
ANSWER 3
Score 2
I have found a solution in Python that is working well !
from math import atan2,degrees
def GetAngleOfLineBetweenTwoPoints(p1, p2):
return degrees(atan2(p2 - p1, 1))
print GetAngleOfLineBetweenTwoPoints(1,3)
ANSWER 4
Score 1
Based on reference "Peter O".. Here is the java version
private static final float angleBetweenPoints(PointF a, PointF b) {
float deltaY = b.y - a.y;
float deltaX = b.x - a.x;
return (float) (Math.atan2(deltaY, deltaX)); }