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