Подпись угла между двумя векторами без опорной плоскости
(В трех измерениях) Я ищу способ вычислить подписанный угол между двумя векторами, не имея информации, отличной от этих векторов. Как уже было сказано в этом вопросе, достаточно просто вычислить угловой знак, заданный нормалью плоскости, перпендикулярной векторам. Но я не могу найти способ сделать это без этой ценности. Очевидно, что перекрестное произведение двух векторов создает такую нормаль, но я воспользовался следующим противоречием, используя ответ выше:
signed_angle(x_dir, y_dir) == 90
signed_angle(y_dir, x_dir) == 90
где я ожидаю, что второй результат будет отрицательным. Это связано с тем, что кросс-произведение cross(x_dir, y_dir)
находится в противоположном направлении от cross(y_dir, x_dir)
, учитывая следующий psuedocode с нормированным входом:
signed_angle(Va, Vb)
magnitude = acos(dot(Va, Vb))
axis = cross(Va, Vb)
dir = dot(Vb, cross(axis, Va))
if dir < 0 then
magnitude = -magnitude
endif
return magnitude
Я не считаю, что dir никогда не будет отрицательным.
Я видел ту же проблему с предлагаемым решением atan2.
Я ищу способ сделать:
signed_angle(a, b) == -signed_angle(b, a)
Ответы
Ответ 1
Спасибо всем. Просмотрев здесь комментарии и оглядываясь на то, что я пытался сделать, я понял, что могу выполнить то, что мне нужно сделать с данной стандартной формулой для подписанного угла. Я просто повесил трубку в unit test для моей подписанной функции угла.
Для справки я возвращаю результирующий угол назад в функцию вращения. Я не учитывал тот факт, что это, естественно, будет использовать ту же ось, что и в signed_angle (поперечное произведение входных векторов), и будет следовать правильное направление вращения, из которого всегда направляется эта ось.
Проще говоря, оба они должны "делать правильные вещи" и вращаться в разных направлениях:
rotate(cross(Va, Vb), signed_angle(Va, Vb), point)
rotate(cross(Vb, Va), signed_angle(Vb, Va), point)
Где первый аргумент - ось вращения, а второй - количество, которое нужно вращать.
Ответ 2
Соответствующие математические формулы:
dot_product(a,b) == length(a) * length(b) * cos(angle)
length(cross_product(a,b)) == length(a) * length(b) * sin(angle)
Для надежного угла между трехмерными векторами ваш фактический расчет должен быть:
s = length(cross_product(a,b))
c = dot_product(a,b)
angle = atan2(s, c)
Если вы используете только acos(c)
, у вас появятся проблемы с серьезной точностью для случаев, когда угол мал. Вычисление s
и использование atan2()
дает вам надежный результат для всех возможных случаев.
Так как s
всегда неотрицательно, результирующий угол будет находиться в диапазоне от 0 до pi. Всегда будет эквивалентный отрицательный угол (angle - 2*pi)
, но нет геометрических причин, чтобы предпочесть его.
Ответ 3
Подпись угол между двумя векторами без опорной плоскости
angle = acos(dotproduct(normalized(a), normalized(b)));
signed_angle (a, b) == -signed_angle (b, a)
Я думаю, что невозможно без какого-либо базисного вектора.
Ответ 4
Если все, что вы хотите, является последовательным результатом, то любой произвольный способ выбора между a × b и b × a для вашего обычного поведения. Возможно, выбрать тот, который лексикографически меньше?
(Но вы, возможно, захотите объяснить, какую проблему вы пытаетесь решить: может быть, есть решение, которое не требует вычисления согласованного угла подписи между произвольными 3-векторами.)