Cómo convertir los angularjs de Euler al vector direccional?

Tengo angularjs de cabeceo, balanceo y guiñada. ¿Cómo los convertiría en un vector direccional?

¡Sería especialmente genial si me puedes mostrar un cuaternión y / o una representación de matriz de esto!

Desafortunadamente, hay diferentes convenciones sobre cómo definir estas cosas (y el balanceo, el cabeceo, la guiñada no son lo mismo que los angularjs de Euler), así que tendrás que tener cuidado.

Si definimos pitch = 0 como horizontal (z = 0) y giramos en sentido antihorario desde el eje x, entonces el vector de dirección será

 x = cos (yaw) * cos (tono)
 y = sin (yaw) * cos (tono)
 z = sin (tono)

Tenga en cuenta que no he usado rollo; este es el vector de unidad de dirección, no especifica la actitud. Es bastante fácil escribir una matriz de rotación que lleve las cosas al marco del objeto volador (si quiere saber, por ejemplo, hacia dónde apunta la punta del ala izquierda), pero en realidad es una buena idea especificar primero las convenciones. ¿Puedes decirnos más sobre el problema?

EDITAR: (He estado pensando en volver a esta pregunta durante dos años y medio).

Para la matriz de rotación completa, si usamos la convención anterior y queremos que el vector gire primero, luego tilde y luego gire, para obtener las coordenadas finales en el marco de coordenadas del mundo debemos aplicar las matrices de rotación en el orden inverso.

Primer lanzamiento:

| 1 0 0 | | 0 cos(roll) -sin(roll) | | 0 sin(roll) cos(roll) | 

luego tono:

 | cos(pitch) 0 -sin(pitch) | | 0 1 0 | | sin(pitch) 0 cos(pitch) | 

luego se desvía

 | cos(yaw) -sin(yaw) 0 | | sin(yaw) cos(yaw) 0 | | 0 0 1 | 

Combínalos, y la matriz de rotación total es:

 | cos(yaw)cos(pitch) -cos(yaw)sin(pitch)sin(roll)-sin(yaw)cos(roll) -cos(yaw)sin(pitch)cos(roll)+sin(yaw)sin(roll)| | sin(yaw)cos(pitch) -sin(yaw)sin(pitch)sin(roll)+cos(yaw)cos(roll) -sin(yaw)sin(pitch)cos(roll)-cos(yaw)sin(roll)| | sin(pitch) cos(pitch)sin(roll) cos(pitch)sin(roll)| 

Entonces, para un vector unitario que comienza en el eje x, las coordenadas finales serán:

 x = cos(yaw)cos(pitch) y = sin(yaw)cos(pitch) z = sin(pitch) 

Y para el vector unitario que comienza en el eje y (la punta del ala izquierda), las coordenadas finales serán:

 x = -cos(yaw)sin(pitch)sin(roll)-sin(yaw)cos(roll) y = -sin(yaw)sin(pitch)sin(roll)+cos(yaw)cos(roll) z = cos(pitch)sin(roll) 

Hay seis formas diferentes de convertir tres angularjs de Euler en una matriz según el orden en que se apliquen:

 typedef float Matrix[3][3]; struct EulerAngle { float X,Y,Z; }; // Euler Order enum. enum EEulerOrder { ORDER_XYZ, ORDER_YZX, ORDER_ZXY, ORDER_ZYX, ORDER_YXZ, ORDER_XZY }; Matrix EulerAnglesToMatrix(const EulerAngle &inEulerAngle,EEulerOrder EulerOrder) { // Convert Euler Angles passed in a vector of Radians // into a rotation matrix. The individual Euler Angles are // processed in the order requested. Matrix Mx; const FLOAT Sx = sinf(inEulerAngle.X); const FLOAT Sy = sinf(inEulerAngle.Y); const FLOAT Sz = sinf(inEulerAngle.Z); const FLOAT Cx = cosf(inEulerAngle.X); const FLOAT Cy = cosf(inEulerAngle.Y); const FLOAT Cz = cosf(inEulerAngle.Z); switch(EulerOrder) { case ORDER_XYZ: Mx.M[0][0]=Cy*Cz; Mx.M[0][1]=-Cy*Sz; Mx.M[0][2]=Sy; Mx.M[1][0]=Cz*Sx*Sy+Cx*Sz; Mx.M[1][1]=Cx*Cz-Sx*Sy*Sz; Mx.M[1][2]=-Cy*Sx; Mx.M[2][0]=-Cx*Cz*Sy+Sx*Sz; Mx.M[2][1]=Cz*Sx+Cx*Sy*Sz; Mx.M[2][2]=Cx*Cy; break; case ORDER_YZX: Mx.M[0][0]=Cy*Cz; Mx.M[0][1]=Sx*Sy-Cx*Cy*Sz; Mx.M[0][2]=Cx*Sy+Cy*Sx*Sz; Mx.M[1][0]=Sz; Mx.M[1][1]=Cx*Cz; Mx.M[1][2]=-Cz*Sx; Mx.M[2][0]=-Cz*Sy; Mx.M[2][1]=Cy*Sx+Cx*Sy*Sz; Mx.M[2][2]=Cx*Cy-Sx*Sy*Sz; break; case ORDER_ZXY: Mx.M[0][0]=Cy*Cz-Sx*Sy*Sz; Mx.M[0][1]=-Cx*Sz; Mx.M[0][2]=Cz*Sy+Cy*Sx*Sz; Mx.M[1][0]=Cz*Sx*Sy+Cy*Sz; Mx.M[1][1]=Cx*Cz; Mx.M[1][2]=-Cy*Cz*Sx+Sy*Sz; Mx.M[2][0]=-Cx*Sy; Mx.M[2][1]=Sx; Mx.M[2][2]=Cx*Cy; break; case ORDER_ZYX: Mx.M[0][0]=Cy*Cz; Mx.M[0][1]=Cz*Sx*Sy-Cx*Sz; Mx.M[0][2]=Cx*Cz*Sy+Sx*Sz; Mx.M[1][0]=Cy*Sz; Mx.M[1][1]=Cx*Cz+Sx*Sy*Sz; Mx.M[1][2]=-Cz*Sx+Cx*Sy*Sz; Mx.M[2][0]=-Sy; Mx.M[2][1]=Cy*Sx; Mx.M[2][2]=Cx*Cy; break; case ORDER_YXZ: Mx.M[0][0]=Cy*Cz+Sx*Sy*Sz; Mx.M[0][1]=Cz*Sx*Sy-Cy*Sz; Mx.M[0][2]=Cx*Sy; Mx.M[1][0]=Cx*Sz; Mx.M[1][1]=Cx*Cz; Mx.M[1][2]=-Sx; Mx.M[2][0]=-Cz*Sy+Cy*Sx*Sz; Mx.M[2][1]=Cy*Cz*Sx+Sy*Sz; Mx.M[2][2]=Cx*Cy; break; case ORDER_XZY: Mx.M[0][0]=Cy*Cz; Mx.M[0][1]=-Sz; Mx.M[0][2]=Cz*Sy; Mx.M[1][0]=Sx*Sy+Cx*Cy*Sz; Mx.M[1][1]=Cx*Cz; Mx.M[1][2]=-Cy*Sx+Cx*Sy*Sz; Mx.M[2][0]=-Cx*Sy+Cy*Sx*Sz; Mx.M[2][1]=Cz*Sx; Mx.M[2][2]=Cx*Cy+Sx*Sy*Sz; break; } return(Mx); } 

FWIW, algunas CPU pueden calcular Sin & Cos simultáneamente (por ejemplo, fsincos en x86). Si hace esto, puede hacerlo un poco más rápido con tres llamadas en lugar de 6 para calcular los valores iniciales de sin y cos.

Actualización: en realidad, hay 12 formas dependiendo de si desea resultados para diestros o zurdos: puede cambiar la “lateralidad” anulando los angularjs.

Beta me salvó el día. Sin embargo, estoy usando un sistema de coordenadas de referencia ligeramente diferente y mi definición de tono está arriba / abajo (asintiendo con la cabeza), donde un tono positivo resulta en un componente y negativo . Mi vector de referencia es el estilo OpenGl (abajo del eje -z) así que con yaw = 0, pitch = 0, el vector unitario resultante debería ser igual (0, 0, -1). Si alguien se encuentra con esta publicación y tiene dificultades para traducir las fórmulas de Beta a este sistema en particular, las ecuaciones que uso son:

 vDir->X = sin(yaw); vDir->Y = -(sin(pitch)*cos(yaw)); vDir->Z = -(cos(pitch)*cos(yaw)); 

Tenga en cuenta el cambio de signo y el cambio de tono de guiñada <->. Espero que esto le ahorre a alguien algo de tiempo.

Debe tener claras sus definiciones aquí, en particular, ¿cuál es el vector que desea? Si es la dirección hacia la que apunta un avión, el balanceo ni siquiera lo afecta, y solo está utilizando coordenadas esféricas (probablemente con ejes / angularjs permutados).

Si, por otro lado, quieres tomar un vector dado y transformarlo por estos angularjs, estás buscando una matriz de rotación. El artículo de wiki sobre matrices de rotación contiene una fórmula para una rotación de balanceo de cabeceo basado en las matrices de rotación xyz. No voy a intentar ingresar aquí, dadas las letras griegas y las matrices involucradas.

Si alguien tropieza con buscar implementación en FreeCAD.

 import FreeCAD, FreeCADGui from FreeCAD import Vector from math import sin, cos, pi cr = FreeCADGui.ActiveDocument.ActiveView.getCameraOrientation().toEuler() crx = cr[2] # Roll cry = cr[1] # Pitch crz = cr[0] # Yaw crx = crx * pi / 180.0 cry = cry * pi / 180.0 crz = crz * pi / 180.0 x = sin(crz) y = -(sin(crx) * cos(crz)) z = cos(crx) * cos(cry) view = Vector(x, y, z)