6 @author Morgan McGuire, graphics3d.com
12 #include "G3D/platform.h"
13 #include "G3D/format.h"
16 #include "G3D/Matrix3.h"
17 #include "G3D/g3dmath.h"
22 const float Matrix3::EPSILON
= 1e-06f
;
24 const Matrix3
& Matrix3::zero() {
25 static Matrix3
m(0, 0, 0, 0, 0, 0, 0, 0, 0);
29 const Matrix3
& Matrix3::identity() {
30 static Matrix3
m(1, 0, 0, 0, 1, 0, 0, 0, 1);
35 const Matrix3
Matrix3::ZERO(0, 0, 0, 0, 0, 0, 0, 0, 0);
36 const Matrix3
Matrix3::IDENTITY(1, 0, 0, 0, 1, 0, 0, 0, 1);
38 const float Matrix3::ms_fSvdEpsilon
= 1e-04f
;
39 const int Matrix3::ms_iSvdMaxIterations
= 32;
41 bool Matrix3::fuzzyEq(const Matrix3
& b
) const {
42 for (int r
= 0; r
< 3; ++r
) {
43 for (int c
= 0; c
< 3; ++c
) {
44 if (! G3D::fuzzyEq(elt
[r
][c
], b
[r
][c
])) {
53 bool Matrix3::isOrthonormal() const {
54 Vector3 X
= getColumn(0);
55 Vector3 Y
= getColumn(1);
56 Vector3 Z
= getColumn(2);
59 (G3D::fuzzyEq(X
.dot(Y
), 0.0f
) &&
60 G3D::fuzzyEq(Y
.dot(Z
), 0.0f
) &&
61 G3D::fuzzyEq(X
.dot(Z
), 0.0f
) &&
62 G3D::fuzzyEq(X
.squaredMagnitude(), 1.0f
) &&
63 G3D::fuzzyEq(Y
.squaredMagnitude(), 1.0f
) &&
64 G3D::fuzzyEq(Z
.squaredMagnitude(), 1.0f
));
67 //----------------------------------------------------------------------------
68 Matrix3::Matrix3(const Quat
& _q
) {
69 // Implementation from Watt and Watt, pg 362
70 // See also http://www.flipcode.com/documents/matrfaq.html#Q54
71 Quat q
= _q
.unitize();
72 float xx
= 2.0f
* q
.x
* q
.x
;
73 float xy
= 2.0f
* q
.x
* q
.y
;
74 float xz
= 2.0f
* q
.x
* q
.z
;
75 float xw
= 2.0f
* q
.x
* q
.w
;
77 float yy
= 2.0f
* q
.y
* q
.y
;
78 float yz
= 2.0f
* q
.y
* q
.z
;
79 float yw
= 2.0f
* q
.y
* q
.w
;
81 float zz
= 2.0f
* q
.z
* q
.z
;
82 float zw
= 2.0f
* q
.z
* q
.w
;
84 set(1.0f
- yy
- zz
, xy
- zw
, xz
+ yw
,
85 xy
+ zw
, 1.0f
- xx
- zz
, yz
- xw
,
86 xz
- yw
, yz
+ xw
, 1.0f
- xx
- yy
);
89 //----------------------------------------------------------------------------
91 Matrix3::Matrix3 (const float aafEntry
[3][3]) {
92 memcpy(elt
, aafEntry
, 9*sizeof(float));
95 //----------------------------------------------------------------------------
96 Matrix3::Matrix3 (const Matrix3
& rkMatrix
) {
97 memcpy(elt
, rkMatrix
.elt
, 9*sizeof(float));
100 //----------------------------------------------------------------------------
102 float fEntry00
, float fEntry01
, float fEntry02
,
103 float fEntry10
, float fEntry11
, float fEntry12
,
104 float fEntry20
, float fEntry21
, float fEntry22
) {
105 set(fEntry00
, fEntry01
, fEntry02
,
106 fEntry10
, fEntry11
, fEntry12
,
107 fEntry20
, fEntry21
, fEntry22
);
111 float fEntry00
, float fEntry01
, float fEntry02
,
112 float fEntry10
, float fEntry11
, float fEntry12
,
113 float fEntry20
, float fEntry21
, float fEntry22
) {
115 elt
[0][0] = fEntry00
;
116 elt
[0][1] = fEntry01
;
117 elt
[0][2] = fEntry02
;
118 elt
[1][0] = fEntry10
;
119 elt
[1][1] = fEntry11
;
120 elt
[1][2] = fEntry12
;
121 elt
[2][0] = fEntry20
;
122 elt
[2][1] = fEntry21
;
123 elt
[2][2] = fEntry22
;
127 //----------------------------------------------------------------------------
128 Vector3
Matrix3::getColumn (int iCol
) const {
129 assert((0 <= iCol
) && (iCol
< 3));
130 return Vector3(elt
[0][iCol
], elt
[1][iCol
],
134 Vector3
Matrix3::getRow (int iRow
) const {
135 return Vector3(elt
[iRow
][0], elt
[iRow
][1], elt
[iRow
][2]);
138 void Matrix3::setColumn(int iCol
, const Vector3
&vector
) {
139 debugAssert((iCol
>= 0) && (iCol
< 3));
140 elt
[0][iCol
] = vector
.x
;
141 elt
[1][iCol
] = vector
.y
;
142 elt
[2][iCol
] = vector
.z
;
146 void Matrix3::setRow(int iRow
, const Vector3
&vector
) {
147 debugAssert((iRow
>= 0) && (iRow
< 3));
148 elt
[iRow
][0] = vector
.x
;
149 elt
[iRow
][1] = vector
.y
;
150 elt
[iRow
][2] = vector
.z
;
154 //----------------------------------------------------------------------------
155 bool Matrix3::operator== (const Matrix3
& rkMatrix
) const {
156 for (int iRow
= 0; iRow
< 3; iRow
++) {
157 for (int iCol
= 0; iCol
< 3; iCol
++) {
158 if ( elt
[iRow
][iCol
] != rkMatrix
.elt
[iRow
][iCol
] )
166 //----------------------------------------------------------------------------
167 bool Matrix3::operator!= (const Matrix3
& rkMatrix
) const {
168 return !operator==(rkMatrix
);
171 //----------------------------------------------------------------------------
172 Matrix3
Matrix3::operator+ (const Matrix3
& rkMatrix
) const {
175 for (int iRow
= 0; iRow
< 3; iRow
++) {
176 for (int iCol
= 0; iCol
< 3; iCol
++) {
177 kSum
.elt
[iRow
][iCol
] = elt
[iRow
][iCol
] +
178 rkMatrix
.elt
[iRow
][iCol
];
185 //----------------------------------------------------------------------------
186 Matrix3
Matrix3::operator- (const Matrix3
& rkMatrix
) const {
189 for (int iRow
= 0; iRow
< 3; iRow
++) {
190 for (int iCol
= 0; iCol
< 3; iCol
++) {
191 kDiff
.elt
[iRow
][iCol
] = elt
[iRow
][iCol
] -
192 rkMatrix
.elt
[iRow
][iCol
];
199 //----------------------------------------------------------------------------
200 Matrix3
Matrix3::operator* (const Matrix3
& rkMatrix
) const {
203 for (int iRow
= 0; iRow
< 3; iRow
++) {
204 for (int iCol
= 0; iCol
< 3; iCol
++) {
205 kProd
.elt
[iRow
][iCol
] =
206 elt
[iRow
][0] * rkMatrix
.elt
[0][iCol
] +
207 elt
[iRow
][1] * rkMatrix
.elt
[1][iCol
] +
208 elt
[iRow
][2] * rkMatrix
.elt
[2][iCol
];
215 Matrix3
& Matrix3::operator+= (const Matrix3
& rkMatrix
) {
216 for (int iRow
= 0; iRow
< 3; iRow
++) {
217 for (int iCol
= 0; iCol
< 3; iCol
++) {
218 elt
[iRow
][iCol
] = elt
[iRow
][iCol
] + rkMatrix
.elt
[iRow
][iCol
];
225 Matrix3
& Matrix3::operator-= (const Matrix3
& rkMatrix
) {
226 for (int iRow
= 0; iRow
< 3; iRow
++) {
227 for (int iCol
= 0; iCol
< 3; iCol
++) {
228 elt
[iRow
][iCol
] = elt
[iRow
][iCol
] - rkMatrix
.elt
[iRow
][iCol
];
235 Matrix3
& Matrix3::operator*= (const Matrix3
& rkMatrix
) {
237 for (int iRow
= 0; iRow
< 3; iRow
++) {
238 for (int iCol
= 0; iCol
< 3; iCol
++) {
239 mulMat
.elt
[iRow
][iCol
] =
240 elt
[iRow
][0] * rkMatrix
.elt
[0][iCol
] +
241 elt
[iRow
][1] * rkMatrix
.elt
[1][iCol
] +
242 elt
[iRow
][2] * rkMatrix
.elt
[2][iCol
];
250 //----------------------------------------------------------------------------
251 Matrix3
Matrix3::operator- () const {
254 for (int iRow
= 0; iRow
< 3; iRow
++) {
255 for (int iCol
= 0; iCol
< 3; iCol
++) {
256 kNeg
[iRow
][iCol
] = -elt
[iRow
][iCol
];
263 //----------------------------------------------------------------------------
264 Matrix3
Matrix3::operator* (float fScalar
) const {
267 for (int iRow
= 0; iRow
< 3; iRow
++) {
268 for (int iCol
= 0; iCol
< 3; iCol
++) {
269 kProd
[iRow
][iCol
] = fScalar
* elt
[iRow
][iCol
];
276 //----------------------------------------------------------------------------
277 Matrix3
operator* (double fScalar
, const Matrix3
& rkMatrix
) {
280 for (int iRow
= 0; iRow
< 3; iRow
++) {
281 for (int iCol
= 0; iCol
< 3; iCol
++) {
282 kProd
[iRow
][iCol
] = fScalar
* rkMatrix
.elt
[iRow
][iCol
];
289 Matrix3
operator* (float fScalar
, const Matrix3
& rkMatrix
) {
290 return (double)fScalar
* rkMatrix
;
294 Matrix3
operator* (int fScalar
, const Matrix3
& rkMatrix
) {
295 return (double)fScalar
* rkMatrix
;
297 //----------------------------------------------------------------------------
298 Matrix3
Matrix3::transpose () const {
301 for (int iRow
= 0; iRow
< 3; iRow
++) {
302 for (int iCol
= 0; iCol
< 3; iCol
++) {
303 kTranspose
[iRow
][iCol
] = elt
[iCol
][iRow
];
310 //----------------------------------------------------------------------------
311 bool Matrix3::inverse (Matrix3
& rkInverse
, float fTolerance
) const {
312 // Invert a 3x3 using cofactors. This is about 8 times faster than
313 // the Numerical Recipes code which uses Gaussian elimination.
315 rkInverse
[0][0] = elt
[1][1] * elt
[2][2] -
316 elt
[1][2] * elt
[2][1];
317 rkInverse
[0][1] = elt
[0][2] * elt
[2][1] -
318 elt
[0][1] * elt
[2][2];
319 rkInverse
[0][2] = elt
[0][1] * elt
[1][2] -
320 elt
[0][2] * elt
[1][1];
321 rkInverse
[1][0] = elt
[1][2] * elt
[2][0] -
322 elt
[1][0] * elt
[2][2];
323 rkInverse
[1][1] = elt
[0][0] * elt
[2][2] -
324 elt
[0][2] * elt
[2][0];
325 rkInverse
[1][2] = elt
[0][2] * elt
[1][0] -
326 elt
[0][0] * elt
[1][2];
327 rkInverse
[2][0] = elt
[1][0] * elt
[2][1] -
328 elt
[1][1] * elt
[2][0];
329 rkInverse
[2][1] = elt
[0][1] * elt
[2][0] -
330 elt
[0][0] * elt
[2][1];
331 rkInverse
[2][2] = elt
[0][0] * elt
[1][1] -
332 elt
[0][1] * elt
[1][0];
335 elt
[0][0] * rkInverse
[0][0] +
336 elt
[0][1] * rkInverse
[1][0] +
337 elt
[0][2] * rkInverse
[2][0];
339 if ( G3D::abs(fDet
) <= fTolerance
)
342 float fInvDet
= 1.0 / fDet
;
344 for (int iRow
= 0; iRow
< 3; iRow
++) {
345 for (int iCol
= 0; iCol
< 3; iCol
++)
346 rkInverse
[iRow
][iCol
] *= fInvDet
;
352 //----------------------------------------------------------------------------
353 Matrix3
Matrix3::inverse (float fTolerance
) const {
354 Matrix3 kInverse
= Matrix3::zero();
355 inverse(kInverse
, fTolerance
);
359 //----------------------------------------------------------------------------
360 float Matrix3::determinant () const {
361 float fCofactor00
= elt
[1][1] * elt
[2][2] -
362 elt
[1][2] * elt
[2][1];
363 float fCofactor10
= elt
[1][2] * elt
[2][0] -
364 elt
[1][0] * elt
[2][2];
365 float fCofactor20
= elt
[1][0] * elt
[2][1] -
366 elt
[1][1] * elt
[2][0];
369 elt
[0][0] * fCofactor00
+
370 elt
[0][1] * fCofactor10
+
371 elt
[0][2] * fCofactor20
;
376 //----------------------------------------------------------------------------
377 void Matrix3::bidiagonalize (Matrix3
& kA
, Matrix3
& kL
,
379 float afV
[3], afW
[3];
380 float fLength
, fSign
, fT1
, fInvT1
, fT2
;
383 // map first column to (*,0,0)
384 fLength
= sqrt(kA
[0][0] * kA
[0][0] + kA
[1][0] * kA
[1][0] +
385 kA
[2][0] * kA
[2][0]);
387 if ( fLength
> 0.0 ) {
388 fSign
= (kA
[0][0] > 0.0 ? 1.0 : -1.0);
389 fT1
= kA
[0][0] + fSign
* fLength
;
391 afV
[1] = kA
[1][0] * fInvT1
;
392 afV
[2] = kA
[2][0] * fInvT1
;
394 fT2
= -2.0 / (1.0 + afV
[1] * afV
[1] + afV
[2] * afV
[2]);
395 afW
[0] = fT2
* (kA
[0][0] + kA
[1][0] * afV
[1] + kA
[2][0] * afV
[2]);
396 afW
[1] = fT2
* (kA
[0][1] + kA
[1][1] * afV
[1] + kA
[2][1] * afV
[2]);
397 afW
[2] = fT2
* (kA
[0][2] + kA
[1][2] * afV
[1] + kA
[2][2] * afV
[2]);
401 kA
[1][1] += afV
[1] * afW
[1];
402 kA
[1][2] += afV
[1] * afW
[2];
403 kA
[2][1] += afV
[2] * afW
[1];
404 kA
[2][2] += afV
[2] * afW
[2];
406 kL
[0][0] = 1.0 + fT2
;
407 kL
[0][1] = kL
[1][0] = fT2
* afV
[1];
408 kL
[0][2] = kL
[2][0] = fT2
* afV
[2];
409 kL
[1][1] = 1.0 + fT2
* afV
[1] * afV
[1];
410 kL
[1][2] = kL
[2][1] = fT2
* afV
[1] * afV
[2];
411 kL
[2][2] = 1.0 + fT2
* afV
[2] * afV
[2];
414 kL
= Matrix3::identity();
418 // map first row to (*,*,0)
419 fLength
= sqrt(kA
[0][1] * kA
[0][1] + kA
[0][2] * kA
[0][2]);
421 if ( fLength
> 0.0 ) {
422 fSign
= (kA
[0][1] > 0.0 ? 1.0 : -1.0);
423 fT1
= kA
[0][1] + fSign
* fLength
;
424 afV
[2] = kA
[0][2] / fT1
;
426 fT2
= -2.0 / (1.0 + afV
[2] * afV
[2]);
427 afW
[0] = fT2
* (kA
[0][1] + kA
[0][2] * afV
[2]);
428 afW
[1] = fT2
* (kA
[1][1] + kA
[1][2] * afV
[2]);
429 afW
[2] = fT2
* (kA
[2][1] + kA
[2][2] * afV
[2]);
432 kA
[1][2] += afW
[1] * afV
[2];
434 kA
[2][2] += afW
[2] * afV
[2];
437 kR
[0][1] = kR
[1][0] = 0.0;
438 kR
[0][2] = kR
[2][0] = 0.0;
439 kR
[1][1] = 1.0 + fT2
;
440 kR
[1][2] = kR
[2][1] = fT2
* afV
[2];
441 kR
[2][2] = 1.0 + fT2
* afV
[2] * afV
[2];
443 kR
= Matrix3::identity();
446 // map second column to (*,*,0)
447 fLength
= sqrt(kA
[1][1] * kA
[1][1] + kA
[2][1] * kA
[2][1]);
449 if ( fLength
> 0.0 ) {
450 fSign
= (kA
[1][1] > 0.0 ? 1.0 : -1.0);
451 fT1
= kA
[1][1] + fSign
* fLength
;
452 afV
[2] = kA
[2][1] / fT1
;
454 fT2
= -2.0 / (1.0 + afV
[2] * afV
[2]);
455 afW
[1] = fT2
* (kA
[1][1] + kA
[2][1] * afV
[2]);
456 afW
[2] = fT2
* (kA
[1][2] + kA
[2][2] * afV
[2]);
459 kA
[2][2] += afV
[2] * afW
[2];
461 float fA
= 1.0 + fT2
;
462 float fB
= fT2
* afV
[2];
463 float fC
= 1.0 + fB
* afV
[2];
467 kL
[0][1] = kL
[1][0] = 0.0;
468 kL
[0][2] = kL
[2][0] = 0.0;
470 kL
[1][2] = kL
[2][1] = fB
;
473 for (int iRow
= 0; iRow
< 3; iRow
++) {
474 float fTmp0
= kL
[iRow
][1];
475 float fTmp1
= kL
[iRow
][2];
476 kL
[iRow
][1] = fA
* fTmp0
+ fB
* fTmp1
;
477 kL
[iRow
][2] = fB
* fTmp0
+ fC
* fTmp1
;
483 //----------------------------------------------------------------------------
484 void Matrix3::golubKahanStep (Matrix3
& kA
, Matrix3
& kL
,
486 float fT11
= kA
[0][1] * kA
[0][1] + kA
[1][1] * kA
[1][1];
487 float fT22
= kA
[1][2] * kA
[1][2] + kA
[2][2] * kA
[2][2];
488 float fT12
= kA
[1][1] * kA
[1][2];
489 float fTrace
= fT11
+ fT22
;
490 float fDiff
= fT11
- fT22
;
491 float fDiscr
= sqrt(fDiff
* fDiff
+ 4.0 * fT12
* fT12
);
492 float fRoot1
= 0.5 * (fTrace
+ fDiscr
);
493 float fRoot2
= 0.5 * (fTrace
- fDiscr
);
496 float fY
= kA
[0][0] - (G3D::abs(fRoot1
- fT22
) <=
497 G3D::abs(fRoot2
- fT22
) ? fRoot1
: fRoot2
);
499 float fInvLength
= 1.0 / sqrt(fY
* fY
+ fZ
* fZ
);
500 float fSin
= fZ
* fInvLength
;
501 float fCos
= -fY
* fInvLength
;
503 float fTmp0
= kA
[0][0];
504 float fTmp1
= kA
[0][1];
505 kA
[0][0] = fCos
* fTmp0
- fSin
* fTmp1
;
506 kA
[0][1] = fSin
* fTmp0
+ fCos
* fTmp1
;
507 kA
[1][0] = -fSin
* kA
[1][1];
512 for (iRow
= 0; iRow
< 3; iRow
++) {
515 kR
[0][iRow
] = fCos
* fTmp0
- fSin
* fTmp1
;
516 kR
[1][iRow
] = fSin
* fTmp0
+ fCos
* fTmp1
;
524 fInvLength
= 1.0 / sqrt(fY
* fY
+ fZ
* fZ
);
526 fSin
= fZ
* fInvLength
;
528 fCos
= -fY
* fInvLength
;
530 kA
[0][0] = fCos
* kA
[0][0] - fSin
* kA
[1][0];
536 kA
[0][1] = fCos
* fTmp0
- fSin
* fTmp1
;
538 kA
[1][1] = fSin
* fTmp0
+ fCos
* fTmp1
;
540 kA
[0][2] = -fSin
* kA
[1][2];
546 for (iCol
= 0; iCol
< 3; iCol
++) {
549 kL
[iCol
][0] = fCos
* fTmp0
- fSin
* fTmp1
;
550 kL
[iCol
][1] = fSin
* fTmp0
+ fCos
* fTmp1
;
558 fInvLength
= 1.0 / sqrt(fY
* fY
+ fZ
* fZ
);
560 fSin
= fZ
* fInvLength
;
562 fCos
= -fY
* fInvLength
;
564 kA
[0][1] = fCos
* kA
[0][1] - fSin
* kA
[0][2];
570 kA
[1][1] = fCos
* fTmp0
- fSin
* fTmp1
;
572 kA
[1][2] = fSin
* fTmp0
+ fCos
* fTmp1
;
574 kA
[2][1] = -fSin
* kA
[2][2];
578 for (iRow
= 0; iRow
< 3; iRow
++) {
581 kR
[1][iRow
] = fCos
* fTmp0
- fSin
* fTmp1
;
582 kR
[2][iRow
] = fSin
* fTmp0
+ fCos
* fTmp1
;
590 fInvLength
= 1.0 / sqrt(fY
* fY
+ fZ
* fZ
);
592 fSin
= fZ
* fInvLength
;
594 fCos
= -fY
* fInvLength
;
596 kA
[1][1] = fCos
* kA
[1][1] - fSin
* kA
[2][1];
602 kA
[1][2] = fCos
* fTmp0
- fSin
* fTmp1
;
604 kA
[2][2] = fSin
* fTmp0
+ fCos
* fTmp1
;
606 for (iCol
= 0; iCol
< 3; iCol
++) {
609 kL
[iCol
][1] = fCos
* fTmp0
- fSin
* fTmp1
;
610 kL
[iCol
][2] = fSin
* fTmp0
+ fCos
* fTmp1
;
614 //----------------------------------------------------------------------------
615 void Matrix3::singularValueDecomposition (Matrix3
& kL
, Vector3
& kS
,
620 bidiagonalize(kA
, kL
, kR
);
622 for (int i
= 0; i
< ms_iSvdMaxIterations
; i
++) {
623 float fTmp
, fTmp0
, fTmp1
;
624 float fSin0
, fCos0
, fTan0
;
625 float fSin1
, fCos1
, fTan1
;
627 bool bTest1
= (G3D::abs(kA
[0][1]) <=
628 ms_fSvdEpsilon
* (G3D::abs(kA
[0][0]) + G3D::abs(kA
[1][1])));
629 bool bTest2
= (G3D::abs(kA
[1][2]) <=
630 ms_fSvdEpsilon
* (G3D::abs(kA
[1][1]) + G3D::abs(kA
[2][2])));
639 // 2x2 closed form factorization
640 fTmp
= (kA
[1][1] * kA
[1][1] - kA
[2][2] * kA
[2][2] +
641 kA
[1][2] * kA
[1][2]) / (kA
[1][2] * kA
[2][2]);
642 fTan0
= 0.5 * (fTmp
+ sqrt(fTmp
* fTmp
+ 4.0));
643 fCos0
= 1.0 / sqrt(1.0 + fTan0
* fTan0
);
644 fSin0
= fTan0
* fCos0
;
646 for (iCol
= 0; iCol
< 3; iCol
++) {
649 kL
[iCol
][1] = fCos0
* fTmp0
- fSin0
* fTmp1
;
650 kL
[iCol
][2] = fSin0
* fTmp0
+ fCos0
* fTmp1
;
653 fTan1
= (kA
[1][2] - kA
[2][2] * fTan0
) / kA
[1][1];
654 fCos1
= 1.0 / sqrt(1.0 + fTan1
* fTan1
);
655 fSin1
= -fTan1
* fCos1
;
657 for (iRow
= 0; iRow
< 3; iRow
++) {
660 kR
[1][iRow
] = fCos1
* fTmp0
- fSin1
* fTmp1
;
661 kR
[2][iRow
] = fSin1
* fTmp0
+ fCos1
* fTmp1
;
665 kS
[1] = fCos0
* fCos1
* kA
[1][1] -
666 fSin1
* (fCos0
* kA
[1][2] - fSin0
* kA
[2][2]);
667 kS
[2] = fSin0
* fSin1
* kA
[1][1] +
668 fCos1
* (fSin0
* kA
[1][2] + fCos0
* kA
[2][2]);
673 // 2x2 closed form factorization
674 fTmp
= (kA
[0][0] * kA
[0][0] + kA
[1][1] * kA
[1][1] -
675 kA
[0][1] * kA
[0][1]) / (kA
[0][1] * kA
[1][1]);
676 fTan0
= 0.5 * ( -fTmp
+ sqrt(fTmp
* fTmp
+ 4.0));
677 fCos0
= 1.0 / sqrt(1.0 + fTan0
* fTan0
);
678 fSin0
= fTan0
* fCos0
;
680 for (iCol
= 0; iCol
< 3; iCol
++) {
683 kL
[iCol
][0] = fCos0
* fTmp0
- fSin0
* fTmp1
;
684 kL
[iCol
][1] = fSin0
* fTmp0
+ fCos0
* fTmp1
;
687 fTan1
= (kA
[0][1] - kA
[1][1] * fTan0
) / kA
[0][0];
688 fCos1
= 1.0 / sqrt(1.0 + fTan1
* fTan1
);
689 fSin1
= -fTan1
* fCos1
;
691 for (iRow
= 0; iRow
< 3; iRow
++) {
694 kR
[0][iRow
] = fCos1
* fTmp0
- fSin1
* fTmp1
;
695 kR
[1][iRow
] = fSin1
* fTmp0
+ fCos1
* fTmp1
;
698 kS
[0] = fCos0
* fCos1
* kA
[0][0] -
699 fSin1
* (fCos0
* kA
[0][1] - fSin0
* kA
[1][1]);
700 kS
[1] = fSin0
* fSin1
* kA
[0][0] +
701 fCos1
* (fSin0
* kA
[0][1] + fCos0
* kA
[1][1]);
705 golubKahanStep(kA
, kL
, kR
);
711 for (iRow
= 0; iRow
< 3; iRow
++) {
712 if ( kS
[iRow
] < 0.0 ) {
713 kS
[iRow
] = -kS
[iRow
];
715 for (iCol
= 0; iCol
< 3; iCol
++)
716 kR
[iRow
][iCol
] = -kR
[iRow
][iCol
];
721 //----------------------------------------------------------------------------
722 void Matrix3::singularValueComposition (const Matrix3
& kL
,
723 const Vector3
& kS
, const Matrix3
& kR
) {
728 for (iRow
= 0; iRow
< 3; iRow
++) {
729 for (iCol
= 0; iCol
< 3; iCol
++)
730 kTmp
[iRow
][iCol
] = kS
[iRow
] * kR
[iRow
][iCol
];
734 for (iRow
= 0; iRow
< 3; iRow
++) {
735 for (iCol
= 0; iCol
< 3; iCol
++) {
736 elt
[iRow
][iCol
] = 0.0;
738 for (int iMid
= 0; iMid
< 3; iMid
++)
739 elt
[iRow
][iCol
] += kL
[iRow
][iMid
] * kTmp
[iMid
][iCol
];
744 //----------------------------------------------------------------------------
745 void Matrix3::orthonormalize () {
746 // Algorithm uses Gram-Schmidt orthogonalization. If 'this' matrix is
747 // M = [m0|m1|m2], then orthonormal output matrix is Q = [q0|q1|q2],
750 // q1 = (m1-(q0*m1)q0)/|m1-(q0*m1)q0|
751 // q2 = (m2-(q0*m2)q0-(q1*m2)q1)/|m2-(q0*m2)q0-(q1*m2)q1|
753 // where |V| indicates length of vector V and A*B indicates dot
754 // product of vectors A and B.
757 float fInvLength
= 1.0 / sqrt(elt
[0][0] * elt
[0][0]
758 + elt
[1][0] * elt
[1][0] +
759 elt
[2][0] * elt
[2][0]);
761 elt
[0][0] *= fInvLength
;
762 elt
[1][0] *= fInvLength
;
763 elt
[2][0] *= fInvLength
;
767 elt
[0][0] * elt
[0][1] +
768 elt
[1][0] * elt
[1][1] +
769 elt
[2][0] * elt
[2][1];
771 elt
[0][1] -= fDot0
* elt
[0][0];
772 elt
[1][1] -= fDot0
* elt
[1][0];
773 elt
[2][1] -= fDot0
* elt
[2][0];
775 fInvLength
= 1.0 / sqrt(elt
[0][1] * elt
[0][1] +
776 elt
[1][1] * elt
[1][1] +
777 elt
[2][1] * elt
[2][1]);
779 elt
[0][1] *= fInvLength
;
780 elt
[1][1] *= fInvLength
;
781 elt
[2][1] *= fInvLength
;
785 elt
[0][1] * elt
[0][2] +
786 elt
[1][1] * elt
[1][2] +
787 elt
[2][1] * elt
[2][2];
790 elt
[0][0] * elt
[0][2] +
791 elt
[1][0] * elt
[1][2] +
792 elt
[2][0] * elt
[2][2];
794 elt
[0][2] -= fDot0
* elt
[0][0] + fDot1
* elt
[0][1];
795 elt
[1][2] -= fDot0
* elt
[1][0] + fDot1
* elt
[1][1];
796 elt
[2][2] -= fDot0
* elt
[2][0] + fDot1
* elt
[2][1];
798 fInvLength
= 1.0 / sqrt(elt
[0][2] * elt
[0][2] +
799 elt
[1][2] * elt
[1][2] +
800 elt
[2][2] * elt
[2][2]);
802 elt
[0][2] *= fInvLength
;
803 elt
[1][2] *= fInvLength
;
804 elt
[2][2] *= fInvLength
;
807 //----------------------------------------------------------------------------
808 void Matrix3::qDUDecomposition (Matrix3
& kQ
,
809 Vector3
& kD
, Vector3
& kU
) const {
810 // Factor M = QR = QDU where Q is orthogonal, D is diagonal,
811 // and U is upper triangular with ones on its diagonal. Algorithm uses
812 // Gram-Schmidt orthogonalization (the QR algorithm).
814 // If M = [ m0 | m1 | m2 ] and Q = [ q0 | q1 | q2 ], then
817 // q1 = (m1-(q0*m1)q0)/|m1-(q0*m1)q0|
818 // q2 = (m2-(q0*m2)q0-(q1*m2)q1)/|m2-(q0*m2)q0-(q1*m2)q1|
820 // where |V| indicates length of vector V and A*B indicates dot
821 // product of vectors A and B. The matrix R has entries
823 // r00 = q0*m0 r01 = q0*m1 r02 = q0*m2
824 // r10 = 0 r11 = q1*m1 r12 = q1*m2
825 // r20 = 0 r21 = 0 r22 = q2*m2
827 // so D = diag(r00,r11,r22) and U has entries u01 = r01/r00,
828 // u02 = r02/r00, and u12 = r12/r11.
834 // D stores the three diagonal entries r00, r11, r22
835 // U stores the entries U[0] = u01, U[1] = u02, U[2] = u12
837 // build orthogonal matrix Q
838 float fInvLength
= 1.0 / sqrt(elt
[0][0] * elt
[0][0]
839 + elt
[1][0] * elt
[1][0] +
840 elt
[2][0] * elt
[2][0]);
841 kQ
[0][0] = elt
[0][0] * fInvLength
;
842 kQ
[1][0] = elt
[1][0] * fInvLength
;
843 kQ
[2][0] = elt
[2][0] * fInvLength
;
845 float fDot
= kQ
[0][0] * elt
[0][1] + kQ
[1][0] * elt
[1][1] +
846 kQ
[2][0] * elt
[2][1];
847 kQ
[0][1] = elt
[0][1] - fDot
* kQ
[0][0];
848 kQ
[1][1] = elt
[1][1] - fDot
* kQ
[1][0];
849 kQ
[2][1] = elt
[2][1] - fDot
* kQ
[2][0];
850 fInvLength
= 1.0 / sqrt(kQ
[0][1] * kQ
[0][1] + kQ
[1][1] * kQ
[1][1] +
851 kQ
[2][1] * kQ
[2][1]);
852 kQ
[0][1] *= fInvLength
;
853 kQ
[1][1] *= fInvLength
;
854 kQ
[2][1] *= fInvLength
;
856 fDot
= kQ
[0][0] * elt
[0][2] + kQ
[1][0] * elt
[1][2] +
857 kQ
[2][0] * elt
[2][2];
858 kQ
[0][2] = elt
[0][2] - fDot
* kQ
[0][0];
859 kQ
[1][2] = elt
[1][2] - fDot
* kQ
[1][0];
860 kQ
[2][2] = elt
[2][2] - fDot
* kQ
[2][0];
861 fDot
= kQ
[0][1] * elt
[0][2] + kQ
[1][1] * elt
[1][2] +
862 kQ
[2][1] * elt
[2][2];
863 kQ
[0][2] -= fDot
* kQ
[0][1];
864 kQ
[1][2] -= fDot
* kQ
[1][1];
865 kQ
[2][2] -= fDot
* kQ
[2][1];
866 fInvLength
= 1.0 / sqrt(kQ
[0][2] * kQ
[0][2] + kQ
[1][2] * kQ
[1][2] +
867 kQ
[2][2] * kQ
[2][2]);
868 kQ
[0][2] *= fInvLength
;
869 kQ
[1][2] *= fInvLength
;
870 kQ
[2][2] *= fInvLength
;
872 // guarantee that orthogonal matrix has determinant 1 (no reflections)
873 float fDet
= kQ
[0][0] * kQ
[1][1] * kQ
[2][2] + kQ
[0][1] * kQ
[1][2] * kQ
[2][0] +
874 kQ
[0][2] * kQ
[1][0] * kQ
[2][1] - kQ
[0][2] * kQ
[1][1] * kQ
[2][0] -
875 kQ
[0][1] * kQ
[1][0] * kQ
[2][2] - kQ
[0][0] * kQ
[1][2] * kQ
[2][1];
878 for (int iRow
= 0; iRow
< 3; iRow
++)
879 for (int iCol
= 0; iCol
< 3; iCol
++)
880 kQ
[iRow
][iCol
] = -kQ
[iRow
][iCol
];
883 // build "right" matrix R
886 kR
[0][0] = kQ
[0][0] * elt
[0][0] + kQ
[1][0] * elt
[1][0] +
887 kQ
[2][0] * elt
[2][0];
889 kR
[0][1] = kQ
[0][0] * elt
[0][1] + kQ
[1][0] * elt
[1][1] +
890 kQ
[2][0] * elt
[2][1];
892 kR
[1][1] = kQ
[0][1] * elt
[0][1] + kQ
[1][1] * elt
[1][1] +
893 kQ
[2][1] * elt
[2][1];
895 kR
[0][2] = kQ
[0][0] * elt
[0][2] + kQ
[1][0] * elt
[1][2] +
896 kQ
[2][0] * elt
[2][2];
898 kR
[1][2] = kQ
[0][1] * elt
[0][2] + kQ
[1][1] * elt
[1][2] +
899 kQ
[2][1] * elt
[2][2];
901 kR
[2][2] = kQ
[0][2] * elt
[0][2] + kQ
[1][2] * elt
[1][2] +
902 kQ
[2][2] * elt
[2][2];
904 // the scaling component
911 // the shear component
912 float fInvD0
= 1.0 / kD
[0];
914 kU
[0] = kR
[0][1] * fInvD0
;
916 kU
[1] = kR
[0][2] * fInvD0
;
918 kU
[2] = kR
[1][2] / kD
[1];
921 //----------------------------------------------------------------------------
922 float Matrix3::maxCubicRoot (float afCoeff
[3]) {
923 // Spectral norm is for A^T*A, so characteristic polynomial
924 // P(x) = c[0]+c[1]*x+c[2]*x^2+x^3 has three positive float roots.
925 // This yields the assertions c[0] < 0 and c[2]*c[2] >= 3*c[1].
927 // quick out for uniform scale (triple root)
928 const float fOneThird
= 1.0f
/ 3.0f
;
929 const float fEpsilon
= 1e-06f
;
930 float fDiscr
= afCoeff
[2] * afCoeff
[2] - 3.0f
* afCoeff
[1];
932 if ( fDiscr
<= fEpsilon
)
933 return -fOneThird
*afCoeff
[2];
935 // Compute an upper bound on roots of P(x). This assumes that A^T*A
936 // has been scaled by its largest entry.
939 float fPoly
= afCoeff
[0] + fX
* (afCoeff
[1] + fX
* (afCoeff
[2] + fX
));
941 if ( fPoly
< 0.0f
) {
942 // uses a matrix norm to find an upper bound on maximum root
943 fX
= G3D::abs(afCoeff
[0]);
944 float fTmp
= 1.0 + G3D::abs(afCoeff
[1]);
949 fTmp
= 1.0 + G3D::abs(afCoeff
[2]);
955 // Newton's method to find root
956 float fTwoC2
= 2.0f
* afCoeff
[2];
958 for (int i
= 0; i
< 16; i
++) {
959 fPoly
= afCoeff
[0] + fX
* (afCoeff
[1] + fX
* (afCoeff
[2] + fX
));
961 if ( G3D::abs(fPoly
) <= fEpsilon
)
964 float fDeriv
= afCoeff
[1] + fX
* (fTwoC2
+ 3.0f
* fX
);
966 fX
-= fPoly
/ fDeriv
;
972 //----------------------------------------------------------------------------
973 float Matrix3::spectralNorm () const {
978 for (iRow
= 0; iRow
< 3; iRow
++) {
979 for (iCol
= 0; iCol
< 3; iCol
++) {
980 kP
[iRow
][iCol
] = 0.0;
982 for (int iMid
= 0; iMid
< 3; iMid
++) {
984 elt
[iMid
][iRow
] * elt
[iMid
][iCol
];
987 if ( kP
[iRow
][iCol
] > fPmax
)
988 fPmax
= kP
[iRow
][iCol
];
992 float fInvPmax
= 1.0 / fPmax
;
994 for (iRow
= 0; iRow
< 3; iRow
++) {
995 for (iCol
= 0; iCol
< 3; iCol
++)
996 kP
[iRow
][iCol
] *= fInvPmax
;
1000 afCoeff
[0] = -(kP
[0][0] * (kP
[1][1] * kP
[2][2] - kP
[1][2] * kP
[2][1]) +
1001 kP
[0][1] * (kP
[2][0] * kP
[1][2] - kP
[1][0] * kP
[2][2]) +
1002 kP
[0][2] * (kP
[1][0] * kP
[2][1] - kP
[2][0] * kP
[1][1]));
1003 afCoeff
[1] = kP
[0][0] * kP
[1][1] - kP
[0][1] * kP
[1][0] +
1004 kP
[0][0] * kP
[2][2] - kP
[0][2] * kP
[2][0] +
1005 kP
[1][1] * kP
[2][2] - kP
[1][2] * kP
[2][1];
1006 afCoeff
[2] = -(kP
[0][0] + kP
[1][1] + kP
[2][2]);
1008 float fRoot
= maxCubicRoot(afCoeff
);
1009 float fNorm
= sqrt(fPmax
* fRoot
);
1013 //----------------------------------------------------------------------------
1014 void Matrix3::toAxisAngle (Vector3
& rkAxis
, float& rfRadians
) const {
1015 // Let (x,y,z) be the unit-length axis and let A be an angle of rotation.
1016 // The rotation matrix is R = I + sin(A)*P + (1-cos(A))*P^2 where
1017 // I is the identity and
1025 // If A > 0, R represents a counterclockwise rotation about the axis in
1026 // the sense of looking from the tip of the axis vector towards the
1027 // origin. Some algebra will show that
1029 // cos(A) = (trace(R)-1)/2 and R - R^t = 2*sin(A)*P
1031 // In the event that A = pi, R-R^t = 0 which prevents us from extracting
1032 // the axis through P. Instead note that R = I+2*P^2 when A = pi, so
1033 // P^2 = (R-I)/2. The diagonal entries of P^2 are x^2-1, y^2-1, and
1034 // z^2-1. We can solve these for axis (x,y,z). Because the angle is pi,
1035 // it does not matter which sign you choose on the square roots.
1037 float fTrace
= elt
[0][0] + elt
[1][1] + elt
[2][2];
1038 float fCos
= 0.5 * (fTrace
- 1.0);
1039 rfRadians
= G3D::aCos(fCos
); // in [0,PI]
1041 if ( rfRadians
> 0.0 ) {
1042 if ( rfRadians
< G3D_PI
) {
1043 rkAxis
.x
= elt
[2][1] - elt
[1][2];
1044 rkAxis
.y
= elt
[0][2] - elt
[2][0];
1045 rkAxis
.z
= elt
[1][0] - elt
[0][1];
1051 if ( elt
[0][0] >= elt
[1][1] ) {
1053 if ( elt
[0][0] >= elt
[2][2] ) {
1054 // r00 is maximum diagonal term
1055 rkAxis
.x
= 0.5 * sqrt(elt
[0][0] -
1056 elt
[1][1] - elt
[2][2] + 1.0);
1057 fHalfInverse
= 0.5 / rkAxis
.x
;
1058 rkAxis
.y
= fHalfInverse
* elt
[0][1];
1059 rkAxis
.z
= fHalfInverse
* elt
[0][2];
1061 // r22 is maximum diagonal term
1062 rkAxis
.z
= 0.5 * sqrt(elt
[2][2] -
1063 elt
[0][0] - elt
[1][1] + 1.0);
1064 fHalfInverse
= 0.5 / rkAxis
.z
;
1065 rkAxis
.x
= fHalfInverse
* elt
[0][2];
1066 rkAxis
.y
= fHalfInverse
* elt
[1][2];
1070 if ( elt
[1][1] >= elt
[2][2] ) {
1071 // r11 is maximum diagonal term
1072 rkAxis
.y
= 0.5 * sqrt(elt
[1][1] -
1073 elt
[0][0] - elt
[2][2] + 1.0);
1074 fHalfInverse
= 0.5 / rkAxis
.y
;
1075 rkAxis
.x
= fHalfInverse
* elt
[0][1];
1076 rkAxis
.z
= fHalfInverse
* elt
[1][2];
1078 // r22 is maximum diagonal term
1079 rkAxis
.z
= 0.5 * sqrt(elt
[2][2] -
1080 elt
[0][0] - elt
[1][1] + 1.0);
1081 fHalfInverse
= 0.5 / rkAxis
.z
;
1082 rkAxis
.x
= fHalfInverse
* elt
[0][2];
1083 rkAxis
.y
= fHalfInverse
* elt
[1][2];
1088 // The angle is 0 and the matrix is the identity. Any axis will
1089 // work, so just use the x-axis.
1096 //----------------------------------------------------------------------------
1097 Matrix3
Matrix3::fromAxisAngle (const Vector3
& rkAxis
, float fRadians
) {
1100 float fCos
= cos(fRadians
);
1101 float fSin
= sin(fRadians
);
1102 float fOneMinusCos
= 1.0 - fCos
;
1103 float fX2
= rkAxis
.x
* rkAxis
.x
;
1104 float fY2
= rkAxis
.y
* rkAxis
.y
;
1105 float fZ2
= rkAxis
.z
* rkAxis
.z
;
1106 float fXYM
= rkAxis
.x
* rkAxis
.y
* fOneMinusCos
;
1107 float fXZM
= rkAxis
.x
* rkAxis
.z
* fOneMinusCos
;
1108 float fYZM
= rkAxis
.y
* rkAxis
.z
* fOneMinusCos
;
1109 float fXSin
= rkAxis
.x
* fSin
;
1110 float fYSin
= rkAxis
.y
* fSin
;
1111 float fZSin
= rkAxis
.z
* fSin
;
1113 m
.elt
[0][0] = fX2
* fOneMinusCos
+ fCos
;
1114 m
.elt
[0][1] = fXYM
- fZSin
;
1115 m
.elt
[0][2] = fXZM
+ fYSin
;
1116 m
.elt
[1][0] = fXYM
+ fZSin
;
1117 m
.elt
[1][1] = fY2
* fOneMinusCos
+ fCos
;
1118 m
.elt
[1][2] = fYZM
- fXSin
;
1119 m
.elt
[2][0] = fXZM
- fYSin
;
1120 m
.elt
[2][1] = fYZM
+ fXSin
;
1121 m
.elt
[2][2] = fZ2
* fOneMinusCos
+ fCos
;
1126 //----------------------------------------------------------------------------
1127 bool Matrix3::toEulerAnglesXYZ (float& rfXAngle
, float& rfYAngle
,
1128 float& rfZAngle
) const {
1129 // rot = cy*cz -cy*sz sy
1130 // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
1131 // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
1133 if ( elt
[0][2] < 1.0f
) {
1134 if ( elt
[0][2] > -1.0f
) {
1135 rfXAngle
= G3D::aTan2( -elt
[1][2], elt
[2][2]);
1136 rfYAngle
= (float) G3D::aSin(elt
[0][2]);
1137 rfZAngle
= G3D::aTan2( -elt
[0][1], elt
[0][0]);
1140 // WARNING. Not unique. XA - ZA = -atan2(r10,r11)
1141 rfXAngle
= -G3D::aTan2(elt
[1][0], elt
[1][1]);
1142 rfYAngle
= -(float)G3D_HALF_PI
;
1147 // WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11)
1148 rfXAngle
= G3D::aTan2(elt
[1][0], elt
[1][1]);
1149 rfYAngle
= (float)G3D_HALF_PI
;
1155 //----------------------------------------------------------------------------
1156 bool Matrix3::toEulerAnglesXZY (float& rfXAngle
, float& rfZAngle
,
1157 float& rfYAngle
) const {
1158 // rot = cy*cz -sz cz*sy
1159 // sx*sy+cx*cy*sz cx*cz -cy*sx+cx*sy*sz
1160 // -cx*sy+cy*sx*sz cz*sx cx*cy+sx*sy*sz
1162 if ( elt
[0][1] < 1.0f
) {
1163 if ( elt
[0][1] > -1.0f
) {
1164 rfXAngle
= G3D::aTan2(elt
[2][1], elt
[1][1]);
1165 rfZAngle
= (float) asin( -elt
[0][1]);
1166 rfYAngle
= G3D::aTan2(elt
[0][2], elt
[0][0]);
1169 // WARNING. Not unique. XA - YA = atan2(r20,r22)
1170 rfXAngle
= G3D::aTan2(elt
[2][0], elt
[2][2]);
1171 rfZAngle
= (float)G3D_HALF_PI
;
1176 // WARNING. Not unique. XA + YA = atan2(-r20,r22)
1177 rfXAngle
= G3D::aTan2( -elt
[2][0], elt
[2][2]);
1178 rfZAngle
= -(float)G3D_HALF_PI
;
1184 //----------------------------------------------------------------------------
1185 bool Matrix3::toEulerAnglesYXZ (float& rfYAngle
, float& rfXAngle
,
1186 float& rfZAngle
) const {
1187 // rot = cy*cz+sx*sy*sz cz*sx*sy-cy*sz cx*sy
1189 // -cz*sy+cy*sx*sz cy*cz*sx+sy*sz cx*cy
1191 if ( elt
[1][2] < 1.0 ) {
1192 if ( elt
[1][2] > -1.0 ) {
1193 rfYAngle
= G3D::aTan2(elt
[0][2], elt
[2][2]);
1194 rfXAngle
= (float) asin( -elt
[1][2]);
1195 rfZAngle
= G3D::aTan2(elt
[1][0], elt
[1][1]);
1198 // WARNING. Not unique. YA - ZA = atan2(r01,r00)
1199 rfYAngle
= G3D::aTan2(elt
[0][1], elt
[0][0]);
1200 rfXAngle
= (float)G3D_HALF_PI
;
1205 // WARNING. Not unique. YA + ZA = atan2(-r01,r00)
1206 rfYAngle
= G3D::aTan2( -elt
[0][1], elt
[0][0]);
1207 rfXAngle
= -(float)G3D_HALF_PI
;
1213 //----------------------------------------------------------------------------
1214 bool Matrix3::toEulerAnglesYZX (float& rfYAngle
, float& rfZAngle
,
1215 float& rfXAngle
) const {
1216 // rot = cy*cz sx*sy-cx*cy*sz cx*sy+cy*sx*sz
1218 // -cz*sy cy*sx+cx*sy*sz cx*cy-sx*sy*sz
1220 if ( elt
[1][0] < 1.0 ) {
1221 if ( elt
[1][0] > -1.0 ) {
1222 rfYAngle
= G3D::aTan2( -elt
[2][0], elt
[0][0]);
1223 rfZAngle
= (float) asin(elt
[1][0]);
1224 rfXAngle
= G3D::aTan2( -elt
[1][2], elt
[1][1]);
1227 // WARNING. Not unique. YA - XA = -atan2(r21,r22);
1228 rfYAngle
= -G3D::aTan2(elt
[2][1], elt
[2][2]);
1229 rfZAngle
= -(float)G3D_HALF_PI
;
1234 // WARNING. Not unique. YA + XA = atan2(r21,r22)
1235 rfYAngle
= G3D::aTan2(elt
[2][1], elt
[2][2]);
1236 rfZAngle
= (float)G3D_HALF_PI
;
1242 //----------------------------------------------------------------------------
1243 bool Matrix3::toEulerAnglesZXY (float& rfZAngle
, float& rfXAngle
,
1244 float& rfYAngle
) const {
1245 // rot = cy*cz-sx*sy*sz -cx*sz cz*sy+cy*sx*sz
1246 // cz*sx*sy+cy*sz cx*cz -cy*cz*sx+sy*sz
1249 if ( elt
[2][1] < 1.0 ) {
1250 if ( elt
[2][1] > -1.0 ) {
1251 rfZAngle
= G3D::aTan2( -elt
[0][1], elt
[1][1]);
1252 rfXAngle
= (float) asin(elt
[2][1]);
1253 rfYAngle
= G3D::aTan2( -elt
[2][0], elt
[2][2]);
1256 // WARNING. Not unique. ZA - YA = -atan(r02,r00)
1257 rfZAngle
= -G3D::aTan2(elt
[0][2], elt
[0][0]);
1258 rfXAngle
= -(float)G3D_HALF_PI
;
1263 // WARNING. Not unique. ZA + YA = atan2(r02,r00)
1264 rfZAngle
= G3D::aTan2(elt
[0][2], elt
[0][0]);
1265 rfXAngle
= (float)G3D_HALF_PI
;
1271 //----------------------------------------------------------------------------
1272 bool Matrix3::toEulerAnglesZYX (float& rfZAngle
, float& rfYAngle
,
1273 float& rfXAngle
) const {
1274 // rot = cy*cz cz*sx*sy-cx*sz cx*cz*sy+sx*sz
1275 // cy*sz cx*cz+sx*sy*sz -cz*sx+cx*sy*sz
1278 if ( elt
[2][0] < 1.0 ) {
1279 if ( elt
[2][0] > -1.0 ) {
1280 rfZAngle
= atan2f(elt
[1][0], elt
[0][0]);
1281 rfYAngle
= asinf(-(double)elt
[2][1]);
1282 rfXAngle
= atan2f(elt
[2][1], elt
[2][2]);
1285 // WARNING. Not unique. ZA - XA = -atan2(r01,r02)
1286 rfZAngle
= -G3D::aTan2(elt
[0][1], elt
[0][2]);
1287 rfYAngle
= (float)G3D_HALF_PI
;
1292 // WARNING. Not unique. ZA + XA = atan2(-r01,-r02)
1293 rfZAngle
= G3D::aTan2( -elt
[0][1], -elt
[0][2]);
1294 rfYAngle
= -(float)G3D_HALF_PI
;
1300 //----------------------------------------------------------------------------
1301 Matrix3
Matrix3::fromEulerAnglesXYZ (float fYAngle
, float fPAngle
,
1305 fCos
= cosf(fYAngle
);
1306 fSin
= sinf(fYAngle
);
1307 Matrix3
kXMat(1.0f
, 0.0f
, 0.0f
, 0.0f
, fCos
, -fSin
, 0.0, fSin
, fCos
);
1309 fCos
= cosf(fPAngle
);
1310 fSin
= sinf(fPAngle
);
1311 Matrix3
kYMat(fCos
, 0.0f
, fSin
, 0.0f
, 1.0f
, 0.0f
, -fSin
, 0.0f
, fCos
);
1313 fCos
= cosf(fRAngle
);
1314 fSin
= sinf(fRAngle
);
1315 Matrix3
kZMat(fCos
, -fSin
, 0.0f
, fSin
, fCos
, 0.0f
, 0.0f
, 0.0f
, 1.0f
);
1317 return kXMat
* (kYMat
* kZMat
);
1320 //----------------------------------------------------------------------------
1321 Matrix3
Matrix3::fromEulerAnglesXZY (float fYAngle
, float fPAngle
,
1326 fCos
= cosf(fYAngle
);
1327 fSin
= sinf(fYAngle
);
1328 Matrix3
kXMat(1.0, 0.0, 0.0, 0.0, fCos
, -fSin
, 0.0, fSin
, fCos
);
1330 fCos
= cosf(fPAngle
);
1331 fSin
= sinf(fPAngle
);
1332 Matrix3
kZMat(fCos
, -fSin
, 0.0, fSin
, fCos
, 0.0, 0.0, 0.0, 1.0);
1334 fCos
= cosf(fRAngle
);
1335 fSin
= sinf(fRAngle
);
1336 Matrix3
kYMat(fCos
, 0.0, fSin
, 0.0, 1.0, 0.0, -fSin
, 0.0, fCos
);
1338 return kXMat
* (kZMat
* kYMat
);
1341 //----------------------------------------------------------------------------
1342 Matrix3
Matrix3::fromEulerAnglesYXZ(
1349 fCos
= cos(fYAngle
);
1350 fSin
= sin(fYAngle
);
1351 Matrix3
kYMat(fCos
, 0.0f
, fSin
, 0.0f
, 1.0f
, 0.0f
, -fSin
, 0.0f
, fCos
);
1353 fCos
= cos(fPAngle
);
1354 fSin
= sin(fPAngle
);
1355 Matrix3
kXMat(1.0f
, 0.0f
, 0.0f
, 0.0f
, fCos
, -fSin
, 0.0f
, fSin
, fCos
);
1357 fCos
= cos(fRAngle
);
1358 fSin
= sin(fRAngle
);
1359 Matrix3
kZMat(fCos
, -fSin
, 0.0f
, fSin
, fCos
, 0.0f
, 0.0f
, 0.0f
, 1.0f
);
1361 return kYMat
* (kXMat
* kZMat
);
1364 //----------------------------------------------------------------------------
1365 Matrix3
Matrix3::fromEulerAnglesYZX(
1372 fCos
= cos(fYAngle
);
1373 fSin
= sin(fYAngle
);
1374 Matrix3
kYMat(fCos
, 0.0f
, fSin
, 0.0f
, 1.0f
, 0.0f
, -fSin
, 0.0f
, fCos
);
1376 fCos
= cos(fPAngle
);
1377 fSin
= sin(fPAngle
);
1378 Matrix3
kZMat(fCos
, -fSin
, 0.0f
, fSin
, fCos
, 0.0f
, 0.0f
, 0.0f
, 1.0f
);
1380 fCos
= cos(fRAngle
);
1381 fSin
= sin(fRAngle
);
1382 Matrix3
kXMat(1.0f
, 0.0f
, 0.0f
, 0.0f
, fCos
, -fSin
, 0.0f
, fSin
, fCos
);
1384 return kYMat
* (kZMat
* kXMat
);
1387 //----------------------------------------------------------------------------
1388 Matrix3
Matrix3::fromEulerAnglesZXY (float fYAngle
, float fPAngle
,
1392 fCos
= cos(fYAngle
);
1393 fSin
= sin(fYAngle
);
1394 Matrix3
kZMat(fCos
, -fSin
, 0.0, fSin
, fCos
, 0.0, 0.0, 0.0, 1.0);
1396 fCos
= cos(fPAngle
);
1397 fSin
= sin(fPAngle
);
1398 Matrix3
kXMat(1.0, 0.0, 0.0, 0.0, fCos
, -fSin
, 0.0, fSin
, fCos
);
1400 fCos
= cos(fRAngle
);
1401 fSin
= sin(fRAngle
);
1402 Matrix3
kYMat(fCos
, 0.0, fSin
, 0.0, 1.0, 0.0, -fSin
, 0.0, fCos
);
1404 return kZMat
* (kXMat
* kYMat
);
1407 //----------------------------------------------------------------------------
1408 Matrix3
Matrix3::fromEulerAnglesZYX (float fYAngle
, float fPAngle
,
1412 fCos
= cos(fYAngle
);
1413 fSin
= sin(fYAngle
);
1414 Matrix3
kZMat(fCos
, -fSin
, 0.0, fSin
, fCos
, 0.0, 0.0, 0.0, 1.0);
1416 fCos
= cos(fPAngle
);
1417 fSin
= sin(fPAngle
);
1418 Matrix3
kYMat(fCos
, 0.0, fSin
, 0.0, 1.0, 0.0, -fSin
, 0.0, fCos
);
1420 fCos
= cos(fRAngle
);
1421 fSin
= sin(fRAngle
);
1422 Matrix3
kXMat(1.0, 0.0, 0.0, 0.0, fCos
, -fSin
, 0.0, fSin
, fCos
);
1424 return kZMat
* (kYMat
* kXMat
);
1427 //----------------------------------------------------------------------------
1428 void Matrix3::tridiagonal (float afDiag
[3], float afSubDiag
[3]) {
1429 // Householder reduction T = Q^t M Q
1431 // mat, symmetric 3x3 matrix M
1433 // mat, orthogonal matrix Q
1434 // diag, diagonal entries of T
1435 // subd, subdiagonal entries of T (T is symmetric)
1437 float fA
= elt
[0][0];
1438 float fB
= elt
[0][1];
1439 float fC
= elt
[0][2];
1440 float fD
= elt
[1][1];
1441 float fE
= elt
[1][2];
1442 float fF
= elt
[2][2];
1447 if ( G3D::abs(fC
) >= EPSILON
) {
1448 float fLength
= sqrt(fB
* fB
+ fC
* fC
);
1449 float fInvLength
= 1.0 / fLength
;
1452 float fQ
= 2.0 * fB
* fE
+ fC
* (fF
- fD
);
1453 afDiag
[1] = fD
+ fC
* fQ
;
1454 afDiag
[2] = fF
- fC
* fQ
;
1455 afSubDiag
[0] = fLength
;
1456 afSubDiag
[1] = fE
- fB
* fQ
;
1483 //----------------------------------------------------------------------------
1484 bool Matrix3::qLAlgorithm (float afDiag
[3], float afSubDiag
[3]) {
1485 // QL iteration with implicit shifting to reduce matrix from tridiagonal
1488 for (int i0
= 0; i0
< 3; i0
++) {
1489 const int iMaxIter
= 32;
1492 for (iIter
= 0; iIter
< iMaxIter
; iIter
++) {
1495 for (i1
= i0
; i1
<= 1; i1
++) {
1496 float fSum
= G3D::abs(afDiag
[i1
]) +
1497 G3D::abs(afDiag
[i1
+ 1]);
1499 if ( G3D::abs(afSubDiag
[i1
]) + fSum
== fSum
)
1506 float fTmp0
= (afDiag
[i0
+ 1] - afDiag
[i0
]) / (2.0 * afSubDiag
[i0
]);
1508 float fTmp1
= sqrt(fTmp0
* fTmp0
+ 1.0);
1511 fTmp0
= afDiag
[i1
] - afDiag
[i0
] + afSubDiag
[i0
] / (fTmp0
- fTmp1
);
1513 fTmp0
= afDiag
[i1
] - afDiag
[i0
] + afSubDiag
[i0
] / (fTmp0
+ fTmp1
);
1521 for (int i2
= i1
- 1; i2
>= i0
; i2
--) {
1522 float fTmp3
= fSin
* afSubDiag
[i2
];
1523 float fTmp4
= fCos
* afSubDiag
[i2
];
1525 if (G3D::abs(fTmp3
) >= G3D::abs(fTmp0
)) {
1526 fCos
= fTmp0
/ fTmp3
;
1527 fTmp1
= sqrt(fCos
* fCos
+ 1.0);
1528 afSubDiag
[i2
+ 1] = fTmp3
* fTmp1
;
1532 fSin
= fTmp3
/ fTmp0
;
1533 fTmp1
= sqrt(fSin
* fSin
+ 1.0);
1534 afSubDiag
[i2
+ 1] = fTmp0
* fTmp1
;
1539 fTmp0
= afDiag
[i2
+ 1] - fTmp2
;
1540 fTmp1
= (afDiag
[i2
] - fTmp0
) * fSin
+ 2.0 * fTmp4
* fCos
;
1541 fTmp2
= fSin
* fTmp1
;
1542 afDiag
[i2
+ 1] = fTmp0
+ fTmp2
;
1543 fTmp0
= fCos
* fTmp1
- fTmp4
;
1545 for (int iRow
= 0; iRow
< 3; iRow
++) {
1546 fTmp3
= elt
[iRow
][i2
+ 1];
1547 elt
[iRow
][i2
+ 1] = fSin
* elt
[iRow
][i2
] +
1549 elt
[iRow
][i2
] = fCos
* elt
[iRow
][i2
] -
1554 afDiag
[i0
] -= fTmp2
;
1555 afSubDiag
[i0
] = fTmp0
;
1556 afSubDiag
[i1
] = 0.0;
1559 if ( iIter
== iMaxIter
) {
1560 // should not get here under normal circumstances
1568 //----------------------------------------------------------------------------
1569 void Matrix3::eigenSolveSymmetric (float afEigenvalue
[3],
1570 Vector3 akEigenvector
[3]) const {
1571 Matrix3 kMatrix
= *this;
1573 kMatrix
.tridiagonal(afEigenvalue
, afSubDiag
);
1574 kMatrix
.qLAlgorithm(afEigenvalue
, afSubDiag
);
1576 for (int i
= 0; i
< 3; i
++) {
1577 akEigenvector
[i
][0] = kMatrix
[0][i
];
1578 akEigenvector
[i
][1] = kMatrix
[1][i
];
1579 akEigenvector
[i
][2] = kMatrix
[2][i
];
1582 // make eigenvectors form a right--handed system
1583 Vector3 kCross
= akEigenvector
[1].cross(akEigenvector
[2]);
1585 float fDet
= akEigenvector
[0].dot(kCross
);
1588 akEigenvector
[2][0] = - akEigenvector
[2][0];
1589 akEigenvector
[2][1] = - akEigenvector
[2][1];
1590 akEigenvector
[2][2] = - akEigenvector
[2][2];
1594 //----------------------------------------------------------------------------
1595 void Matrix3::tensorProduct (const Vector3
& rkU
, const Vector3
& rkV
,
1596 Matrix3
& rkProduct
) {
1597 for (int iRow
= 0; iRow
< 3; iRow
++) {
1598 for (int iCol
= 0; iCol
< 3; iCol
++) {
1599 rkProduct
[iRow
][iCol
] = rkU
[iRow
] * rkV
[iCol
];
1604 //----------------------------------------------------------------------------
1606 // Runs in 52 cycles on AMD, 76 cycles on Intel Centrino
1608 // The loop unrolling is necessary for performance.
1609 // I was unable to improve performance further by flattening the matrices
1610 // into float*'s instead of 2D arrays.
1613 void Matrix3::_mul(const Matrix3
& A
, const Matrix3
& B
, Matrix3
& out
) {
1614 const float* ARowPtr
= A
.elt
[0];
1615 float* outRowPtr
= out
.elt
[0];
1617 ARowPtr
[0] * B
.elt
[0][0] +
1618 ARowPtr
[1] * B
.elt
[1][0] +
1619 ARowPtr
[2] * B
.elt
[2][0];
1621 ARowPtr
[0] * B
.elt
[0][1] +
1622 ARowPtr
[1] * B
.elt
[1][1] +
1623 ARowPtr
[2] * B
.elt
[2][1];
1625 ARowPtr
[0] * B
.elt
[0][2] +
1626 ARowPtr
[1] * B
.elt
[1][2] +
1627 ARowPtr
[2] * B
.elt
[2][2];
1630 outRowPtr
= out
.elt
[1];
1633 ARowPtr
[0] * B
.elt
[0][0] +
1634 ARowPtr
[1] * B
.elt
[1][0] +
1635 ARowPtr
[2] * B
.elt
[2][0];
1637 ARowPtr
[0] * B
.elt
[0][1] +
1638 ARowPtr
[1] * B
.elt
[1][1] +
1639 ARowPtr
[2] * B
.elt
[2][1];
1641 ARowPtr
[0] * B
.elt
[0][2] +
1642 ARowPtr
[1] * B
.elt
[1][2] +
1643 ARowPtr
[2] * B
.elt
[2][2];
1646 outRowPtr
= out
.elt
[2];
1649 ARowPtr
[0] * B
.elt
[0][0] +
1650 ARowPtr
[1] * B
.elt
[1][0] +
1651 ARowPtr
[2] * B
.elt
[2][0];
1653 ARowPtr
[0] * B
.elt
[0][1] +
1654 ARowPtr
[1] * B
.elt
[1][1] +
1655 ARowPtr
[2] * B
.elt
[2][1];
1657 ARowPtr
[0] * B
.elt
[0][2] +
1658 ARowPtr
[1] * B
.elt
[1][2] +
1659 ARowPtr
[2] * B
.elt
[2][2];
1662 //----------------------------------------------------------------------------
1663 void Matrix3::_transpose(const Matrix3
& A
, Matrix3
& out
) {
1664 out
[0][0] = A
.elt
[0][0];
1665 out
[0][1] = A
.elt
[1][0];
1666 out
[0][2] = A
.elt
[2][0];
1667 out
[1][0] = A
.elt
[0][1];
1668 out
[1][1] = A
.elt
[1][1];
1669 out
[1][2] = A
.elt
[2][1];
1670 out
[2][0] = A
.elt
[0][2];
1671 out
[2][1] = A
.elt
[1][2];
1672 out
[2][2] = A
.elt
[2][2];
1675 //-----------------------------------------------------------------------------
1676 std::string
Matrix3::toString() const {
1677 return G3D::format("[%g, %g, %g; %g, %g, %g; %g, %g, %g]",
1678 elt
[0][0], elt
[0][1], elt
[0][2],
1679 elt
[1][0], elt
[1][1], elt
[1][2],
1680 elt
[2][0], elt
[2][1], elt
[2][2]);