Ответ 1
Сначала найдите разницу между начальной точкой и конечной точкой (здесь это скорее ориентированный сегмент линии, а не "линия", так как линии бесконечно расширяются и не начинаются в определенной точке).
deltaY = P2_y - P1_y
deltaX = P2_x - P1_x
Затем вычислим угол (который исходит от положительной оси X в точке P1
до положительной оси Y в точке P1
).
angleInDegrees = arctan(deltaY / deltaX) * 180 / PI
Но arctan
может быть не идеальным, потому что разделение различий таким образом стирает различие, необходимое для того, чтобы отличить квадрант, в котором находится угол (см. ниже). Вместо этого используйте следующее, если ваш язык включает функцию atan2
:
angleInDegrees = atan2(deltaY, deltaX) * 180 / PI
EDIT (22 февраля 2017 года): В общем, однако, вызов atan2(deltaY,deltaX)
только для получения правильного угла для cos
и sin
может быть неэлегантным. В таких случаях вы можете часто делать следующее:
- Относитесь к
(deltaX, deltaY)
как к вектору. - Нормализовать этот вектор на единичный вектор. Для этого разделите
deltaX
иdeltaY
на длину вектора (sqrt(deltaX*deltaX+deltaY*deltaY)
), если длина не равна 0. - После этого
deltaX
теперь будет косинусом угла между вектором и горизонтальной осью (в направлении от положительного X до положительной оси Y в точкеP1
). - И
deltaY
теперь будет синусом этого угла. - Если длина вектора равна 0, у него не будет угла между ним и горизонтальной осью (поэтому он не будет иметь значимого синуса и косинуса).
EDIT (28 февраля 2017 г.): Даже без нормализации (deltaX, deltaY)
:
- Знак
deltaX
скажет вам, является ли косинус, описанный на шаге 3 положительным или отрицательным. - Знак
deltaY
скажет вам, является ли синус, описанный на шаге 4 положительным или отрицательным. - Знаки
deltaX
иdeltaY
расскажут вам, в каком квадранте находится угол, относительно положительной оси X в точкеP1
:-
+deltaX
,+deltaY
: от 0 до 90 градусов. -
-deltaX
,+deltaY
: от 90 до 180 градусов. -
-deltaX
,-deltaY
: от 180 до 270 градусов (от -180 до -90 градусов). -
+deltaX
,-deltaY
: от 270 до 360 градусов (от -90 до 0 градусов).
-
Реализация на Python с использованием радианов (предоставленная 19 июля 2015 г. Эриком Лещински, который отредактировал мой ответ):
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