1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
4 // Digital Ltd. LLC
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are
10 // met:
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 // * Neither the name of Industrial Light & Magic nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 ///////////////////////////////////////////////////////////////////////////
34
35
36 #ifndef INCLUDED_IMATHMATRIXALGO_H
37 #define INCLUDED_IMATHMATRIXALGO_H
38
39 //-------------------------------------------------------------------------
40 //
41 // This file contains algorithms applied to or in conjunction with
42 // transformation matrices (Imath::Matrix33 and Imath::Matrix44).
43 // The assumption made is that these functions are called much less
44 // often than the basic point functions or these functions require
45 // more support classes.
46 //
47 // This file also defines a few predefined constant matrices.
48 //
49 //-------------------------------------------------------------------------
50
51 #include "ImathMatrix.h"
52 #include "ImathQuat.h"
53 #include "ImathEuler.h"
54 #include "ImathExc.h"
55 #include "ImathVec.h"
56 #include "ImathLimits.h"
57 #include <math.h>
58
59
60 #ifdef OPENEXR_DLL
61 #ifdef IMATH_EXPORTS
62 #define IMATH_EXPORT_CONST extern __declspec(dllexport)
63 #else
64 #define IMATH_EXPORT_CONST extern __declspec(dllimport)
65 #endif
66 #else
67 #define IMATH_EXPORT_CONST extern const
68 #endif
69
70
71 namespace Imath {
72
73 //------------------
74 // Identity matrices
75 //------------------
76
77 IMATH_EXPORT_CONST M33f identity33f;
78 IMATH_EXPORT_CONST M44f identity44f;
79 IMATH_EXPORT_CONST M33d identity33d;
80 IMATH_EXPORT_CONST M44d identity44d;
81
82 //----------------------------------------------------------------------
83 // Extract scale, shear, rotation, and translation values from a matrix:
84 //
85 // Notes:
86 //
87 // This implementation follows the technique described in the paper by
88 // Spencer W. Thomas in the Graphics Gems II article: "Decomposing a
89 // Matrix into Simple Transformations", p. 320.
90 //
91 // - Some of the functions below have an optional exc parameter
92 // that determines the functions' behavior when the matrix'
93 // scaling is very close to zero:
94 //
95 // If exc is true, the functions throw an Imath::ZeroScale exception.
96 //
97 // If exc is false:
98 //
99 // extractScaling (m, s) returns false, s is invalid
100 // sansScaling (m) returns m
101 // removeScaling (m) returns false, m is unchanged
102 // sansScalingAndShear (m) returns m
103 // removeScalingAndShear (m) returns false, m is unchanged
104 // extractAndRemoveScalingAndShear (m, s, h)
105 // returns false, m is unchanged,
106 // (sh) are invalid
107 // checkForZeroScaleInRow () returns false
108 // extractSHRT (m, s, h, r, t) returns false, (shrt) are invalid
109 //
110 // - Functions extractEuler(), extractEulerXYZ() and extractEulerZYX()
111 // assume that the matrix does not include shear or non-uniform scaling,
112 // but they do not examine the matrix to verify this assumption.
113 // Matrices with shear or non-uniform scaling are likely to produce
114 // meaningless results. Therefore, you should use the
115 // removeScalingAndShear() routine, if necessary, prior to calling
116 // extractEuler...() .
117 //
118 // - All functions assume that the matrix does not include perspective
119 // transformation(s), but they do not examine the matrix to verify
120 // this assumption. Matrices with perspective transformations are
121 // likely to produce meaningless results.
122 //
123 //----------------------------------------------------------------------
124
125
126 //
127 // Declarations for 4x4 matrix.
128 //
129
130 template <class T> bool extractScaling
131 (const Matrix44<T> &mat,
132 Vec3<T> &scl,
133 bool exc = true);
134
135 template <class T> Matrix44<T> sansScaling (const Matrix44<T> &mat,
136 bool exc = true);
137
138 template <class T> bool removeScaling
139 (Matrix44<T> &mat,
140 bool exc = true);
141
142 template <class T> bool extractScalingAndShear
143 (const Matrix44<T> &mat,
144 Vec3<T> &scl,
145 Vec3<T> &shr,
146 bool exc = true);
147
148 template <class T> Matrix44<T> sansScalingAndShear
149 (const Matrix44<T> &mat,
150 bool exc = true);
151
152 template <class T> void sansScalingAndShear
153 (Matrix44<T> &result,
154 const Matrix44<T> &mat,
155 bool exc = true);
156
157 template <class T> bool removeScalingAndShear
158 (Matrix44<T> &mat,
159 bool exc = true);
160
161 template <class T> bool extractAndRemoveScalingAndShear
162 (Matrix44<T> &mat,
163 Vec3<T> &scl,
164 Vec3<T> &shr,
165 bool exc = true);
166
167 template <class T> void extractEulerXYZ
168 (const Matrix44<T> &mat,
169 Vec3<T> &rot);
170
171 template <class T> void extractEulerZYX
172 (const Matrix44<T> &mat,
173 Vec3<T> &rot);
174
175 template <class T> Quat<T> extractQuat (const Matrix44<T> &mat);
176
177 template <class T> bool extractSHRT
178 (const Matrix44<T> &mat,
179 Vec3<T> &s,
180 Vec3<T> &h,
181 Vec3<T> &r,
182 Vec3<T> &t,
183 bool exc /*= true*/,
184 typename Euler<T>::Order rOrder);
185
186 template <class T> bool extractSHRT
187 (const Matrix44<T> &mat,
188 Vec3<T> &s,
189 Vec3<T> &h,
190 Vec3<T> &r,
191 Vec3<T> &t,
192 bool exc = true);
193
194 template <class T> bool extractSHRT
195 (const Matrix44<T> &mat,
196 Vec3<T> &s,
197 Vec3<T> &h,
198 Euler<T> &r,
199 Vec3<T> &t,
200 bool exc = true);
201
202 //
203 // Internal utility function.
204 //
205
206 template <class T> bool checkForZeroScaleInRow
207 (const T &scl,
208 const Vec3<T> &row,
209 bool exc = true);
210
211 template <class T> Matrix44<T> outerProduct
212 ( const Vec4<T> &a,
213 const Vec4<T> &b);
214
215
216 //
217 // Returns a matrix that rotates "fromDirection" vector to "toDirection"
218 // vector.
219 //
220
221 template <class T> Matrix44<T> rotationMatrix (const Vec3<T> &fromDirection,
222 const Vec3<T> &toDirection);
223
224
225
226 //
227 // Returns a matrix that rotates the "fromDir" vector
228 // so that it points towards "toDir". You may also
229 // specify that you want the up vector to be pointing
230 // in a certain direction "upDir".
231 //
232
233 template <class T> Matrix44<T> rotationMatrixWithUpDir
234 (const Vec3<T> &fromDir,
235 const Vec3<T> &toDir,
236 const Vec3<T> &upDir);
237
238
239 //
240 // Constructs a matrix that rotates the z-axis so that it
241 // points towards "targetDir". You must also specify
242 // that you want the up vector to be pointing in a
243 // certain direction "upDir".
244 //
245 // Notes: The following degenerate cases are handled:
246 // (a) when the directions given by "toDir" and "upDir"
247 // are parallel or opposite;
248 // (the direction vectors must have a non-zero cross product)
249 // (b) when any of the given direction vectors have zero length
250 //
251
252 template <class T> void alignZAxisWithTargetDir
253 (Matrix44<T> &result,
254 Vec3<T> targetDir,
255 Vec3<T> upDir);
256
257
258 // Compute an orthonormal direct frame from : a position, an x axis direction and a normal to the y axis
259 // If the x axis and normal are perpendicular, then the normal will have the same direction as the z axis.
260 // Inputs are :
261 // -the position of the frame
262 // -the x axis direction of the frame
263 // -a normal to the y axis of the frame
264 // Return is the orthonormal frame
265 template <class T> Matrix44<T> computeLocalFrame( const Vec3<T>& p,
266 const Vec3<T>& xDir,
267 const Vec3<T>& normal);
268
269 // Add a translate/rotate/scale offset to an input frame
270 // and put it in another frame of reference
271 // Inputs are :
272 // - input frame
273 // - translate offset
274 // - rotate offset in degrees
275 // - scale offset
276 // - frame of reference
277 // Output is the offsetted frame
278 template <class T> Matrix44<T> addOffset( const Matrix44<T>& inMat,
279 const Vec3<T>& tOffset,
280 const Vec3<T>& rOffset,
281 const Vec3<T>& sOffset,
282 const Vec3<T>& ref);
283
284 // Compute Translate/Rotate/Scale matrix from matrix A with the Rotate/Scale of Matrix B
285 // Inputs are :
286 // -keepRotateA : if true keep rotate from matrix A, use B otherwise
287 // -keepScaleA : if true keep scale from matrix A, use B otherwise
288 // -Matrix A
289 // -Matrix B
290 // Return Matrix A with tweaked rotation/scale
291 template <class T> Matrix44<T> computeRSMatrix( bool keepRotateA,
292 bool keepScaleA,
293 const Matrix44<T>& A,
294 const Matrix44<T>& B);
295
296
297 //----------------------------------------------------------------------
298
299
300 //
301 // Declarations for 3x3 matrix.
302 //
303
304
305 template <class T> bool extractScaling
306 (const Matrix33<T> &mat,
307 Vec2<T> &scl,
308 bool exc = true);
309
310 template <class T> Matrix33<T> sansScaling (const Matrix33<T> &mat,
311 bool exc = true);
312
313 template <class T> bool removeScaling
314 (Matrix33<T> &mat,
315 bool exc = true);
316
317 template <class T> bool extractScalingAndShear
318 (const Matrix33<T> &mat,
319 Vec2<T> &scl,
320 T &h,
321 bool exc = true);
322
323 template <class T> Matrix33<T> sansScalingAndShear
324 (const Matrix33<T> &mat,
325 bool exc = true);
326
327 template <class T> bool removeScalingAndShear
328 (Matrix33<T> &mat,
329 bool exc = true);
330
331 template <class T> bool extractAndRemoveScalingAndShear
332 (Matrix33<T> &mat,
333 Vec2<T> &scl,
334 T &shr,
335 bool exc = true);
336
337 template <class T> void extractEuler
338 (const Matrix33<T> &mat,
339 T &rot);
340
341 template <class T> bool extractSHRT (const Matrix33<T> &mat,
342 Vec2<T> &s,
343 T &h,
344 T &r,
345 Vec2<T> &t,
346 bool exc = true);
347
348 template <class T> bool checkForZeroScaleInRow
349 (const T &scl,
350 const Vec2<T> &row,
351 bool exc = true);
352
353 template <class T> Matrix33<T> outerProduct
354 ( const Vec3<T> &a,
355 const Vec3<T> &b);
356
357
358 //-----------------------------------------------------------------------------
359 // Implementation for 4x4 Matrix
360 //------------------------------
361
362
363 template <class T>
364 bool
extractScaling(const Matrix44<T> & mat,Vec3<T> & scl,bool exc)365 extractScaling (const Matrix44<T> &mat, Vec3<T> &scl, bool exc)
366 {
367 Vec3<T> shr;
368 Matrix44<T> M (mat);
369
370 if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))
371 return false;
372
373 return true;
374 }
375
376
377 template <class T>
378 Matrix44<T>
sansScaling(const Matrix44<T> & mat,bool exc)379 sansScaling (const Matrix44<T> &mat, bool exc)
380 {
381 Vec3<T> scl;
382 Vec3<T> shr;
383 Vec3<T> rot;
384 Vec3<T> tran;
385
386 if (! extractSHRT (mat, scl, shr, rot, tran, exc))
387 return mat;
388
389 Matrix44<T> M;
390
391 M.translate (tran);
392 M.rotate (rot);
393 M.shear (shr);
394
395 return M;
396 }
397
398
399 template <class T>
400 bool
removeScaling(Matrix44<T> & mat,bool exc)401 removeScaling (Matrix44<T> &mat, bool exc)
402 {
403 Vec3<T> scl;
404 Vec3<T> shr;
405 Vec3<T> rot;
406 Vec3<T> tran;
407
408 if (! extractSHRT (mat, scl, shr, rot, tran, exc))
409 return false;
410
411 mat.makeIdentity ();
412 mat.translate (tran);
413 mat.rotate (rot);
414 mat.shear (shr);
415
416 return true;
417 }
418
419
420 template <class T>
421 bool
extractScalingAndShear(const Matrix44<T> & mat,Vec3<T> & scl,Vec3<T> & shr,bool exc)422 extractScalingAndShear (const Matrix44<T> &mat,
423 Vec3<T> &scl, Vec3<T> &shr, bool exc)
424 {
425 Matrix44<T> M (mat);
426
427 if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))
428 return false;
429
430 return true;
431 }
432
433
434 template <class T>
435 Matrix44<T>
sansScalingAndShear(const Matrix44<T> & mat,bool exc)436 sansScalingAndShear (const Matrix44<T> &mat, bool exc)
437 {
438 Vec3<T> scl;
439 Vec3<T> shr;
440 Matrix44<T> M (mat);
441
442 if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))
443 return mat;
444
445 return M;
446 }
447
448
449 template <class T>
450 void
sansScalingAndShear(Matrix44<T> & result,const Matrix44<T> & mat,bool exc)451 sansScalingAndShear (Matrix44<T> &result, const Matrix44<T> &mat, bool exc)
452 {
453 Vec3<T> scl;
454 Vec3<T> shr;
455
456 if (! extractAndRemoveScalingAndShear (result, scl, shr, exc))
457 result = mat;
458 }
459
460
461 template <class T>
462 bool
removeScalingAndShear(Matrix44<T> & mat,bool exc)463 removeScalingAndShear (Matrix44<T> &mat, bool exc)
464 {
465 Vec3<T> scl;
466 Vec3<T> shr;
467
468 if (! extractAndRemoveScalingAndShear (mat, scl, shr, exc))
469 return false;
470
471 return true;
472 }
473
474
475 template <class T>
476 bool
extractAndRemoveScalingAndShear(Matrix44<T> & mat,Vec3<T> & scl,Vec3<T> & shr,bool exc)477 extractAndRemoveScalingAndShear (Matrix44<T> &mat,
478 Vec3<T> &scl, Vec3<T> &shr, bool exc)
479 {
480 //
481 // This implementation follows the technique described in the paper by
482 // Spencer W. Thomas in the Graphics Gems II article: "Decomposing a
483 // Matrix into Simple Transformations", p. 320.
484 //
485
486 Vec3<T> row[3];
487
488 row[0] = Vec3<T> (mat[0][0], mat[0][1], mat[0][2]);
489 row[1] = Vec3<T> (mat[1][0], mat[1][1], mat[1][2]);
490 row[2] = Vec3<T> (mat[2][0], mat[2][1], mat[2][2]);
491
492 T maxVal = 0;
493 for (int i=0; i < 3; i++)
494 for (int j=0; j < 3; j++)
495 if (Imath::abs (row[i][j]) > maxVal)
496 maxVal = Imath::abs (row[i][j]);
497
498 //
499 // We normalize the 3x3 matrix here.
500 // It was noticed that this can improve numerical stability significantly,
501 // especially when many of the upper 3x3 matrix's coefficients are very
502 // close to zero; we correct for this step at the end by multiplying the
503 // scaling factors by maxVal at the end (shear and rotation are not
504 // affected by the normalization).
505
506 if (maxVal != 0)
507 {
508 for (int i=0; i < 3; i++)
509 if (! checkForZeroScaleInRow (maxVal, row[i], exc))
510 return false;
511 else
512 row[i] /= maxVal;
513 }
514
515 // Compute X scale factor.
516 scl.x = row[0].length ();
517 if (! checkForZeroScaleInRow (scl.x, row[0], exc))
518 return false;
519
520 // Normalize first row.
521 row[0] /= scl.x;
522
523 // An XY shear factor will shear the X coord. as the Y coord. changes.
524 // There are 6 combinations (XY, XZ, YZ, YX, ZX, ZY), although we only
525 // extract the first 3 because we can effect the last 3 by shearing in
526 // XY, XZ, YZ combined rotations and scales.
527 //
528 // shear matrix < 1, YX, ZX, 0,
529 // XY, 1, ZY, 0,
530 // XZ, YZ, 1, 0,
531 // 0, 0, 0, 1 >
532
533 // Compute XY shear factor and make 2nd row orthogonal to 1st.
534 shr[0] = row[0].dot (row[1]);
535 row[1] -= shr[0] * row[0];
536
537 // Now, compute Y scale.
538 scl.y = row[1].length ();
539 if (! checkForZeroScaleInRow (scl.y, row[1], exc))
540 return false;
541
542 // Normalize 2nd row and correct the XY shear factor for Y scaling.
543 row[1] /= scl.y;
544 shr[0] /= scl.y;
545
546 // Compute XZ and YZ shears, orthogonalize 3rd row.
547 shr[1] = row[0].dot (row[2]);
548 row[2] -= shr[1] * row[0];
549 shr[2] = row[1].dot (row[2]);
550 row[2] -= shr[2] * row[1];
551
552 // Next, get Z scale.
553 scl.z = row[2].length ();
554 if (! checkForZeroScaleInRow (scl.z, row[2], exc))
555 return false;
556
557 // Normalize 3rd row and correct the XZ and YZ shear factors for Z scaling.
558 row[2] /= scl.z;
559 shr[1] /= scl.z;
560 shr[2] /= scl.z;
561
562 // At this point, the upper 3x3 matrix in mat is orthonormal.
563 // Check for a coordinate system flip. If the determinant
564 // is less than zero, then negate the matrix and the scaling factors.
565 if (row[0].dot (row[1].cross (row[2])) < 0)
566 for (int i=0; i < 3; i++)
567 {
568 scl[i] *= -1;
569 row[i] *= -1;
570 }
571
572 // Copy over the orthonormal rows into the returned matrix.
573 // The upper 3x3 matrix in mat is now a rotation matrix.
574 for (int i=0; i < 3; i++)
575 {
576 mat[i][0] = row[i][0];
577 mat[i][1] = row[i][1];
578 mat[i][2] = row[i][2];
579 }
580
581 // Correct the scaling factors for the normalization step that we
582 // performed above; shear and rotation are not affected by the
583 // normalization.
584 scl *= maxVal;
585
586 return true;
587 }
588
589
590 template <class T>
591 void
extractEulerXYZ(const Matrix44<T> & mat,Vec3<T> & rot)592 extractEulerXYZ (const Matrix44<T> &mat, Vec3<T> &rot)
593 {
594 //
595 // Normalize the local x, y and z axes to remove scaling.
596 //
597
598 Vec3<T> i (mat[0][0], mat[0][1], mat[0][2]);
599 Vec3<T> j (mat[1][0], mat[1][1], mat[1][2]);
600 Vec3<T> k (mat[2][0], mat[2][1], mat[2][2]);
601
602 i.normalize();
603 j.normalize();
604 k.normalize();
605
606 Matrix44<T> M (i[0], i[1], i[2], 0,
607 j[0], j[1], j[2], 0,
608 k[0], k[1], k[2], 0,
609 0, 0, 0, 1);
610
611 //
612 // Extract the first angle, rot.x.
613 //
614
615 rot.x = Math<T>::atan2 (M[1][2], M[2][2]);
616
617 //
618 // Remove the rot.x rotation from M, so that the remaining
619 // rotation, N, is only around two axes, and gimbal lock
620 // cannot occur.
621 //
622
623 Matrix44<T> N;
624 N.rotate (Vec3<T> (-rot.x, 0, 0));
625 N = N * M;
626
627 //
628 // Extract the other two angles, rot.y and rot.z, from N.
629 //
630
631 T cy = Math<T>::sqrt (N[0][0]*N[0][0] + N[0][1]*N[0][1]);
632 rot.y = Math<T>::atan2 (-N[0][2], cy);
633 rot.z = Math<T>::atan2 (-N[1][0], N[1][1]);
634 }
635
636
637 template <class T>
638 void
extractEulerZYX(const Matrix44<T> & mat,Vec3<T> & rot)639 extractEulerZYX (const Matrix44<T> &mat, Vec3<T> &rot)
640 {
641 //
642 // Normalize the local x, y and z axes to remove scaling.
643 //
644
645 Vec3<T> i (mat[0][0], mat[0][1], mat[0][2]);
646 Vec3<T> j (mat[1][0], mat[1][1], mat[1][2]);
647 Vec3<T> k (mat[2][0], mat[2][1], mat[2][2]);
648
649 i.normalize();
650 j.normalize();
651 k.normalize();
652
653 Matrix44<T> M (i[0], i[1], i[2], 0,
654 j[0], j[1], j[2], 0,
655 k[0], k[1], k[2], 0,
656 0, 0, 0, 1);
657
658 //
659 // Extract the first angle, rot.x.
660 //
661
662 rot.x = -Math<T>::atan2 (M[1][0], M[0][0]);
663
664 //
665 // Remove the x rotation from M, so that the remaining
666 // rotation, N, is only around two axes, and gimbal lock
667 // cannot occur.
668 //
669
670 Matrix44<T> N;
671 N.rotate (Vec3<T> (0, 0, -rot.x));
672 N = N * M;
673
674 //
675 // Extract the other two angles, rot.y and rot.z, from N.
676 //
677
678 T cy = Math<T>::sqrt (N[2][2]*N[2][2] + N[2][1]*N[2][1]);
679 rot.y = -Math<T>::atan2 (-N[2][0], cy);
680 rot.z = -Math<T>::atan2 (-N[1][2], N[1][1]);
681 }
682
683
684 template <class T>
685 Quat<T>
extractQuat(const Matrix44<T> & mat)686 extractQuat (const Matrix44<T> &mat)
687 {
688 Matrix44<T> rot;
689
690 T tr, s;
691 T q[4];
692 int i, j, k;
693 Quat<T> quat;
694
695 int nxt[3] = {1, 2, 0};
696 tr = mat[0][0] + mat[1][1] + mat[2][2];
697
698 // check the diagonal
699 if (tr > 0.0) {
700 s = Math<T>::sqrt (tr + T(1.0));
701 quat.r = s / T(2.0);
702 s = T(0.5) / s;
703
704 quat.v.x = (mat[1][2] - mat[2][1]) * s;
705 quat.v.y = (mat[2][0] - mat[0][2]) * s;
706 quat.v.z = (mat[0][1] - mat[1][0]) * s;
707 }
708 else {
709 // diagonal is negative
710 i = 0;
711 if (mat[1][1] > mat[0][0])
712 i=1;
713 if (mat[2][2] > mat[i][i])
714 i=2;
715
716 j = nxt[i];
717 k = nxt[j];
718 s = Math<T>::sqrt ((mat[i][i] - (mat[j][j] + mat[k][k])) + T(1.0));
719
720 q[i] = s * T(0.5);
721 if (s != T(0.0))
722 s = T(0.5) / s;
723
724 q[3] = (mat[j][k] - mat[k][j]) * s;
725 q[j] = (mat[i][j] + mat[j][i]) * s;
726 q[k] = (mat[i][k] + mat[k][i]) * s;
727
728 quat.v.x = q[0];
729 quat.v.y = q[1];
730 quat.v.z = q[2];
731 quat.r = q[3];
732 }
733
734 return quat;
735 }
736
737 template <class T>
738 bool
extractSHRT(const Matrix44<T> & mat,Vec3<T> & s,Vec3<T> & h,Vec3<T> & r,Vec3<T> & t,bool exc,typename Euler<T>::Order rOrder)739 extractSHRT (const Matrix44<T> &mat,
740 Vec3<T> &s,
741 Vec3<T> &h,
742 Vec3<T> &r,
743 Vec3<T> &t,
744 bool exc /* = true */ ,
745 typename Euler<T>::Order rOrder /* = Euler<T>::XYZ */ )
746 {
747 Matrix44<T> rot;
748
749 rot = mat;
750 if (! extractAndRemoveScalingAndShear (rot, s, h, exc))
751 return false;
752
753 extractEulerXYZ (rot, r);
754
755 t.x = mat[3][0];
756 t.y = mat[3][1];
757 t.z = mat[3][2];
758
759 if (rOrder != Euler<T>::XYZ)
760 {
761 Imath::Euler<T> eXYZ (r, Imath::Euler<T>::XYZ);
762 Imath::Euler<T> e (eXYZ, rOrder);
763 r = e.toXYZVector ();
764 }
765
766 return true;
767 }
768
769 template <class T>
770 bool
extractSHRT(const Matrix44<T> & mat,Vec3<T> & s,Vec3<T> & h,Vec3<T> & r,Vec3<T> & t,bool exc)771 extractSHRT (const Matrix44<T> &mat,
772 Vec3<T> &s,
773 Vec3<T> &h,
774 Vec3<T> &r,
775 Vec3<T> &t,
776 bool exc)
777 {
778 return extractSHRT(mat, s, h, r, t, exc, Imath::Euler<T>::XYZ);
779 }
780
781 template <class T>
782 bool
extractSHRT(const Matrix44<T> & mat,Vec3<T> & s,Vec3<T> & h,Euler<T> & r,Vec3<T> & t,bool exc)783 extractSHRT (const Matrix44<T> &mat,
784 Vec3<T> &s,
785 Vec3<T> &h,
786 Euler<T> &r,
787 Vec3<T> &t,
788 bool exc /* = true */)
789 {
790 return extractSHRT (mat, s, h, r, t, exc, r.order ());
791 }
792
793
794 template <class T>
795 bool
checkForZeroScaleInRow(const T & scl,const Vec3<T> & row,bool exc)796 checkForZeroScaleInRow (const T& scl,
797 const Vec3<T> &row,
798 bool exc /* = true */ )
799 {
800 for (int i = 0; i < 3; i++)
801 {
802 if ((abs (scl) < 1 && abs (row[i]) >= limits<T>::max() * abs (scl)))
803 {
804 if (exc)
805 throw Imath::ZeroScaleExc ("Cannot remove zero scaling "
806 "from matrix.");
807 else
808 return false;
809 }
810 }
811
812 return true;
813 }
814
815 template <class T>
816 Matrix44<T>
outerProduct(const Vec4<T> & a,const Vec4<T> & b)817 outerProduct (const Vec4<T> &a, const Vec4<T> &b )
818 {
819 return Matrix44<T> (a.x*b.x, a.x*b.y, a.x*b.z, a.x*b.w,
820 a.y*b.x, a.y*b.y, a.y*b.z, a.x*b.w,
821 a.z*b.x, a.z*b.y, a.z*b.z, a.x*b.w,
822 a.w*b.x, a.w*b.y, a.w*b.z, a.w*b.w);
823 }
824
825 template <class T>
826 Matrix44<T>
rotationMatrix(const Vec3<T> & from,const Vec3<T> & to)827 rotationMatrix (const Vec3<T> &from, const Vec3<T> &to)
828 {
829 Quat<T> q;
830 q.setRotation(from, to);
831 return q.toMatrix44();
832 }
833
834
835 template <class T>
836 Matrix44<T>
rotationMatrixWithUpDir(const Vec3<T> & fromDir,const Vec3<T> & toDir,const Vec3<T> & upDir)837 rotationMatrixWithUpDir (const Vec3<T> &fromDir,
838 const Vec3<T> &toDir,
839 const Vec3<T> &upDir)
840 {
841 //
842 // The goal is to obtain a rotation matrix that takes
843 // "fromDir" to "toDir". We do this in two steps and
844 // compose the resulting rotation matrices;
845 // (a) rotate "fromDir" into the z-axis
846 // (b) rotate the z-axis into "toDir"
847 //
848
849 // The from direction must be non-zero; but we allow zero to and up dirs.
850 if (fromDir.length () == 0)
851 return Matrix44<T> ();
852
853 else
854 {
855 Matrix44<T> zAxis2FromDir( Imath::UNINITIALIZED );
856 alignZAxisWithTargetDir (zAxis2FromDir, fromDir, Vec3<T> (0, 1, 0));
857
858 Matrix44<T> fromDir2zAxis = zAxis2FromDir.transposed ();
859
860 Matrix44<T> zAxis2ToDir( Imath::UNINITIALIZED );
861 alignZAxisWithTargetDir (zAxis2ToDir, toDir, upDir);
862
863 return fromDir2zAxis * zAxis2ToDir;
864 }
865 }
866
867
868 template <class T>
869 void
alignZAxisWithTargetDir(Matrix44<T> & result,Vec3<T> targetDir,Vec3<T> upDir)870 alignZAxisWithTargetDir (Matrix44<T> &result, Vec3<T> targetDir, Vec3<T> upDir)
871 {
872 //
873 // Ensure that the target direction is non-zero.
874 //
875
876 if ( targetDir.length () == 0 )
877 targetDir = Vec3<T> (0, 0, 1);
878
879 //
880 // Ensure that the up direction is non-zero.
881 //
882
883 if ( upDir.length () == 0 )
884 upDir = Vec3<T> (0, 1, 0);
885
886 //
887 // Check for degeneracies. If the upDir and targetDir are parallel
888 // or opposite, then compute a new, arbitrary up direction that is
889 // not parallel or opposite to the targetDir.
890 //
891
892 if (upDir.cross (targetDir).length () == 0)
893 {
894 upDir = targetDir.cross (Vec3<T> (1, 0, 0));
895 if (upDir.length() == 0)
896 upDir = targetDir.cross(Vec3<T> (0, 0, 1));
897 }
898
899 //
900 // Compute the x-, y-, and z-axis vectors of the new coordinate system.
901 //
902
903 Vec3<T> targetPerpDir = upDir.cross (targetDir);
904 Vec3<T> targetUpDir = targetDir.cross (targetPerpDir);
905
906 //
907 // Rotate the x-axis into targetPerpDir (row 0),
908 // rotate the y-axis into targetUpDir (row 1),
909 // rotate the z-axis into targetDir (row 2).
910 //
911
912 Vec3<T> row[3];
913 row[0] = targetPerpDir.normalized ();
914 row[1] = targetUpDir .normalized ();
915 row[2] = targetDir .normalized ();
916
917 result.x[0][0] = row[0][0];
918 result.x[0][1] = row[0][1];
919 result.x[0][2] = row[0][2];
920 result.x[0][3] = (T)0;
921
922 result.x[1][0] = row[1][0];
923 result.x[1][1] = row[1][1];
924 result.x[1][2] = row[1][2];
925 result.x[1][3] = (T)0;
926
927 result.x[2][0] = row[2][0];
928 result.x[2][1] = row[2][1];
929 result.x[2][2] = row[2][2];
930 result.x[2][3] = (T)0;
931
932 result.x[3][0] = (T)0;
933 result.x[3][1] = (T)0;
934 result.x[3][2] = (T)0;
935 result.x[3][3] = (T)1;
936 }
937
938
939 // Compute an orthonormal direct frame from : a position, an x axis direction and a normal to the y axis
940 // If the x axis and normal are perpendicular, then the normal will have the same direction as the z axis.
941 // Inputs are :
942 // -the position of the frame
943 // -the x axis direction of the frame
944 // -a normal to the y axis of the frame
945 // Return is the orthonormal frame
946 template <class T>
947 Matrix44<T>
computeLocalFrame(const Vec3<T> & p,const Vec3<T> & xDir,const Vec3<T> & normal)948 computeLocalFrame( const Vec3<T>& p,
949 const Vec3<T>& xDir,
950 const Vec3<T>& normal)
951 {
952 Vec3<T> _xDir(xDir);
953 Vec3<T> x = _xDir.normalize();
954 Vec3<T> y = (normal % x).normalize();
955 Vec3<T> z = (x % y).normalize();
956
957 Matrix44<T> L;
958 L[0][0] = x[0];
959 L[0][1] = x[1];
960 L[0][2] = x[2];
961 L[0][3] = 0.0;
962
963 L[1][0] = y[0];
964 L[1][1] = y[1];
965 L[1][2] = y[2];
966 L[1][3] = 0.0;
967
968 L[2][0] = z[0];
969 L[2][1] = z[1];
970 L[2][2] = z[2];
971 L[2][3] = 0.0;
972
973 L[3][0] = p[0];
974 L[3][1] = p[1];
975 L[3][2] = p[2];
976 L[3][3] = 1.0;
977
978 return L;
979 }
980
981 // Add a translate/rotate/scale offset to an input frame
982 // and put it in another frame of reference
983 // Inputs are :
984 // - input frame
985 // - translate offset
986 // - rotate offset in degrees
987 // - scale offset
988 // - frame of reference
989 // Output is the offsetted frame
990 template <class T>
991 Matrix44<T>
addOffset(const Matrix44<T> & inMat,const Vec3<T> & tOffset,const Vec3<T> & rOffset,const Vec3<T> & sOffset,const Matrix44<T> & ref)992 addOffset( const Matrix44<T>& inMat,
993 const Vec3<T>& tOffset,
994 const Vec3<T>& rOffset,
995 const Vec3<T>& sOffset,
996 const Matrix44<T>& ref)
997 {
998 Matrix44<T> O;
999
1000 Vec3<T> _rOffset(rOffset);
1001 _rOffset *= M_PI / 180.0;
1002 O.rotate (_rOffset);
1003
1004 O[3][0] = tOffset[0];
1005 O[3][1] = tOffset[1];
1006 O[3][2] = tOffset[2];
1007
1008 Matrix44<T> S;
1009 S.scale (sOffset);
1010
1011 Matrix44<T> X = S * O * inMat * ref;
1012
1013 return X;
1014 }
1015
1016 // Compute Translate/Rotate/Scale matrix from matrix A with the Rotate/Scale of Matrix B
1017 // Inputs are :
1018 // -keepRotateA : if true keep rotate from matrix A, use B otherwise
1019 // -keepScaleA : if true keep scale from matrix A, use B otherwise
1020 // -Matrix A
1021 // -Matrix B
1022 // Return Matrix A with tweaked rotation/scale
1023 template <class T>
1024 Matrix44<T>
computeRSMatrix(bool keepRotateA,bool keepScaleA,const Matrix44<T> & A,const Matrix44<T> & B)1025 computeRSMatrix( bool keepRotateA,
1026 bool keepScaleA,
1027 const Matrix44<T>& A,
1028 const Matrix44<T>& B)
1029 {
1030 Vec3<T> as, ah, ar, at;
1031 extractSHRT (A, as, ah, ar, at);
1032
1033 Vec3<T> bs, bh, br, bt;
1034 extractSHRT (B, bs, bh, br, bt);
1035
1036 if (!keepRotateA)
1037 ar = br;
1038
1039 if (!keepScaleA)
1040 as = bs;
1041
1042 Matrix44<T> mat;
1043 mat.makeIdentity();
1044 mat.translate (at);
1045 mat.rotate (ar);
1046 mat.scale (as);
1047
1048 return mat;
1049 }
1050
1051
1052
1053 //-----------------------------------------------------------------------------
1054 // Implementation for 3x3 Matrix
1055 //------------------------------
1056
1057
1058 template <class T>
1059 bool
extractScaling(const Matrix33<T> & mat,Vec2<T> & scl,bool exc)1060 extractScaling (const Matrix33<T> &mat, Vec2<T> &scl, bool exc)
1061 {
1062 T shr;
1063 Matrix33<T> M (mat);
1064
1065 if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))
1066 return false;
1067
1068 return true;
1069 }
1070
1071
1072 template <class T>
1073 Matrix33<T>
sansScaling(const Matrix33<T> & mat,bool exc)1074 sansScaling (const Matrix33<T> &mat, bool exc)
1075 {
1076 Vec2<T> scl;
1077 T shr;
1078 T rot;
1079 Vec2<T> tran;
1080
1081 if (! extractSHRT (mat, scl, shr, rot, tran, exc))
1082 return mat;
1083
1084 Matrix33<T> M;
1085
1086 M.translate (tran);
1087 M.rotate (rot);
1088 M.shear (shr);
1089
1090 return M;
1091 }
1092
1093
1094 template <class T>
1095 bool
removeScaling(Matrix33<T> & mat,bool exc)1096 removeScaling (Matrix33<T> &mat, bool exc)
1097 {
1098 Vec2<T> scl;
1099 T shr;
1100 T rot;
1101 Vec2<T> tran;
1102
1103 if (! extractSHRT (mat, scl, shr, rot, tran, exc))
1104 return false;
1105
1106 mat.makeIdentity ();
1107 mat.translate (tran);
1108 mat.rotate (rot);
1109 mat.shear (shr);
1110
1111 return true;
1112 }
1113
1114
1115 template <class T>
1116 bool
extractScalingAndShear(const Matrix33<T> & mat,Vec2<T> & scl,T & shr,bool exc)1117 extractScalingAndShear (const Matrix33<T> &mat, Vec2<T> &scl, T &shr, bool exc)
1118 {
1119 Matrix33<T> M (mat);
1120
1121 if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))
1122 return false;
1123
1124 return true;
1125 }
1126
1127
1128 template <class T>
1129 Matrix33<T>
sansScalingAndShear(const Matrix33<T> & mat,bool exc)1130 sansScalingAndShear (const Matrix33<T> &mat, bool exc)
1131 {
1132 Vec2<T> scl;
1133 T shr;
1134 Matrix33<T> M (mat);
1135
1136 if (! extractAndRemoveScalingAndShear (M, scl, shr, exc))
1137 return mat;
1138
1139 return M;
1140 }
1141
1142
1143 template <class T>
1144 bool
removeScalingAndShear(Matrix33<T> & mat,bool exc)1145 removeScalingAndShear (Matrix33<T> &mat, bool exc)
1146 {
1147 Vec2<T> scl;
1148 T shr;
1149
1150 if (! extractAndRemoveScalingAndShear (mat, scl, shr, exc))
1151 return false;
1152
1153 return true;
1154 }
1155
1156 template <class T>
1157 bool
extractAndRemoveScalingAndShear(Matrix33<T> & mat,Vec2<T> & scl,T & shr,bool exc)1158 extractAndRemoveScalingAndShear (Matrix33<T> &mat,
1159 Vec2<T> &scl, T &shr, bool exc)
1160 {
1161 Vec2<T> row[2];
1162
1163 row[0] = Vec2<T> (mat[0][0], mat[0][1]);
1164 row[1] = Vec2<T> (mat[1][0], mat[1][1]);
1165
1166 T maxVal = 0;
1167 for (int i=0; i < 2; i++)
1168 for (int j=0; j < 2; j++)
1169 if (Imath::abs (row[i][j]) > maxVal)
1170 maxVal = Imath::abs (row[i][j]);
1171
1172 //
1173 // We normalize the 2x2 matrix here.
1174 // It was noticed that this can improve numerical stability significantly,
1175 // especially when many of the upper 2x2 matrix's coefficients are very
1176 // close to zero; we correct for this step at the end by multiplying the
1177 // scaling factors by maxVal at the end (shear and rotation are not
1178 // affected by the normalization).
1179
1180 if (maxVal != 0)
1181 {
1182 for (int i=0; i < 2; i++)
1183 if (! checkForZeroScaleInRow (maxVal, row[i], exc))
1184 return false;
1185 else
1186 row[i] /= maxVal;
1187 }
1188
1189 // Compute X scale factor.
1190 scl.x = row[0].length ();
1191 if (! checkForZeroScaleInRow (scl.x, row[0], exc))
1192 return false;
1193
1194 // Normalize first row.
1195 row[0] /= scl.x;
1196
1197 // An XY shear factor will shear the X coord. as the Y coord. changes.
1198 // There are 2 combinations (XY, YX), although we only extract the XY
1199 // shear factor because we can effect the an YX shear factor by
1200 // shearing in XY combined with rotations and scales.
1201 //
1202 // shear matrix < 1, YX, 0,
1203 // XY, 1, 0,
1204 // 0, 0, 1 >
1205
1206 // Compute XY shear factor and make 2nd row orthogonal to 1st.
1207 shr = row[0].dot (row[1]);
1208 row[1] -= shr * row[0];
1209
1210 // Now, compute Y scale.
1211 scl.y = row[1].length ();
1212 if (! checkForZeroScaleInRow (scl.y, row[1], exc))
1213 return false;
1214
1215 // Normalize 2nd row and correct the XY shear factor for Y scaling.
1216 row[1] /= scl.y;
1217 shr /= scl.y;
1218
1219 // At this point, the upper 2x2 matrix in mat is orthonormal.
1220 // Check for a coordinate system flip. If the determinant
1221 // is -1, then flip the rotation matrix and adjust the scale(Y)
1222 // and shear(XY) factors to compensate.
1223 if (row[0][0] * row[1][1] - row[0][1] * row[1][0] < 0)
1224 {
1225 row[1][0] *= -1;
1226 row[1][1] *= -1;
1227 scl[1] *= -1;
1228 shr *= -1;
1229 }
1230
1231 // Copy over the orthonormal rows into the returned matrix.
1232 // The upper 2x2 matrix in mat is now a rotation matrix.
1233 for (int i=0; i < 2; i++)
1234 {
1235 mat[i][0] = row[i][0];
1236 mat[i][1] = row[i][1];
1237 }
1238
1239 scl *= maxVal;
1240
1241 return true;
1242 }
1243
1244
1245 template <class T>
1246 void
extractEuler(const Matrix33<T> & mat,T & rot)1247 extractEuler (const Matrix33<T> &mat, T &rot)
1248 {
1249 //
1250 // Normalize the local x and y axes to remove scaling.
1251 //
1252
1253 Vec2<T> i (mat[0][0], mat[0][1]);
1254 Vec2<T> j (mat[1][0], mat[1][1]);
1255
1256 i.normalize();
1257 j.normalize();
1258
1259 //
1260 // Extract the angle, rot.
1261 //
1262
1263 rot = - Math<T>::atan2 (j[0], i[0]);
1264 }
1265
1266
1267 template <class T>
1268 bool
extractSHRT(const Matrix33<T> & mat,Vec2<T> & s,T & h,T & r,Vec2<T> & t,bool exc)1269 extractSHRT (const Matrix33<T> &mat,
1270 Vec2<T> &s,
1271 T &h,
1272 T &r,
1273 Vec2<T> &t,
1274 bool exc)
1275 {
1276 Matrix33<T> rot;
1277
1278 rot = mat;
1279 if (! extractAndRemoveScalingAndShear (rot, s, h, exc))
1280 return false;
1281
1282 extractEuler (rot, r);
1283
1284 t.x = mat[2][0];
1285 t.y = mat[2][1];
1286
1287 return true;
1288 }
1289
1290
1291 template <class T>
1292 bool
checkForZeroScaleInRow(const T & scl,const Vec2<T> & row,bool exc)1293 checkForZeroScaleInRow (const T& scl,
1294 const Vec2<T> &row,
1295 bool exc /* = true */ )
1296 {
1297 for (int i = 0; i < 2; i++)
1298 {
1299 if ((abs (scl) < 1 && abs (row[i]) >= limits<T>::max() * abs (scl)))
1300 {
1301 if (exc)
1302 throw Imath::ZeroScaleExc ("Cannot remove zero scaling "
1303 "from matrix.");
1304 else
1305 return false;
1306 }
1307 }
1308
1309 return true;
1310 }
1311
1312
1313 template <class T>
1314 Matrix33<T>
outerProduct(const Vec3<T> & a,const Vec3<T> & b)1315 outerProduct (const Vec3<T> &a, const Vec3<T> &b )
1316 {
1317 return Matrix33<T> (a.x*b.x, a.x*b.y, a.x*b.z,
1318 a.y*b.x, a.y*b.y, a.y*b.z,
1319 a.z*b.x, a.z*b.y, a.z*b.z );
1320 }
1321
1322
1323 // Computes the translation and rotation that brings the 'from' points
1324 // as close as possible to the 'to' points under the Frobenius norm.
1325 // To be more specific, let x be the matrix of 'from' points and y be
1326 // the matrix of 'to' points, we want to find the matrix A of the form
1327 // [ R t ]
1328 // [ 0 1 ]
1329 // that minimizes
1330 // || (A*x - y)^T * W * (A*x - y) ||_F
1331 // If doScaling is true, then a uniform scale is allowed also.
1332 template <typename T>
1333 Imath::M44d
1334 procrustesRotationAndTranslation (const Imath::Vec3<T>* A, // From these
1335 const Imath::Vec3<T>* B, // To these
1336 const T* weights,
1337 const size_t numPoints,
1338 const bool doScaling = false);
1339
1340 // Unweighted:
1341 template <typename T>
1342 Imath::M44d
1343 procrustesRotationAndTranslation (const Imath::Vec3<T>* A,
1344 const Imath::Vec3<T>* B,
1345 const size_t numPoints,
1346 const bool doScaling = false);
1347
1348 // Compute the SVD of a 3x3 matrix using Jacobi transformations. This method
1349 // should be quite accurate (competitive with LAPACK) even for poorly
1350 // conditioned matrices, and because it has been written specifically for the
1351 // 3x3/4x4 case it is much faster than calling out to LAPACK.
1352 //
1353 // The SVD of a 3x3/4x4 matrix A is defined as follows:
1354 // A = U * S * V^T
1355 // where S is the diagonal matrix of singular values and both U and V are
1356 // orthonormal. By convention, the entries S are all positive and sorted from
1357 // the largest to the smallest. However, some uses of this function may
1358 // require that the matrix U*V^T have positive determinant; in this case, we
1359 // may make the smallest singular value negative to ensure that this is
1360 // satisfied.
1361 //
1362 // Currently only available for single- and double-precision matrices.
1363 template <typename T>
1364 void
1365 jacobiSVD (const Imath::Matrix33<T>& A,
1366 Imath::Matrix33<T>& U,
1367 Imath::Vec3<T>& S,
1368 Imath::Matrix33<T>& V,
1369 const T tol = Imath::limits<T>::epsilon(),
1370 const bool forcePositiveDeterminant = false);
1371
1372 template <typename T>
1373 void
1374 jacobiSVD (const Imath::Matrix44<T>& A,
1375 Imath::Matrix44<T>& U,
1376 Imath::Vec4<T>& S,
1377 Imath::Matrix44<T>& V,
1378 const T tol = Imath::limits<T>::epsilon(),
1379 const bool forcePositiveDeterminant = false);
1380
1381 // Compute the eigenvalues (S) and the eigenvectors (V) of
1382 // a real symmetric matrix using Jacobi transformation.
1383 //
1384 // Jacobi transformation of a 3x3/4x4 matrix A outputs S and V:
1385 // A = V * S * V^T
1386 // where V is orthonormal and S is the diagonal matrix of eigenvalues.
1387 // Input matrix A must be symmetric. A is also modified during
1388 // the computation so that upper diagonal entries of A become zero.
1389 //
1390 template <typename T>
1391 void
1392 jacobiEigenSolver (Matrix33<T>& A,
1393 Vec3<T>& S,
1394 Matrix33<T>& V,
1395 const T tol);
1396
1397 template <typename T>
1398 inline
1399 void
jacobiEigenSolver(Matrix33<T> & A,Vec3<T> & S,Matrix33<T> & V)1400 jacobiEigenSolver (Matrix33<T>& A,
1401 Vec3<T>& S,
1402 Matrix33<T>& V)
1403 {
1404 jacobiEigenSolver(A,S,V,limits<T>::epsilon());
1405 }
1406
1407 template <typename T>
1408 void
1409 jacobiEigenSolver (Matrix44<T>& A,
1410 Vec4<T>& S,
1411 Matrix44<T>& V,
1412 const T tol);
1413
1414 template <typename T>
1415 inline
1416 void
jacobiEigenSolver(Matrix44<T> & A,Vec4<T> & S,Matrix44<T> & V)1417 jacobiEigenSolver (Matrix44<T>& A,
1418 Vec4<T>& S,
1419 Matrix44<T>& V)
1420 {
1421 jacobiEigenSolver(A,S,V,limits<T>::epsilon());
1422 }
1423
1424 // Compute a eigenvector corresponding to the abs max/min eigenvalue
1425 // of a real symmetric matrix using Jacobi transformation.
1426 template <typename TM, typename TV>
1427 void
1428 maxEigenVector (TM& A, TV& S);
1429 template <typename TM, typename TV>
1430 void
1431 minEigenVector (TM& A, TV& S);
1432
1433 } // namespace Imath
1434
1435 #endif
1436