На языке программирования (Python, C# и т. д) Мне нужно определить, как вычислить угол между линией и горизонтальной оси?
Я думаю, что образ описывает лучшее, что я хочу:
Учитывая (П1<суб>х</суб> Р1<суб>г</суб> У) и (Р2<суб>х</суб>,Р2<суб>г</суб>) что является лучшим способом для вычисления этого угла? Источник находится в левой и используется только положительный квадрант.
Сначала найдем разницу между начальной точкой и конечной точки (здесь, это больше похоже на направленный отрезок прямой, а не на "линии" и, поскольку линии проходят бесконечно и Дон'т начать в конкретный момент).
deltaY = P2_y - P1_y
deltaX = P2_x - P1_x
Затем вычислить угол (который идет от положительной оси X на величину P1 на положительной оси Y на величину P1).
angleInDegrees = arctan(deltaY / deltaX) * 180 / PI
Но равенства arctg` не может быть идеальным, потому что, разделив разницы этот путь стереть различия нужны, чтобы определить, какой квадрант угол в (см. ниже). Использовать следующее, Если ваш язык включает в себя инструмент atan2 функция:
angleInDegrees = atan2(deltaY, deltaX) * 180 / PI
Редактирование (Февраля. 22 2017,): в целом, однако, называя инструмент atan2(deltaY,deltaX)
только, чтобы получить правильный угол для сов
и грех
может быть безвкусным. В таких случаях вы часто можете вместо этого сделать следующее:
deltaX и deltaY
вектор's длина (функция sqrt(deltaX*deltaX+deltaY*deltaY)
), если длина равна 0.deltaX
теперь будет косинус угла между вектором и горизонтальной оси (в направлении от положительной оси X к положительной оси Y на величину P1).Редактирование (Февраля. 28 2017,): даже без нормализации (deltaX, deltaY)
:
deltaX
скажет вам, является ли Косинус, описанные в шаге 3, положительный или отрицательный.deltaY
скажет вам, является ли синус, описанные в шаге 4 является положительным или отрицательным.deltaX и deltaY
расскажет вам, какие квадранте угол в, по отношению к положительной оси X Р1
:+deltaX
, +deltaY
: от 0 до 90 градусов.-deltaX
, +deltaY
: от 90 до 180 градусов.-deltaX
, -deltaY
: 180 до 270 градусов (-90 до -180 градусов).+deltaX
, -deltaY
: 270 ° до 360 ° (от -90 до 0 градусов).Реализация в Python с использованием радианах (при условии, 19 июля 2015, Эрик Leschinski, кто редактировал мой ответ):
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)
Все тесты проходят. См https://en.wikipedia.org/wiki/Unit_circle
Извините, но я'м довольно уверен, что Питер'ы ответ неправильный. Обратите внимание, что ось Y идет вниз страницы (обычная графика). Как такой расчет deltaY должно быть отменено, или вы получаете неправильный ответ.
Рассмотрим:
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)));
дает
45.0
-45.0
135.0
-135.0
Так, если в приведенном выше примере, Р1 (1,1) и Р2 (2,2) [потому что y увеличивается вниз страницы], приведенный выше код даст 45.0 градусов на показанном примере, что неправильно. Изменить порядок расчета deltaY и он работает правильно.
Учитывая точный вопрос, ставящий нас в том, что "специальные" в системе координат, где оси положительное перемещение вниз (как экран или вид интерфейса), вы должны адаптировать эту функцию, как это, так и отрицательные координаты Y:
Пример в Swift 2.0
func angle_between_two_points(pa:CGPoint,pb:CGPoint)->Double{
let deltaY:Double = (Double(-pb.y) - Double(-pa.y))
let deltaX:Double = (Double(pb.x) - Double(pa.x))
var a = atan2(deltaY,deltaX)
while a < 0.0 {
a = a + M_PI*2
}
return a
}
Эта функция дает правильный ответ на вопрос. Ответ в радианах, поэтому использование, просмотреть углов в градусах, является:
let p1 = CGPoint(x: 1.5, y: 2) //estimated coords of p1 in question
let p2 = CGPoint(x: 2, y : 3) //estimated coords of p2 in question
print(angle_between_two_points(p1, pb: p2) / (M_PI/180))
//returns 296.56
Я нашел решение в Python, который хорошо работает !
from math import atan2,degrees
def GetAngleOfLineBetweenTwoPoints(p1, p2):
return degrees(atan2(p2 - p1, 1))
print GetAngleOfLineBetweenTwoPoints(1,3)
Исходя ссылка на "Питер О', что".. Вот это Java версия
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)); }
deltaY = Math.Abs(P2.y - P1.y);
deltaX = Math.Abs(P2.x - P1.x);
angleInDegrees = Math.atan2(deltaY, deltaX) * 180 / PI
if(p2.y > p1.y) // Second point is lower than first, angle goes down (180-360)
{
if(p2.x < p1.x)//Second point is to the left of first (180-270)
angleInDegrees += 180;
else (270-360)
angleInDegrees += 270;
}
else if (p2.x < p1.x) //Second point is top left of first (90-180)
angleInDegrees += 90;
Формула для угла от 0 до 2pi.
Есть Х=Х2-Х1 и у=У2-У1.Формула работает для
любое значение X и y. Для Х=Y=0, то результат неопределен.
ф(х,г)=пи () пи()/2(1+знак(Х))(1-знак(г^2))
-pi()/4*(2+sign(x))*sign(y)
-sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))