угол меньше 180 между двумя отрезками (линиями)

Мне нужно найти «внутренний» угол в градусах между двумя сегментами (линиями), то есть меньше 180 градусов. Любой быстрый способ сделать это в python2.7? (У Shapely, похоже, нет функции для этого)

сегмент 1 - это x1, y1, x2, y2

сегмент 2 - это x3, y3, x4, y4

введите описание изображения здесь


person OHTO    schedule 10.10.2013    source источник
comment
если вы умеете вычислять угол между 3 точками, то если ›180: innerAngle = 360.0 - угол; Ваше принятое решение не рекомендуется (плохой acos ()), ищите дальше.   -  person AlexWien    schedule 10.10.2013
comment
В этом ответе показан общий способ вычисления угла между двумя отрезками линии .   -  person Mike T    schedule 18.10.2013


Ответы (1)


Первоначально я предлагал использовать закон косинусов в векторной форме: если заданы два отрезка линии векторами b и c, а угол между ними равен θ, то

b · c = | b | | c | cos θ

и так

θ = cos −1 ((b · c) / | b | | c |)

Но, как отмечает Алекс Вин в комментариях, это дает плохие результаты, когда θ близко к нулю:

>>> theta = 1e-6
>>> a = Vector(1, 0)
>>> b = Vector(cos(theta), sin(theta))
>>> acos(a.dot(b) / (a.length * b.length))
9.999334257726859e-07
>>> abs(theta - _) / theta
6.657422731408927e-05

что является относительной ошибкой при получении доли из десяти тысяч. Для очень малых углов можно получить 100% относительную погрешность:

>>> theta = 1e-9
>>> a = Vector(1, 0)
>>> b = Vector(cos(theta), sin(theta))
>>> acos(a.dot(b) / (a.length * b.length))
0.0

Альтернативная формула использует арктангенс вместо арккосинуса:

θ = tan −1 (| a × b | / (a · b ))

и это дает более точный результат для малых углов:

>>> atan2(abs(a.cross(b)), a.dot(b))
1e-09
>>> theta == _
True

(Альтернативная формула следует из свойства перекрестного произведения, что | a < / strong> × b | = | a | | b | sin θ. Разделите это на закон косинусов, чтобы получить результат, используемый здесь .)

person Gareth Rees    schedule 10.10.2013
comment
Как мне написать этот cos ^ -1 (и т. Д.) На Python? - person OHTO; 10.10.2013
comment
Ну вы читаете мануал! Математические функции, такие как арккосинус, находятся в модуле math. - person Gareth Rees; 10.10.2013
comment
Это неприменимо для компьютерной программы. Это далеко от рабочего кода. - person AlexWien; 10.10.2013
comment
Обратный cos плохо обусловлен для компьютерных программ, правильное решение использует atan2 () для этой задачи и обрабатывает особые случаи, такие как деление на 0. - person AlexWien; 10.10.2013
comment
Я думаю, что acos достаточно для этого случая ... ему нужны только углы между векторами <180 градусов, но если ему нужен прямой угол в 4 квадранта, тогда ваше право и atan2 - единственный выбор - person Spektre; 28.10.2013
comment
@AlexWien: Я пересмотрел ответ; как тебе это сейчас нравится? - person Gareth Rees; 29.10.2013
comment
Какой модуль мы здесь используем? В вопросе упоминается Shapely, но я не могу найти класс Vector в Shapely. Или я что-то упускаю? - person Bill; 12.10.2016
comment
@Bill: Подойдет любой векторный класс с перекрестными и точечными произведениями, поэтому используйте то, что вам больше нравится. - person Gareth Rees; 12.10.2016