Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Quaternion to Euler (ZXY order)

877 views
Skip to first unread message

Dave

unread,
Jun 17, 2009, 1:54:01 PM6/17/09
to
Hi folks,

I am working on some code to convert a quaternion Q into euler angles.
I came across Paul Heckbert's section in Graphics Gems 4:

http://vered.rose.utoronto.ca/people/david_dir/GEMS/GEMS.html

The short of it is that his code should convert between any euler
angles representation to rotation matrices and quaternions.

However, I am confused as to how the output should come out. I wrote a
little test program to make sure it works:

// Create a quaternion rotation of 90 degrees about a diagonal
axis
Quat q = AxisAngle( Vector( 1, 1, 1 ), M_PI * 0.5 );

// Convert to ZXY euler angles with static frame of reference
int enc = EulOrdZXYs;
EulerAngles ea = Eul_FromQuat( q, enc );

// Generate quaternions for each indivudual axes
Quat qx = AxisAngle( Vector( 1, 0, 0 ), ea.x );
Quat qy = AxisAngle( Vector( 0, 1, 0 ), ea.y );
Quat qz = AxisAngle( Vector( 0, 0, 1 ), ea.z );

// Combine the individual rotations
const Quat qAct = qy * qx * qz;

// See how close the combined rotations are to the original
quaternion
const Quat qDiff = qAct.inverse() * q;

// Print out the variables and their values
cout << STREAM_VAR( q ) << endl;
cout << STREAM_VAR( ea ) << endl;
cout << STREAM_VAR( qx ) << endl;
cout << STREAM_VAR( qy ) << endl;
cout << STREAM_VAR( qz ) << endl;
cout << STREAM_VAR( qAct ) << endl;
cout << STREAM_VAR( qDiff ) << endl;
cout << STREAM_VAR( acos( qDiff.w ) * 180 / M_PI ) << endl;


I didn't include the AxisAngle function or the STREAM_VAR macro, but
basically the first one converts from an axis-angle representation to
a quaternion, and the second prints out a variable's name followed by
its value. I also didn't give the operator*(Quat,Quat) or Quat::inverse
() functions, but they are standard quaternion multiplication and
inversion methods. If you like, I'll post all that code.

The output I get is:

q (0.707107 0.408248 0.408248 0.408248)
ea (1.21992 0.246506 1.21992 16 )
qx (0.819672 0.572833 0 0)
qy (0.992414 0 0.122941 0)
qz (0.819672 0 0 0.572833)
qAct (0.707107 0.523699 -0.243049 0.408248)
qDiff (0.781241 0.184255 0.507669 -0.313024)
acos( qDiff.w ) * 180 / M_PI (38.6256)

So, the effect of combining the angles in ZXY order gives me a ~39
degree discrepancy between that combined rotation and the original
one.

However, if I change the order in which I combine the rotations to be
XYZ, like so:

const Quat qAct = qz * qy * qx;

I get the correct answer:

q (0.707107 0.408248 0.408248 0.408248)
ea (1.21992 0.246506 1.21992 16)
qx (0.819672 0.572833 0 0)
qy (0.992414 0 0.122941 0)
qz (0.819672 0 0 0.572833)
qAct (0.707107 0.408248 0.408248 0.408248)
qDiff (1 0 0 0)
acos( qDiff.w ) * 180 / M_PI (0)

So, what about this code am I not understanding? It seems to always
give me the rotation in XYZ order.

Thanks.

Dave

John Nagle

unread,
Jul 12, 2009, 11:28:37 AM7/12/09
to
Dave wrote:
> Hi folks,

> However, if I change the order in which I combine the rotations to be
> XYZ, like so:
>
> const Quat qAct = qz * qy * qx;
>
> I get the correct answer:

What does "*" mean in this context? Did you define multiplication
in C++ for quaternions? The code in Graphics Gems does not.

See "http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation"
for the theory of quaternion rotation.

John Nagle

Dave

unread,
Jul 14, 2009, 6:02:29 PM7/14/09
to


As I explained in the original post, I defined operator*(Quat,Quat)
and Quat::inverse() to be proper quaternion multiplication and
inversion code, but here is that code if you want to inspect it
yourself.

inline Quat operator*(const Quat &a, const Quat &b)
{
return Quat(a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z,
a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y,
a.w*b.y + a.y*b.w + a.z*b.x - a.x*b.z,
a.w*b.z + a.z*b.w + a.x*b.y - a.y*b.x);
}

inline Quat Quat::inverse() const
{
return Quat(w, -x, -y, -z);
}


As far as theory, I think I'm good on that, but if you see any holes
in my reasoning, by all means let me know. My thoughts were that, if I
decompose the quaternion into ZXY-order euler angles, then I can
reconstruct the original quaternion by rotating first about the Z
axis, then the X, then the Y. So, if qz, qx, and qy are quaternions
for those rotations, I should be able to get the original by
multiplying in the reverse order (like is done with rotation matrices
when operating on column vectors):

q == qy * qx * qz

Correct so far? So what else might I be missing? Am I using Shoemake's
code incorrectly, or am I making a mistake on my theory?

noel

unread,
Aug 5, 2009, 7:43:20 PM8/5/09
to

I have written a paper on converting a quaternion to Euler angles of
any rotation sequence. You can find it at noelhughes.net. There is a
typographic error in it that I recently became aware of. Let me know
if you find it.

Noel Hughes
noel.h...@gmail.com

0 new messages