Ángulo firmado entre dos vectores 3D con el mismo origen dentro del mismo plano

Lo que necesito es un ángulo de rotación firmado entre dos vectores Va y Vb que se encuentran dentro del mismo plano 3D y tienen el mismo origen sabiendo que:

  1. El avión que contiene ambos vectores es arbitrario y no es paralelo a XY ni a ningún otro plano cardinal
  2. Vn – es un avión normal
  3. Ambos vectores junto con el normal tienen el mismo origen O = {0, 0, 0}
  4. Va – es una referencia para medir la rotación de zurdos en Vn

El ángulo debe medirse de tal manera que si el plano fuese XY, el Va representaría el vector de la unidad del eje X.

Supongo que debería realizar una especie de transformación del espacio de coordenadas usando Va como el eje X y el producto cruzado de Vb y Vn como el eje Y y luego simplemente usando algún método 2d como con atan2 () o algo así. ¿Algunas ideas? Fórmulas?

Use el producto cruzado de los dos vectores para obtener la normalidad del plano formado por los dos vectores. Luego, compruebe el producto de puntos entre ese y el plano original normal para ver si están orientados en la misma dirección.

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

La solución que estoy usando parece faltar aquí. Suponiendo que el plano normal está normalizado ( |Vn| == 1 ), el ángulo firmado es simplemente:

atan2((Vb x Va) . Vn, Va . Vb)

que devuelve un ángulo en el rango [-PI, + PI] (o lo que sea que devuelva la implementación atan2 disponible).

. y x son el producto punto y cruz respectivamente.

No es necesario realizar una bifurcación explícita ni calcular la longitud de la división / vector. Use Va x Vb para la rotación de la mano derecha en lugar de la izquierda

Explicación de por qué esto funciona: permita que alfa sea el ángulo directo entre los vectores (0 ° a 180 °) y beta el ángulo que estamos buscando (0 ° a 360 °) con beta == alpha o 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) 

Finalmente

 tan(beta) = sin(beta) / cos(beta) == ((Va x Vb) . Vn) / (Va . Vb) 

Puedes hacer esto en dos pasos:

  1. Determine el ángulo entre los dos vectores

    theta = acos (producto de puntos de Va, Vb). Suponiendo que Va, Vb están normalizados. Esto dará el ángulo mínimo entre los dos vectores

  2. Determine el signo del ángulo

    Encuentre el vector V3 = producto cruzado de Va, Vb. (el orden es importante)

    Si (producto de punto de V3, Vn) es negativo, theta es negativo. De lo contrario, theta es positivo.

Puede obtener el ángulo para firmar usando el producto de puntos . Para obtener el signo del ángulo, toma el signo de Vn * (Va x Vb) . En el caso especial del plano XY, esto se reduce a solo Va_x*Vb_y - Va_y*Vb_x .

Cruce un vector en el otro y normalícelo para obtener el vector unitario.

El seno del ángulo entre los dos vectores es igual a la magnitud del producto cruzado dividido por las magnitudes de los dos vectores:

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

Supongamos que Vx es el eje x, dado el Vn normal, puede obtener el eje y por producto cruzado, puede proyectar el vector Vb a Vx y Vy (mediante el producto escalar puede obtener la longitud de la proyección de Vb en Vx y Vy), dada la coordenada (x, y) en el plano, puedes usar atan2 (y, x) para obtener el ángulo en el rango [-pi, + pi]

Advanced Customer proporcionó la siguiente solución (originalmente una edición de la pregunta):

 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 } 

Deje que theta sea el ángulo entre los vectores. Deje que C = Va cruce el producto Vb. Entonces

sin theta = longitud (C) / (longitud (Va) * longitud (Vb))

Para determinar si theta es positivo o negativo, recuerde que C es perpendicular a Va y Vb apuntando en la dirección determinada por la regla de la mano derecha . Entonces, en particular, C es paralelo a Vn. En su caso, si C apunta en la misma dirección que Vn, entonces theta es negativo, ya que desea la rotación de la mano izquierda. Probablemente la forma computacional más sencilla para comprobar rápidamente si Vn y C apuntan en la misma dirección es simplemente tomar su producto de puntos; si es positivo apuntan en la misma dirección.

Todo esto se desprende de las propiedades elementales del producto cruzado .

Este es el código de Matlab para calcular el ángulo firmado entre dos vectores u, v en 2D o en 3D. El código es auto explicativo. La convención de signos es tal que se emite un + 90 ° positivo entre ix e iy ([1,0,0], [0,1,0]) o iy e 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