Вычислить угол (по часовой стрелке) между двумя точками
Я долгое время не использовал математику, и это должна быть простая проблема для решения.
Предположим, что у меня есть две точки A: (1, 0) и B: (1, -1).
Я хочу использовать программу (Python или любой язык программирования) для вычисления угла по часовой стрелке между A, началом (0, 0) и B. Это будет примерно так:
angle_clockwise(point1, point2)
Заметим, что порядок параметров имеет значение. Поскольку расчет угла будет по часовой стрелке:
- Если я вызываю angle_clockwise (A, B), он возвращает 45.
- Если я вызываю angle_clockwise (B, A), он возвращает 315.
Другими словами, алгоритм выглядит следующим образом:
- Нарисуйте строку (строка 1) между параметром первой точки с (0, 0).
- Нарисуйте строку (строка 2) между параметром второй точки с (0, 0).
- Верните линию 1 вокруг (0, 0) по часовой стрелке до тех пор, пока она не пересечет линию 2.
- Промежуточная линия angular 1 будет возвращенным углом.
Есть ли способ кодировать эту проблему?
Ответы
Ответ 1
Используйте внутренний продукт и определитель двух векторов. Это действительно то, что вы должны понимать, если хотите понять, как это работает. Вам нужно знать/читать о векторной математике, чтобы понять.
Смотрите: https://en.wikipedia.org/wiki/Dot_product и https://en.wikipedia.org/wiki/Determinant
from math import acos
from math import sqrt
from math import pi
def length(v):
return sqrt(v[0]**2+v[1]**2)
def dot_product(v,w):
return v[0]*w[0]+v[1]*w[1]
def determinant(v,w):
return v[0]*w[1]-v[1]*w[0]
def inner_angle(v,w):
cosx=dot_product(v,w)/(length(v)*length(w))
rad=acos(cosx) # in radians
return rad*180/pi # returns degrees
def angle_clockwise(A, B):
inner=inner_angle(A,B)
det = determinant(A,B)
if det<0: #this is a property of the det. If the det < 0 then B is clockwise of A
return inner
else: # if the det > 0 then A is immediately clockwise of B
return 360-inner
В определении детерминанта вы объединяете два вектора, чтобы сформировать матрицу 2 x 2, для которой вы вычисляете определитель.
Ответ 2
Numpy arctan2(y, x)
вычислит угол против часовой стрелки (в радианах) между началом и точкой (x, y)
.
Вы можете сделать это для своих очков A
и B
, а затем вычесть второй угол из первого, чтобы получить разницу по счету по часовой стрелке angular. Это будет между -π и π, поэтому, чтобы получить положительный угол между 0 и 2π, вы могли бы взять модуль по отношению к 2π. Наконец, вы можете преобразовать радианы в градусы, используя np.rad2deg
.
import numpy as np
def angle_between(p1, p2):
ang1 = np.arctan2(*p1[::-1])
ang2 = np.arctan2(*p2[::-1])
return np.rad2deg((ang1 - ang2) % (2 * np.pi))
Например:
A = (1, 0)
B = (1, -1)
print(angle_between(A, B))
# 45.
print(angle_between(B, A))
# 315.
Если вы не хотите использовать numpy, вы можете использовать math.atan2
вместо np.arctan2
и использовать math.degrees
(или просто умножить на 180 / math.pi
), чтобы преобразовать из радианов в градусы. Одним из преимуществ версии numpy является то, что вы также можете передать два массива (2, ...)
для p1
и p2
, чтобы вычислить углы между несколькими парами точек в векторном виде.
Ответ 3
Здесь решение, которое не требует cmath
.
import math
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
v1 = Vector(0, 1)
v2 = Vector(0, -1)
v1_theta = math.atan2(v1.y, v1.x)
v2_theta = math.atan2(v2.y, v2.x)
r = (v2_theta - v1_theta) * (180.0 / math.pi)
if r < 0:
r += 360.0
print r
Ответ 4
Посмотрите cmath библиотеку python.
>>> import cmath
>>> a_phase = cmath.phase(complex(1,0))
>>> b_phase = cmath.phase(complex(1,-1))
>>> (a_phase - b_phase) * 180 / cmath.pi
45.0
>>> (b_phase - a_phase) * 180 / cmath.pi
-45.0
Вы можете проверить, меньше ли число 0 и добавить к нему 360, если вы хотите все положительные углы.
Ответ 5
Chris St Pierre: при использовании вашей функции:
A = (x=1, y=0)
B = (x=0, y=1)
Предполагается, что угол степени 90
от A
до B
. Ваша функция вернет 270
.
Есть ли ошибка в том, как вы обрабатываете знак det или я что-то не хватает?