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