Como converter ângulos de Euler para vetor direcional?

Eu tenho ângulos de inclinação, inclinação e guinada. Como eu converteria estes em um vetor direcional?

Seria especialmente legal se você pudesse me mostrar uma representação quaternária e / ou matricial disso!

Infelizmente existem diferentes convenções sobre como definir essas coisas (e roll, pitch, yaw não são exatamente o mesmo que os de Euler), então você terá que ser cuidadoso.

Se definirmos pitch = 0 como horizontal (z = 0) e yaw como sentido anti-horário a partir do eixo x, então o vetor de direção será

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

Note que eu não usei roll; isso é vetor de unidade de direção, não especifica atitude. É bastante fácil escrever uma matriz de rotação que carregará as coisas no quadro do object voador (se você quiser saber, por exemplo, onde a ponta da asa esquerda está apontando), mas é realmente uma boa idéia especificar as convenções primeiro. Você pode nos contar mais sobre o problema?

EDIT: (Eu estava querendo voltar a essa pergunta por dois anos e meio.)

Para a matriz de rotação completa, se usarmos a convenção acima e quisermos que o vetor gire primeiro, depois arremessemos e depois rolemos para obter as coordenadas finais no quadro de coordenadas mundiais, devemos aplicar as matrizes de rotação na ordem inversa.

Primeiro rolo:

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

depois lance:

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

então guinchar:

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

Combine-os e a matriz de rotação total é:

 | 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)| 

Então, para um vetor unitário que começa no eixo x, as coordenadas finais serão:

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

E para o vetor unitário que começa no eixo y (a ponta da asa esquerda), as coordenadas finais serão:

 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) 

Existem seis maneiras diferentes de converter três ângulos de Euler em uma matriz, dependendo do pedido em que são aplicados:

 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, algumas CPUs podem calcular Sin & Cos simultaneamente (por exemplo, fsincos on x86). Se você fizer isso, poderá torná-lo um pouco mais rápido com três chamadas, em vez de 6, para calcular os valores iniciais de sin e cos.

Atualização: Existem na verdade 12 maneiras dependendo se você quer resultados destros ou canhotos – você pode mudar a “lateralidade” negando os ângulos.

Beta salvou meu dia. No entanto, estou usando um sistema de coordenadas de referência ligeiramente diferente e minha definição de pitch é para cima / para baixo (acenando com a cabeça em concordância), onde um pitch positivo resulta em um componente y negativo . Meu vetor de referência é o estilo OpenGl (abaixo do eixo -z), portanto, com yaw = 0, pitch = 0, o vetor unitário resultante deve ser igual a (0, 0, -1). Se alguém se deparar com este post e tiver dificuldades em traduzir as fórmulas do Beta para esse sistema em particular, as equações que eu uso são:

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

Observe a mudança de sinal e o guinada <-> pitch swap. Espero que isso vai salvar alguém algum tempo.

Você precisa ser claro sobre suas definições aqui – em particular, qual é o vetor que você quer? Se é a direção que uma aeronave está apontando, o rolo nem mesmo a afeta, e você está apenas usando coordenadas esféricas (provavelmente com eixos / ângulos permutados).

Se, por outro lado, você quiser pegar um determinado vetor e transformá-lo por esses ângulos, você está procurando por uma matriz de rotação. O artigo do wiki sobre matrizes de rotação contém uma fórmula para uma rotação de inclinação-rotação-rotação, baseada nas matrizes de rotação xyz. Não vou tentar entrar aqui, dadas as letras e matrizes gregas envolvidas.

Se alguém se deparar com a procura de implementação no 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)