Подписанный угол между двумя 3D-векторами с одинаковым началом в одной плоскости

Мне нужен подписанный угол поворота между двумя векторами Va и Vb, лежащими в одной и той же трехмерной плоскости и имеющими одно и то же происхождение, зная, что:

  1. Плоскость, контактирующая с обоими векторами, является произвольной и не параллельна XY или любой другой из кардинальных плоскостей
  2. Vn – нормальная плоскость
  3. Оба вектора вместе с нормалью имеют одинаковое начало O = {0, 0, 0}
  4. Va – эталон для измерения левого вращения при Vn

Угол должен быть измерен таким образом, чтобы, если плоскость была бы плоскостью XY, Va стояла бы за единичный вектор оси X.

Я предполагаю, что я должен выполнить какое-то преобразование координатного пространства, используя Va как ось X и поперечное произведение Vb и Vn как ось Y, а затем просто используя какой-то 2d-метод, например, с atan2 () или что-то еще. Есть идеи? Формулы?

Используйте перекрестное произведение двух векторов, чтобы получить нормаль плоскости, образованной двумя векторами. Затем проверьте, что dotproduct между ним и исходной плоскостью нормальный, чтобы увидеть, находятся ли они в одном направлении.

 angle = acos(dotProduct(Va.normalize(), Vb.normalize())); cross = crossProduct(Va, Vb); if (dotProduct(Vn, cross) < 0) { // Or > 0 angle = -angle; } 

Решение, которое я сейчас использую, похоже, отсутствует здесь. Предполагая, что нормаль плоскости нормирована ( |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) 

Вы можете сделать это в два этапа:

  1. Определить угол между двумя векторами

    theta = acos (точечный продукт Va, Vb). Предполагая, что Va, Vb нормированы. Это даст минимальный угол между двумя векторами

  2. Определить знак угла

    Найти вектор V3 = перекрестное произведение Va, Vb. (порядок важен)

    Если (точечный продукт V3, Vn) отрицательный, theta отрицателен. В противном случае тета положительна.

Вы можете получить угол под знаком, используя точечный продукт . Чтобы получить знак угла, возьмем знак Vn * (Va x Vb) . В частном случае плоскости XY это сводится к просто Va_x*Vb_y - Va_y*Vb_x .

Пересеките один вектор в другой и нормализовать, чтобы получить единичный вектор.

Синус угла между двумя векторами равняется величине поперечного произведения, деленному на величины двух векторов:

http://mathworld.wolfram.com/CrossProduct.html

Предположим, что Vx является осью x, с учетом нормали Vn, вы можете получить ось y поперечным произведением, вы можете проецировать вектор Vb в Vx и Vy (через точечный продукт вы можете получить длину проекции Vb на Vx и Vy), учитывая координату (x, y) на плоскости, вы можете использовать atan2 (y, x), чтобы получить угол в диапазоне [-pi, + pi]

Advanced Client предоставил следующее решение (изначально редактирование вопроса):

 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 } 

Пусть theta – угол между векторами. Пусть C = Va – поперечное произведение Vb. затем

sin theta = length (C) / (длина (Va) * длина (Vb))

Чтобы определить, является ли тета положительным или отрицательным, помните, что C перпендикулярно Va и Vb, указывающим направление, определенное правым правилом . Так, в частности, C параллельна Vn. В вашем случае, если C указывает в том же направлении, что и Vn, то theta отрицательно, так как вам нужно левое rotation. Вероятно, самый простой вычислительный способ быстро проверить, что Vn и C указывают в том же направлении, просто взять свой точечный продукт; если он положителен, они указывают в одном направлении.

Все это вытекает из элементарных свойств кросс-произведения .

Это код 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 
  • Матричная обратная точность
  • Как вы находите точку на заданном перпендикулярном расстоянии от линии?
  • N-ая комбинация
  • исправление искажений рыбий глаз программным путем
  • Как определить, находится ли точка в правой или левой части строки
  • Вычисление матрицы LookAt
  • C ++ библиотека с фиксированной точкой?
  • Как округлить до ближайшего 0,5?
  • Резиновое литье с разной высотой
  • Повышение точности решения трансцендентного уравнения
  • Математика с фиксированной точкой в ​​c #?
  • Давайте будем гением компьютера.