ImathMatrixAlgo.h 46 KB

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