Don Hatch (hatch++at++hell.engr.sgi.com)
Tue, 15 Sep 1998 11:11:13 -0700
I'm having a hard time following your version.
In the non-degenerate case, you set:
*xrot (i.e. pitch) = atan2f(mat[1][2], mat[2][2])
but this doesn't seem right, since mat[1][2] is sin(pitch)
and mat[2][2] is cos(roll)*cos(pitch).
So I'm lost right there...
It's true that Performer's algorithm is exceptionally stable
(it was substantially improved shortly after Performer 2.0).
Here is an explanation of the current algorithm...
============================================================================
Choose the roll first; then (effectively) factor out the roll from
the rest of the transformation by multiplying by the inverse of the
roll matrix on the left; this gives the heading/pitch matrix,
from which the pitch and heading are well-defined and well-behaved.
For reference, the composite matrix is:
[cr 0 -sr] [1 0 0 ] [ ch sh 0]
[0 1 0 ] * [0 cp sp] * [-sh ch 0]
[sr 0 cr] [0 -sp cp] [ 0 0 1]
[cr 0 -sr] [ ch sh 0 ]
= [0 1 0 ] * [-cp*sh cp*ch sp]
[sr 0 cr] [ sp*sh -sp*ch cp]
[(cr*ch - sr*sp*sh) (cr*sh + sr*sp*ch) -sr*cp]
= [ -cp*sh cp*ch sp]
[(sr*ch + cr*sp*sh) (sr*sh - cr*sp*ch) cr*cp]
The inverse of the roll matrix is:
[ cr 0 sr]
[ 0 1 0 ]
[-sr 0 cr]
Here is the code:
r = pfArcTan2(-mat[0][2], mat[2][2]);// returns 0 if both 0; that's fine
pfSinCos(r, &sr, &cr);
ch = cr*mat[0][0] + sr*mat[2][0];
sh = cr*mat[0][1] + sr*mat[2][1];
cp = cr*mat[2][2] - sr*mat[0][2];// guaranteed >=0 so pitch in [-90..90]
sp = mat[1][2];
h = pfArcTan2(sh, ch);
p = pfArcTan2(sp, cp);
The above 8 lines work fine in all cases, but they squander
2 trig functions and a bunch of arithmetic in the common case
that mat[0][2] == 0 (i.e. roll == 0 or 180, or pitch == +-90).
Adding a test for this case, the complete algorithm would be:
if (mat[0][2] == 0) // (roll == 0 or 180) or (pitch == +-90)
{
if (mat[2][2] >= 0)
{
r = 0; // cr == 1, sr == 0
ch = mat[0][0];
sh = mat[0][1];
cp = mat[2][2];
}
else
{
r = 180; // cr == -1, sr = 0
ch = -mat[0][0];
sh = -mat[0][1];
cp = -mat[2][2];
}
}
else
{
r = pfArcTan2(-mat[0][2], mat[2][2]);
pfSinCos(r, &sr, &cr);
ch = cr*mat[0][0] + sr*mat[2][0];
sh = cr*mat[0][1] + sr*mat[2][1];
cp = cr*mat[2][2] - sr*mat[0][2];
}
sp = mat[1][2];
h = pfArcTan2(sh, ch);
p = pfArcTan2(sp, cp);
==============================================================================
Don
-- Don Hatch hatch++at++sgi.com (650) 933-5150 Silicon Graphics, Inc.
This archive was generated by hypermail 2.0b2 on Tue Sep 15 1998 - 11:11:18 PDT