Подпись угла между двумя векторами без опорной плоскости

(В трех измерениях) Я ищу способ вычислить подписанный угол между двумя векторами, не имея информации, отличной от этих векторов. Как уже было сказано в этом вопросе, достаточно просто вычислить угловой знак, заданный нормалью плоскости, перпендикулярной векторам. Но я не могу найти способ сделать это без этой ценности. Очевидно, что перекрестное произведение двух векторов создает такую ​​нормаль, но я воспользовался следующим противоречием, используя ответ выше:

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-векторами.)