Pergunta

Estou tentando converter uma rotação 3D descrita no termo dos ângulos de Euler em uma matriz e depois atrás, usando .NET/C#. Minhas convenções são:

  • Sistema canhoto (x direita, y top, z para frente)
  • Ordem de rotações: indo em torno de Y, arrementa em volta x, banco em torno de z
  • As rotações são positivas usando a regra da esquerda (apontando o polegar para +infinito)

Meu julgamento é:

Euler para Matrix (Eu removi a parte de tradução x, y, z para simplificação)

Matrix3D matrix = new Matrix3D() {
    M11 =   cosH * cosB - sinH * sinP * sinB,
    M12 = - sinB * cosP,
    M13 =   sinH * cosB + cosH * sinP * sinB,
    M21 =   cosH * sinB + sinH * sinP * cosB,
    M22 =   cosB * cosP,
    M23 =   sinB * sinH - cosH * sinP * cosB,
    M31 = - sinH * cosP,
    M32 = - sinP,
    M33 =   cosH * cosP,
};

Matriz para Euler

const double RD_TO_DEG = 180 / Math.PI;            
double h, p, b; // angles in degrees

// extract pitch
double sinP = -matrix.M23;            
if (sinP >= 1) {
    p = 90; }       // pole
else if (sinP <= -1) {
    p = -90; } // pole
else {
    p = Math.Asin(sinP) * RD_TO_DEG; }             

// extract heading and bank
if (sinP < -0.9999 || sinP > 0.9999) { // account for small angle errors
    h = Math.Atan2(-matrix.M31, matrix.M11) * RD_TO_DEG;
    b = 0; }
else {
    h = Math.Atan2(matrix.M13, matrix.M33) * RD_TO_DEG;
    b = Math.Atan2(matrix.M21, matrix.M22) * RD_TO_DEG; }

Deve estar errado. Se eu pegar 3 ângulos, convertê -los em uma matriz e converter a matriz de volta em ângulos, o resultado se diferente dos valores íntimos.

Eu naveguei em vários sites com fórmulas diferentes, começando com euclideanspace.com, mas agora estou completamente perdido e não consigo encontrar os cálculos certos. Agradeço uma pequena ajuda. Existe um matemático a bordo?

Foi útil?

Solução

Em primeiro lugar, deveria:

sinP = -matrix.M32

EDITAR: Solução completa segue

Minha derivação:

Rx(P)=| 1      0       0 |
      | 0  cos P  -sin P |
      | 0  sin P   cos P |

Ry(H)=|  cos H  0  sin H |
      |      0  1      0 |
      | -sin H  0  cos H |

Rz(B)=| cos B  -sin B  0 |
      | sin B   cos B  0 |
      |     0       0  1 |

Multiplicado com o seu pedido:

R = Ry(H)*Rx(P)*Rz(B)
  = | cos H*cos B+sin H*sin P*sin B  cos B*sin H*sin P-sin B*cos H  cos P*sin H |
    |                   cos P*sin B                    cos B*cos P       -sin P |
    | sin B*cos H*sin P-sin H*cos B  sin H*sin B+cos B*cos H*sin P  cos P*cos H |

Que dá derivações reversas:

tan b = m12/m22

sin p = -m32

tan h = m31/m33

Outras dicas

Sua ideia está errada: "Deve estar errado. Se eu levar 3 ângulos, convertê -los em uma matriz e converter a matriz de volta em ângulos, o resultado se diferente dos valores ínticos". Teria sido bonito, mas não é necessariamente verdadeiro. Em geral, mais de um trigêmeo de ângulos de Euler (fixado a convenção) leva à mesma orientação no espaço. Isso não significa que, no seu cálculo, não existe um erro. Da Wikipedia: "Por exemplo, suponha que usemos a convenção ZYZ acima; então temos os seguintes pares equivalentes: (90 °, 45 °, −105 °) ≡ (−270 °, −315 °, 255 °) de múltiplos de 360 ° (72 °, 0 °, 0 °) ≡ (40 °, 0 °, 32 °) alinhamento singular (45 °, 60 °, −30 °) ≡ (−135 °, −60 °, 150 °) FILHA "

Há um grande número de combinações dessas funções à medida que a resposta muda, dependendo de suas convenções. Normalmente, estou usando o DirectX e as mesmas convenções que a unidade. Além disso, meu plano de fundo é o Flightstims, o espaço e os mapas, então a guinada e depois o rolo corresponde ao estilo Lat/Lon também.

Não estar claro sobre as convenções ou ter funções incompatíveis de composição/decomposição pode levar a bugs muito ímpares. Também vale a pena ter em mente que vários conjuntos de ângulos de Euler podem produzir a mesma orientação.

Convenções (como acima):

  • Ângulos de Euler: x = pitch, y = guinada, z = rolo
  • Ordem de Euler: rotação aplicada, guinada e depois enrole
  • Eixos: +x à direita, +y para cima, +z para a frente
  • Matrizes: Convenções DirectX (usando simplemath.h de ms Directxtk)

Para converter para a versão OpenGL, dê uma olhada isto.

eu tenho tomado Mike TunnicliffeA resposta e converteu -a ao código C ++ e a adicionou à minha biblioteca. Espero que outras pessoas economizem algum tempo usando -o.

Vale a pena notar que a função de composição limpa a 4ª coluna e o componente de tradução para a identidade, e a função decomposta assume que o elemento de rotação 3x3 contém rotação pura (ou seja, sem escala etc.).

Em primeiro lugar, o código para gerar uma matriz de Eulers:

//====================================================================================================
// MatrixFromYawPitchRoll
//
// Create matrix based on provided yaw (heading), pitch and roll (bank).
//
// Assumptions:
//  Euler:   X = Pitch, Y = Yaw, Z = Roll
//  Applied: Yaw then pitch then roll
//  Axes:    X = Right, Y = Up, Z = Forward
//  DirectX: Matrices are row major (http://www.mindcontrol.org/~hplus/graphics/matrix-layout.html)
//
// Code is based on Mike Tunnicliffe's answer to this question:
//   https://stackoverflow.com/questions/1996957/conversion-euler-to-matrix-and-matrix-to-euler
inline void MatrixFromYawPitchRoll(
    const DirectX::SimpleMath::Vector3& euler,
    DirectX::SimpleMath::Matrix&        mat)
{
    float cosY = cosf(euler.y);     // Yaw
    float sinY = sinf(euler.y);

    float cosP = cosf(euler.x);     // Pitch
    float sinP = sinf(euler.x);

    float cosR = cosf(euler.z);     // Roll
    float sinR = sinf(euler.z);

    mat = DirectX::SimpleMath::Matrix::Identity;
    mat._11 = cosY * cosR + sinY * sinP * sinR;
    mat._21 = cosR * sinY * sinP - sinR * cosY;
    mat._31 = cosP * sinY;

    mat._12 = cosP * sinR;
    mat._22 = cosR * cosP;
    mat._32 = -sinP;

    mat._13 = sinR * cosY * sinP - sinY * cosR;
    mat._23 = sinY * sinR + cosR * cosY * sinP;
    mat._33 = cosP * cosY;
}

Em seguida, código para recuperar os ângulos de Euler da Matrix:

//====================================================================================================
// MatrixDecomposeYawPitchRoll
//
// Extract the rotation contained in the provided matrix as yaw (heading), pitch and roll (bank) in
// radiuans.
//
// Assumptions:
//  Euler:   X = Pitch, Y = Yaw, Z = Roll
//  Applied: Yaw then pitch then roll
//  Axes:    X = Right, Y = Up, Z = Forward
//  DirectX: Matrices are row major (http://www.mindcontrol.org/~hplus/graphics/matrix-layout.html)
//
// Code is based on Mike Tunnicliffe's answer to this question:
//   https://stackoverflow.com/questions/1996957/conversion-euler-to-matrix-and-matrix-to-euler
inline void MatrixDecomposeYawPitchRoll(
    const DirectX::SimpleMath::Matrix&  mat,
    DirectX::SimpleMath::Vector3&       euler)
{
    euler.x = asinf(-mat._32);                  // Pitch
    if (cosf(euler.x) > 0.0001)                 // Not at poles
    {
        euler.y = atan2f(mat._31, mat._33);     // Yaw
        euler.z = atan2f(mat._12, mat._22);     // Roll
    }
    else
    {
        euler.y = 0.0f;                         // Yaw
        euler.z = atan2f(-mat._21, mat._11);    // Roll
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top