Here's another technical article. The last one was about rendering; this time I'm switching to animation (specifically, rotation).
Euler angles have well-known limitations, such as gimbal lock. Another slightly-less-well-known issue is the way in which there are many different (rx,ry,rz) triplets that all encode the same orientation, and writing a program to choose the "right" triplet for a given orientation is sometimes a lot more difficult than it would seem. This problem can come up when implementing a user-interface control for instance, or a dynamics engine. Any time that a program has an non-Euler orientation (expressed as a quaternion, a matrix, and axis and an angle, or whatever) and it has to convert it to a triplet of Euler angles that must fit in smoothly with a sequence of other Euler angles, you have to be careful how you choose which triplet to use.
It's not hard to find convert a quaternion to a valid triplet triplet of Euler angles, of course. Ken Shoemake's article in Graphics Gems IV (for instance) demonstrates how to do that. But applying his recipe to a sequence of smoothly-varying orientations doesn't necessarily produce a sequence of smoothly-varying Euler triplets. For instance, because you can add or subtract any multiple of 360 degrees to any of the three Euler angles and the triplet still describes the same orientation, our valid sequence of Euler triplets might have objectionable 360-degree discontinuities in it. We could make a rule that indicates which value is preferred (like, the angle with the smallest absolute value), but that would only serve to define where the discontinuities occur, not eliminate them. For instance, imagine that we're writing a physics simulator and we run it on an object with a angular velocity around the x-axis. We would expect the x-angle to be a linear function of time, but if compute it by applying Ken's formulae to quaternions, we get a sawtooth function instead:
This problem is solved easily enough by taking the previous frame's Euler angles into account when converting each frame's orientation from a quaternion to Euler angles. After finding a triplet that corresponds to the given quaternion (which probably has angles in some nominal range like -π ... π), we can add or subtract some multiple of 2π to each angle so that it's as close to the previous values as possible. That'll restore our x-angle function to the linear shape that we'd expect it to have.
There's one more problem though, and this one's subtler. If you implement a rotation manipulator and you notice that 180-degree "flips" are creeping into your results, you'll realize there's another choice (like the ±2π one described above) that our conversion has to make. To understand this one, let's start by visualizing an example. Suppose we have an object that's rotated by 180 degrees around its z axis, and -90 degrees around its x axis (assuming ZXY rotation order). That object would be facing up, with its head towards us. Now suppose we took a different object and rotated it by -90 degrees around its x axis, and 180 degrees around its y axis. The second object would be in exactly the same position: facing up, with its head towards us. But these two sets of angles (-90,0,180 and -90,180,0) aren't merely different by multiples of 360 degrees... something else is going on. With a little bit more spatial visualization, we notice that it seems we can generalize it with the following relation:
Y(φ) X(θ) Z(ψ) = Y(π + φ) X(π - θ) Z(π + ψ)
where X, Y, and Z are rotation operators, and [θ, φ, ψ] is our ZXY Euler triplet. But if we're going to use this "180 degree identity", we need more than spatial intuition... we must show that it's really correct. We can do that by converting the rotation operators to quaternions, so that we have an algebra with which to manipulate them. Because we can express rotation θ around a unit vector a using the quaternion
q = (cos(θ/2), a sin(θ/2)),
our three rotation operators become
X(θ) = cos(θ/2) + i sin(θ/2)
Y(φ) = cos(φ/2) + j sin(φ/2)
Z(ψ) = cos(ψ/2) + k sin(ψ/2)
And the two sides of the 180-degree identity can be written
(cos(φ/2) + j sin(φ/2)) (cos(θ/2) + i sin(θ/2)) (cos(ψ/2) + k sin(ψ/2))
(-sin(φ/2) + j cos(φ/2)) (sin(θ/2) + i cos(θ/2)) (-cos(ψ/2) + k cos(ψ/2)).
If you multiply-out both of those expressions (keeping in mind that i2 = j2 = k2 = i j k = -1) then you'll find them equal. That's more algebra than I'm going to include in this article; I verified it using Mathematica and you should feel free to convince yourself, too. The point is that you can use this identity (in combination with the 360-degree property mentioned above) to convert quaternions to Euler angles gracefully, as follows:
Here's a summary of this technique, then. If you have a set of "reference" angles [θ, φ, ψ] and a quaternion q′ that you want to convert to "similar" angles [θ′, φ′, ψ′], then first convert the quaternion q′ to a triplet [θ0, φ0, ψ0]. Then add/subtract multiples of 360 degrees:
θ1 = θ0 + nθ1 2π
φ1 = φ0 + nφ1 2π
ψ1 = ψ0 + nψ1 2π
(where nθ1, nφ1, and nψ1 are integers) in order to minimize the distance from the reference angles,
δ1 = | θ1 - θ | + | φ1 - φ | + | ψ1 - ψ |,
do the same thing for the angles produced by the 180-degree identity:
θ2 = π + θ1 + nθ2 2π
φ2 = π - φ1 + nφ2 2π
ψ2 = π + ψ1 + nψ2 2π
δ2 = | θ2 - θ | + | φ2 - φ | + | ψ2 - ψ |,
and pick whichever triplet ([&theta1, &phi1, &psi1] or [&theta2, &phi2, &psi2]) is closer to the reference triplet.
By the way, if you're interested in this kind of thing, check out James Diebel's "quick reference guide". (Just kidding, it's anything but quick... it's exhaustive!). Also, Andrew J. Hanson is the biggest fan of quaternions that I've ever met and he has a book on visualizing them. I haven't read it, but if it's half as enthusiastic as his lectures then it's probably an insightful read.