calculate the angle between a line and x-axis
If you have two points, (x0, y0)
and (x1, y1)
, then the angle of the line joining them (relative to the X axis) is given by:
theta = atan2((y1 - y0), (x1 - x0))
Calculating the angle between a line and the x-axis
Assumptions: x
is the horizontal axis, and increases when moving from left to right.y
is the vertical axis, and increases from bottom to top. (touch_x, touch_y)
is the
point selected by the user. (center_x, center_y)
is the point at the center of the
screen. theta
is measured counter-clockwise from the +x
axis. Then:
delta_x = touch_x - center_x
delta_y = touch_y - center_y
theta_radians = atan2(delta_y, delta_x)
Edit: you mentioned in a comment that y increases from top to bottom. In that
case,
delta_y = center_y - touch_y
But it would be more correct to describe this as expressing (touch_x, touch_y)
in polar coordinates relative to (center_x, center_y)
. As ChrisF mentioned,
the idea of taking an "angle between two points" is not well defined.
How to calculate the angle between a line and the horizontal axis?
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
deltaX
anddeltaY
by the vector's length (sqrt(deltaX*deltaX+deltaY*deltaY)
), unless the length is 0. - After that,
deltaX
will 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
deltaY
will 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
deltaX
will tell you whether the cosine described in step 3 is positive or negative. - The sign of
deltaY
will tell you whether the sine described in step 4 is positive or negative. - The signs of
deltaX
anddeltaY
will 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
How to find angle of point from x-axis independant of quadrant?
Use Math.atan2()
because it returns a value from 0->180 in the first two quadrants and -180->0 in the last 2.
calculate angle between horizontal axis and two points
I'm going to assume that your longitudinal coordinates represent the distance of each point along the x-axis and that your latitudinal coordinates represent the distance of each point along the y-axis. If this is an incorrect assumption let me know.
y
| (B)
| /|
| / |
| / |
| distance(AB) / |
| / | (LatB-LatA)
| / |
| / |
| / |
| /alpha |
| (A)----------
| (LonB-LonA)
|
|
|__________________________________ x
0
Then, in order to find your angle relative to the x-axis, you should apply one of the following rules:
sin(alpha) = (LatB - LatA) / distance(AB)
cos(alpha) = (LonB - LonA) / distance(AB)
tan(alpha) = (LatB - LatA) / (LonB - LonA)
By simply rearranging one of the equations by using the inverse of sin
, cos
, or tan
, you should be able to find alpha
in radians. For example...
alpha = Math.Asin((LatB - LatA) / distance(AB));
alpha = Math.Acos((LonB - LonA) / distance(AB));
alpha = Math.Atan((LatB - LatA) / (LonB - LonA));
Calculate angle (gradient) from a vector with x-axis
You could use the dot product (http://en.wikipedia.org/wiki/Dot_product) but simplifying it all out, you end up just taking the arctangent of the endpoint of your vector to get the angle between it and the x axis. Atan functions usually return on the order [-pi,pi] or [-180,180], so if you're looking to make sure it wraps correctly, you'll need to check to see if the y-component of your vector is negative. In C, you can use atan2 instead of atan, and it'll use the sign of each component to figure out the sign of the angle (http://www.cplusplus.com/reference/clibrary/cmath/atan2/).
For example, if you have the vector points start=<1,2> and end=<-5,-5>, adjust it back to the origin by subtracting the start from the end, giving you <-6,-7>. So you're looking at that point. The angle with the x-axis is atan2(y,x), atan2(-7,-6), which is -130.6.
double x = -6;
double y = -7;
fprintf(stderr,"angle is %.2f\n",atan2(y,x)*180/3.14159);
angle is -130.60
Line Equation with angle
An equation of a line is like:
m*x + n = y
m can be calculated by angle; m = tan(angle)
And if you know a start point then you can find n.
tan(angle) * startPoint_X + n = startPoint_Y
So n = startPoint_Y - (tan ( angle) * startPoint_X )
If you want to draw a line-segment and you know the length, the start point and the angle, there will be two equations.
The first is m*x + n = y
(we solved it).
And this means m*(endPoint_X) + n = endPoint_Y
The second is to find the endPoint.
length^2 = (endPoint_X - startPoint_X)^2 + (endPoint_Y - startPoint_Y)^2
There are only two things that still we don't know: endPoint_x & endPoint_Y
If we rewrite the equation:
length^2 = (endPoint_X - startPoint_X)^2 + ( m*(endPoint_X) + n - startPoint_Y)^2
now we know everything except endPoint_X.
This equation will give us two solutions for endPoint_X.
Then you can find two different ednPoint_Y.
Calculating angles between line segments (Python) with math.atan2
The easiest way to get at this problem is using the dot-product.
Try this code (I've commented practically everything):
import math
def dot(vA, vB):
return vA[0]*vB[0]+vA[1]*vB[1]
def ang(lineA, lineB):
# Get nicer vector form
vA = [(lineA[0][0]-lineA[1][0]), (lineA[0][1]-lineA[1][1])]
vB = [(lineB[0][0]-lineB[1][0]), (lineB[0][1]-lineB[1][1])]
# Get dot prod
dot_prod = dot(vA, vB)
# Get magnitudes
magA = dot(vA, vA)**0.5
magB = dot(vB, vB)**0.5
# Get cosine value
cos_ = dot_prod/magA/magB
# Get angle in radians and then convert to degrees
angle = math.acos(dot_prod/magB/magA)
# Basically doing angle <- angle mod 360
ang_deg = math.degrees(angle)%360
if ang_deg-180>=0:
# As in if statement
return 360 - ang_deg
else:
return ang_deg
Now try your variations of lineA and lineB and all should give the same answer.
Related Topics
Dynamic/Runtime Dispatch in Swift, or "The Strange Way Structs Behave in One Man's Opinion"
Why Do Integers Not Conform to the Anyobject Protocol
Suppressing Implicit Returns in Swift
Appending Tuples to an Array of Tuples
Is There a Preferred Technique to Prohibit Pasting into a Uitextfield
Incorrect String to Date Conversion Swift 3.0
How to Convert Anyclass to a Specific Class and Init It Dynamically in Swift
Uiview Background Color in Swift
How to Create an Array with Incremented Values in Swift
Ui Testing Failure - Neither Element Nor Any Descendant Has Keyboard Focus on Textview
How to Stream Remote Audio in iOS 13? (Swiftui)
Google API - Invalid Credentials
Pdfview Does Not Display My PDF
Swift Test Give Error "Undefined Symbols for Architecture X86_64"