Skip to content

EulerAngles gives wrong result on a gymbal lock configuration

Summary

Eigen::EulerAngles gives a wrong result on a gymbal lock configuration

Environment

Godbolt x86-64 Eigen 3.4.0 gcc 12.2

Eigen versions prior to 3.4.0 don't seem to have the problem.

Minimal Example

https://godbolt.org/z/YWex16oWE

#include <iostream>
#include <unsupported/Eigen/EulerAngles>


int main() {
    Eigen::Quaterniond q(0.5, 0.5, 0.5, -0.5);
    std::cout << q.coeffs();
    std::cout << std::endl << std::endl;

    puts("eulerAngles gives correct XYZ angles:");
    Eigen::Vector3d ea = Eigen::Matrix3d(q).eulerAngles(1,0,2) / M_PI * 180.;
    std::cout << ea(0) << " " << ea(1) << " " << ea(2) << std::endl << std::endl;

    puts("Eigen::EulerAngles: (also correct in this case)");
    Eigen::Vector3d ea2 = Eigen::EulerAnglesYXZd(q).angles() / M_PI * 180.;
    std::cout << ea2(0) << " " << ea2(1) << " " << ea2(2) << std::endl << std::endl;

    puts ("The linear subspace of correct solutions satisfies \n"
          "first angle - third angle = 90\n");


    // Cursed quaternion for Eigen::EulerAnglesYXZ
    // Arch is x86-64
    Eigen::Quaterniond q2;
    auto& coeffs = q2.coeffs();
    *(uint64_t*)&coeffs(0) = 0x3FDFFFFFC0000000;
    *(uint64_t*)&coeffs(1) = 0x3FE0000000000001;
    *(uint64_t*)&coeffs(2) = 0xBFE0000000000000;
    *(uint64_t*)&coeffs(3) = 0x3FDFFFFFBFFFFFFE;

    puts("Almost the same quaternion, -0.000000059604645 diff in x and w \n"
        "due to floating point garbage. Printing it gives impression it is identical ");
    std::cout << q2.coeffs();
    std::cout << std::endl << std::endl;

    puts("eulerAngles method still works:");
    Eigen::Vector3d ea3 = Eigen::Matrix3d(q2).eulerAngles(1,0,2) / M_PI * 180.;
    std::cout << ea3(0) << " " << ea3(1) << " " << ea3(2) << std::endl << std::endl;
    
    Eigen::Vector3d ea4 = Eigen::EulerAnglesYXZd(q2).angles() / M_PI * 180.;
    puts("Eigen::EulerAngles on Eigen >= 3.4.0 now gives a wrong result, 0 90 0!");
    std::cout << ea4(0) << " " << ea4(1) << " " << ea4(2) << std::endl << std::endl;
}

Steps to reproduce

Open Godbolt

What is the current bug behavior?

Incorrect angles computed

What is the expected correct behavior?

Correct angles computed

Relevant logs

Eigen 3.4.0:

 0.5
 0.5
-0.5
 0.5

eulerAngles gives correct XYZ angles:
0 90 -90

Eigen::EulerAngles: (also correct in this case)
90 90 0

The linear subspace of correct solutions satisfies 
first angle - third angle = 90

Almost the same quaternion, -0.000000059604645 diff in x and w 
due to floating point garbage. Printing it gives impression it is identical 
 0.5
 0.5
-0.5
 0.5

eulerAngles method still works:
0 90 -90

Eigen::EulerAngles on Eigen >= 3.4.0 now gives a wrong result, 0 90 0!
0 90 1.06722e-07

On Godbolt, with Eigen 3.3.9 and prior it seems to work correctly:

 0.5
 0.5
-0.5
 0.5

eulerAngles gives correct XYZ angles:
0 90 -90

Eigen::EulerAngles: (also correct in this case)
0 90 -90

The linear subspace of correct solutions satisfies 
first angle - third angle = 90

Almost the same quaternion, -0.000000059604645 diff in x and w 
due to floating point garbage. Printing it gives impression it is identical 
 0.5
 0.5
-0.5
 0.5

eulerAngles method still works:
0 90 -90

Eigen::EulerAngles on Eigen >= 3.4.0 now gives a wrong result, 0 90 0!
0 90 -90
Edited by Juraj Oršulić