[Math] Convert from fixed axis $XYZ$ rotations to Euler $ZXZ$ rotations

matricesrotations

Because I'm a new user, I can't post images or hyperlinks, there is a complete version with images here:

https://stackoverflow.com/questions/9774958/converting-from-a-euler-zxz-rotation-to-fixed-axis-xyz-rotations

The problem I have, is that I need to convert from $XYZ$ fixed axis rotations, to Euler rotations about $Z$, then $X'$, then $Z''$.

Here are the relevant matricies:

$$X = \left(\begin{matrix} 1 & 0 & 0 \\ 0 & \cos(\theta) & -\sin(\theta) \\ 0 & \sin(\theta) & \cos(\theta)\end{matrix}\right)$$

$$Y = \left(\begin{matrix} \cos(\phi) & 0 & \sin(\phi) \\ 0 & 1 & 0 \\ -\sin(\phi) & 0 & \cos(\phi)\end{matrix}\right)$$

$$Z = \left(\begin{matrix} \cos(\psi) & -\sin(\psi) & 0 \\ \sin(\psi) & \cos(\psi) & 0 \\ 0 & 0 & 1\end{matrix}\right)$$

Combined, as $R_z(\psi) R_y(\phi) R_x(\theta) = R_{xyz}(\theta,\phi,\psi)$; they give:

$R_{xyz}$: i.imgur.com/8UQM6.jpg

And the Rotation matrix for the Specific convention of Euler angles I want; is this:

Euler: Euler

So my initial plan, was to compare matrix elements, and extract the angles I wanted that way; I came up with this (actual current code at the end):

But this doesn't work under several circumstances. The most obvious being when $\cos(\theta)\cos(\phi) = 1$; since then $\cos(\beta) = 1$, and so $\sin(\beta) = 0$. Where $\sin(\beta)$ is s2 in the code. This happens only when $\cos(\theta)$ and $\cos(\phi) = \pm 1$.

So right away I can just rule out the possible situations;

When $\theta$ or $\phi = 0, 180, 360, 540, \ldots$, then $\cos(\theta)$, and $\cos(\phi)$ are $\pm 1$;

so I only need to do it differently for these cases;

And I ended up with this code:

public static double[] ZXZtoEuler(double θ, double φ, double ψ){

    θ *= Math.PI/180.0;
    φ *= Math.PI/180.0;
    ψ *= Math.PI/180.0;

    double α = -1;
    double β = -1;
    double γ = -1;

    double c2 = Math.cos(θ) * Math.cos(φ);

    β = Math.acos(r(c2));

    if(eq(c2,1) || eq(c2,-1)){
        if(eq(Math.cos(θ),1)){
            if(eq(Math.cos(φ),1)){
                α = 0.0;
                γ = ψ;
            }else if(eq(Math.cos(φ),-1)){
                α = 0.0;
                γ = Math.PI - ψ;
            }
        }else if(eq(Math.cos(θ),-1)){
            if(eq(Math.cos(φ),1)){
                α = 0.0;
                γ = -ψ;
            }else if(eq(Math.cos(φ),-1)){
                α = 0.0;
                γ = ψ + Math.PI;
            }
        }
    }else{

        //original way

        double s2 = Math.sin(β);

        double c3 = ( Math.sin(θ) * Math.cos(φ) )/ s2;
        double s1 = ( Math.sin(θ) * Math.sin(ψ) + Math.cos(θ) * Math.sin(φ) * Math.cos(ψ) )/s2;

        γ = Math.acos(r(c3));
        α = Math.asin(r(s1));

    }

    α *= 180/Math.PI;
    β *= 180/Math.PI;
    γ *= 180/Math.PI;

    return new double[] {r(α), r(β), r(γ)};
}

Where r and eq are just two simple functions;

public static double r(double a){
    double prec = 1000000000.0;
    return Math.round(a*prec)/prec;
}

static double thresh = 1E-4;
public static boolean eq(double a, double b){
    return (Math.abs(a-b) < thresh);
}

eq is just to compare the numbers for tests, and r is to prevent floating point errors pushing numbers outside the range of Math.acos / Math.asin and giving me NaN results;

(i.e. every now and then I'd end up with Math.acos(1.000000000000000004) or something.)

Which takes into account the 4 cases of having rotations around $x$ and $y$ which leave c2==1.

But now is where the problem occurs;

Everything I have done above, makes sense to me, but it does not give the correct angles;

Here is some output, in each pair, the first are the $\theta, \phi, \psi$ angles, and the second of each pair is the corresponding $\alpha, \beta, \gamma$ lines. Ignoring the rounding errors, it seems to be getting some of the angles off by about

[0.0, 0.0, 0.0] – correct!
[0.0, 0.0, 0.0]

[0.0, 0.0, 45.0] – correct!
[0.0, 0.0, 45.0]

[0.0, 0.0, 90.0] – correct!
[0.0, 0.0, 90.0]

[0.0, 0.0, 135.0] – correct!
[0.0, 0.0, 135.0]

[0.0, 0.0, 180.0] – correct
[0.0, 0.0, 180.0]

[0.0, 0.0, 225.0] – correct
[0.0, 0.0, 225.0]

[0.0, 0.0, 270.0] – correct
[0.0, 0.0, 270.0]

[0.0, 0.0, 315.0] – correct
[0.0, 0.0, 315.0]

[0.0, 45.0, 0.0] – incorrect: should be [90, 45, -90]
[90.0, 44.999982, 90.0]

[0.0, 45.0, 45.0]
[45.000018, 44.999982, 90.0]

[0.0, 45.0, 90.0]
[0.0, 44.999982, 90.0]

[0.0, 45.0, 135.0]
[-45.000018, 44.999982, 90.0]

[0.0, 45.0, 180.0]
[-90.0, 44.999982, 90.0]

[0.0, 45.0, 225.0]
[-45.000018, 44.999982, 90.0]

[0.0, 45.0, 270.0]
[0.0, 44.999982, 90.0]

[0.0, 45.0, 315.0]
[45.000018, 44.999982, 90.0]

[0.0, 90.0, 0.0]
[90.0, 90.0, 90.0]

[0.0, 90.0, 45.0]
[45.000018, 90.0, 90.0]

[0.0, 90.0, 90.0]
[0.0, 90.0, 90.0]

[0.0, 90.0, 135.0]
[-45.000018, 90.0, 90.0]

[0.0, 90.0, 180.0]
[-90.0, 90.0, 90.0]

[0.0, 90.0, 225.0]
[-45.000018, 90.0, 90.0]

Can anyone think of a solution?

EDIT: I don't know if this helps, but there are a few other ways at looking at these rotations:

A way to rotate about an arbitrary axis, is to reorient that axis as the Z Axis, and then do the inverse of the reorientation; you can apply this over and over, to obtain the Euler rotations in terms of the original fixed axis rotations;

$$R_{Z^{\prime\prime} X^{\prime} Z}(\alpha,\beta,\gamma) = R_{Z^{\prime\prime}}(\gamma)R_{X^{\prime}}(\beta)R_Z(\alpha)$$

$$R_{X^{\prime}}(\beta) = R_Z(\alpha)R_Y(\frac{\pi}{2})R_Z(\beta)R_Y(-\frac{\pi}{2})R_Z(-\alpha)$$

so

$$R_{X^{\prime}}(\beta)R_Z(\alpha) = R_Z(\alpha)R_Y(\frac{\pi}{2})R_Z(\beta)R_Y(-\frac{\pi}{2})$$

$$R_{Z^{\prime\prime}} = R_Z(\alpha)R_Y(\frac{\pi}{2})R_Z(\beta)R_Y(-\frac{\pi}{2})R_Z(\gamma)R_Y(\frac{\pi}{2})R_Z(-\beta)R_Y(-\frac{\pi}{2})R_Z(-\alpha)$$

And so the whole thing;

$$R_{Z^{\prime\prime}}(\gamma)R_{X^{\prime}}(\beta)R_Z(\alpha) = R_Z(\alpha)R_Y(\frac{\pi}{2})R_Z(\beta)R_Y(-\frac{\pi}{2})R_Z(\gamma)R_Y(\frac{\pi}{2})R_Z(-\beta)R_Y(-\frac{\pi}{2})R_Z(-\alpha)R_Z(\alpha)R_Y(\frac{\pi}{2})R_Z(\beta)R_Y(-\frac{\pi}{2})$$

Which cancels down;

$$R_{Z^{\prime\prime}}(\gamma)R_{X^{\prime}}(\beta)R_Z(\alpha) = R_Z(\alpha)R_Y(\frac{\pi}{2})R_Z(\beta)R_Y(-\frac{\pi}{2})R_Z(\gamma)R_Y(\frac{\pi}{2})R_Z(-\beta)\mathbf{R_Y(-\frac{\pi}{2})R_Y(\frac{\pi}{2})}R_Z(\beta)R_Y(-\frac{\pi}{2})$$

$$R_{Z^{\prime\prime}}(\gamma)R_{X^{\prime}}(\beta)R_Z(\alpha) = R_Z(\alpha)R_Y(\frac{\pi}{2})R_Z(\beta)R_Y(-\frac{\pi}{2})R_Z(\gamma)R_Y(\frac{\pi}{2})\mathbf{R_Z(-\beta)R_Z(\beta)}R_Y(-\frac{\pi}{2})$$

$$R_{Z^{\prime\prime}}(\gamma)R_{X^{\prime}}(\beta)R_Z(\alpha) = R_Z(\alpha)R_Y(\frac{\pi}{2})R_Z(\beta)R_Y(-\frac{\pi}{2})R_Z(\gamma)\mathbf{R_Y(\frac{\pi}{2})R_Y(-\frac{\pi}{2})}$$

$$R_{Z^{\prime\prime}}(\gamma)R_{X^{\prime}}(\beta)R_Z(\alpha) = R_Z(\alpha)R_Y(\frac{\pi}{2})R_Z(\beta)R_Y(-\frac{\pi}{2})R_Z(\gamma)$$

And note that
$$R_Y(\frac{\pi}{2})R_Z(\beta)R_Y(-\frac{\pi}{2}) = R_X(\beta)$$

so we have
$$R_{Z^{\prime\prime}}(\gamma)R_{X^{\prime}}(\beta)R_Z(\alpha) = R_Z(\alpha)R_X(\beta)R_Z(\gamma)$$

Now i'm not sure how much this might help… but it's something i guess…

Best Answer

This paper describes exactly what you need.

Read this, and then this.

Then if you read a little deeper, you'll find this:

Here is some EulerAngles Code, which you can have a look at...

this google search also gives lots of other solutions to your problem.

You can actually use these methods to recover the regular rotation angles too, as constructing the rotation matrix is trivial, and you only need to reverse the order of the euler rotations to get the the regular rotation angles.

(where by regular and euler, i just mean intrinsic and extrinsic)

EDIT: just realised i answered my own question by accident...