Because I'm a new user, I can't post images or hyperlinks, there is a complete version with images here:
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:
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...