Подписанный угол между двумя 3D-векторами с одинаковым началом в одной плоскости
Мне нужен подписанный угол поворота между двумя векторами Va и Vb, лежащими в одной и той же трехмерной плоскости и имеющими одно и то же происхождение, зная, что:
- Плоскость, контактирующая с обоими векторами, является произвольной и не параллельна XY или любой другой из кардинальных плоскостей
- Vn - плоская нормаль
- Оба вектора вместе с нормалью имеют одинаковое происхождение O = {0, 0, 0}
- Va - эталон для измерения левого вращения при Vn
Угол должен быть измерен таким образом, чтобы, если плоскость была бы плоскостью XY, Va стояла бы за единичный вектор оси X.
Я предполагаю, что я должен выполнить какое-то преобразование координатного пространства, используя Va как ось X и поперечное произведение Vb и Vn как ось Y, а затем просто используя некоторый 2d-метод, подобный с atan2() или чем-то, Есть идеи? Формулы?
Ответы
Ответ 1
Используйте кросс-произведение двух векторов, чтобы получить нормаль плоскости, образованной двумя векторами. Затем проверьте, что dotproduct между ним и исходной плоскостью нормальный, чтобы увидеть, находятся ли они в одном направлении.
angle = acos(dotProduct(Va.normalize(), Vb.normalize()));
cross = crossProduct(Va, Vb);
if (dotProduct(Vn, cross) < 0) { // Or > 0
angle = -angle;
}
Ответ 2
Решение, которое я сейчас использую, похоже, отсутствует здесь.
Предполагая, что нормаль плоскости нормирована (|Vn| == 1
), подписанный угол просто:
atan2((Vb x Va) . Vn, Va . Vb)
который возвращает угол в диапазоне [-PI, + PI] (или независимо от возвращаемой реализации atan2).
.
и x
являются точками и поперечными произведениями соответственно.
Не требуется явное разветвление и вычисление длины деления/длины вектора.
Используйте Va x Vb
для вращения правой руки вместо левой
Объяснение, почему это работает: пусть альфа - прямой угол между векторами (от 0 ° до 180 °) и бета - угол, который мы ищем (от 0 ° до 360 °), с beta == alpha
или beta == 360° - alpha
Va . Vb == |Va| * |Vb| * cos(alpha) (by definition)
== |Va| * |Vb| * cos(beta) (cos(alpha) == cos(-alpha) == cos(360° - alpha)
Va x Vb == |Va| * |Vb| * sin(alpha) * n1
(by definition; n1 is a unit vector perpendicular to Va and Vb with
orientation matching the right-hand rule)
Therefore (again assuming Vn is normalized):
n1 . Vn == 1 when beta < 180
n1 . Vn == -1 when beta > 180
==> (Va x Vb) . Vn == |Va| * |Vb| * sin(beta)
Наконец
tan(beta) = sin(beta) / cos(beta) == ((Va x Vb) . Vn) / (Va . Vb)
Ответ 3
Вы можете сделать это в два этапа:
-
Определите угол между двумя векторами
theta = acos (точечный продукт Va, Vb). Предполагая, что Va, Vb нормированы. Это даст минимальный угол между двумя векторами
-
Определите знак угла
Найти вектор V3 = поперечное произведение Va, Vb. (порядок важен)
Если (точечный продукт V3, Vn) отрицателен, theta отрицателен. В противном случае theta положительна.
Ответ 4
Вы можете получить угол под знаком, используя dot product. Чтобы получить знак угла, возьмите знак Vn * (Va x Vb)
. В частном случае плоскости XY это сводится к просто Va_x*Vb_y - Va_y*Vb_x
.
Ответ 5
Переместите один вектор в другой и нормализуйте его, чтобы получить единичный вектор.
Синус угла между двумя векторами равно величине поперечного произведения, деленному на величины двух векторов:
http://mathworld.wolfram.com/CrossProduct.html
Ответ 6
Предположим, что Vx является осью x, учитывая нормаль Vn, вы можете получить ось y поперечным произведением, вы можете проецировать вектор Vb в Vx и Vy (через точечный продукт вы можете получить длину проекции Vb на Vx и Vy), учитывая координату (x, y) на плоскости, вы можете использовать atan2 (y, x), чтобы получить угол в диапазоне [-pi, + pi]
Ответ 7
Advanced Customer предоставил следующее решение (изначально редактирование вопроса):
SOLUTION:
sina = |Va x Vb| / ( |Va| * |Vb| )
cosa = (Va . Vb) / ( |Va| * |Vb| )
angle = atan2( sina, cosa )
sign = Vn . ( Va x Vb )
if(sign<0)
{
angle=-angle
}
Ответ 8
Пусть theta - угол между векторами. Пусть C = Va - поперечное произведение Vb. Тогда
sin theta = length (C)/(длина (Va) * Длина (Vb))
Чтобы определить, является ли theta положительным или отрицательным, помните, что C перпендикулярно Va и Vb, указывающим в направлении, определяемом правым правилом . Так, в частности, C параллельна Vn. В вашем случае, если C указывает в том же направлении, что и Vn, то theta отрицательно, так как вам нужно левое вращение. Вероятно, самый простой вычислительный способ быстро проверить, что Vn и C указывают в том же направлении, просто взять свой точечный продукт; если он положителен, они указывают в одном направлении.
Все это следует из элементарных свойств cross product.
Ответ 9
Это код Matlab для вычисления подписанного угла между двумя векторами u, v либо в 2D, либо в 3D. Код является самоочевидным. Выражение знака таково, что положительный + 90 ° выводится между ix и iy ([1,0,0], [0,1,0]) или iy и iz ([0,1,0], [0, 0,1])
function thetaDEG = angDist2Vecs(u,v)
if length(u)==3
%3D, can use cross to resolve sign
uMod = sqrt(sum(u.^2));
vMod = sqrt(sum(v.^2));
uvPr = sum(u.*v);
costheta = min(uvPr/uMod/vMod,1);
thetaDEG = acos(costheta)*180/pi;
%resolve sign
cp=(cross(u,v));
idxM=find(abs(cp)==max(abs(cp)));
s=sign(cp(idxM(1)));
if s < 0
thetaDEG = -thetaDEG;
end
elseif length(u)==2
%2D use atan2
thetaDEG = (atan2(v(2),v(1))-atan2(u(2),u(1)))*180/pi;
else
error('u,v must be 2D or 3D vectors');
end