Rotation.h 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/AxisAngle.h>
  9. #include <Mathematics/EulerAngles.h>
  10. #include <Mathematics/Matrix.h>
  11. #include <Mathematics/Quaternion.h>
  12. namespace WwiseGTE
  13. {
  14. // Conversions among various representations of rotations. The value of
  15. // N must be 3 or 4. The latter case supports affine algebra when you use
  16. // 4-tuple vectors (w-component is 1 for points and 0 for vector) and 4x4
  17. // matrices for affine transformations. Rotation axes must be unit
  18. // length. The angles are in radians. The Euler angles are in world
  19. // coordinates; we have not yet added support for body coordinates.
  20. template <int N, typename Real>
  21. class Rotation
  22. {
  23. public:
  24. // Create rotations from various representations.
  25. Rotation(Matrix<N, N, Real> const& matrix)
  26. :
  27. mType(IS_MATRIX),
  28. mMatrix(matrix)
  29. {
  30. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  31. }
  32. Rotation(Quaternion<Real> const& quaternion)
  33. :
  34. mType(IS_QUATERNION),
  35. mQuaternion(quaternion)
  36. {
  37. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  38. }
  39. Rotation(AxisAngle<N, Real> const& axisAngle)
  40. :
  41. mType(IS_AXIS_ANGLE),
  42. mAxisAngle(axisAngle)
  43. {
  44. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  45. }
  46. Rotation(EulerAngles<Real> const& eulerAngles)
  47. :
  48. mType(IS_EULER_ANGLES),
  49. mEulerAngles(eulerAngles)
  50. {
  51. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  52. }
  53. // Convert one representation to another.
  54. operator Matrix<N, N, Real>() const
  55. {
  56. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  57. switch (mType)
  58. {
  59. case IS_MATRIX:
  60. break;
  61. case IS_QUATERNION:
  62. Convert(mQuaternion, mMatrix);
  63. break;
  64. case IS_AXIS_ANGLE:
  65. Convert(mAxisAngle, mMatrix);
  66. break;
  67. case IS_EULER_ANGLES:
  68. Convert(mEulerAngles, mMatrix);
  69. break;
  70. }
  71. return mMatrix;
  72. }
  73. operator Quaternion<Real>() const
  74. {
  75. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  76. switch (mType)
  77. {
  78. case IS_MATRIX:
  79. Convert(mMatrix, mQuaternion);
  80. break;
  81. case IS_QUATERNION:
  82. break;
  83. case IS_AXIS_ANGLE:
  84. Convert(mAxisAngle, mQuaternion);
  85. break;
  86. case IS_EULER_ANGLES:
  87. Convert(mEulerAngles, mQuaternion);
  88. break;
  89. }
  90. return mQuaternion;
  91. }
  92. operator AxisAngle<N, Real>() const
  93. {
  94. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  95. switch (mType)
  96. {
  97. case IS_MATRIX:
  98. Convert(mMatrix, mAxisAngle);
  99. break;
  100. case IS_QUATERNION:
  101. Convert(mQuaternion, mAxisAngle);
  102. break;
  103. case IS_AXIS_ANGLE:
  104. break;
  105. case IS_EULER_ANGLES:
  106. Convert(mEulerAngles, mAxisAngle);
  107. break;
  108. }
  109. return mAxisAngle;
  110. }
  111. EulerAngles<Real> const& operator()(int i0, int i1, int i2) const
  112. {
  113. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  114. mEulerAngles.axis[0] = i0;
  115. mEulerAngles.axis[1] = i1;
  116. mEulerAngles.axis[2] = i2;
  117. switch (mType)
  118. {
  119. case IS_MATRIX:
  120. Convert(mMatrix, mEulerAngles);
  121. break;
  122. case IS_QUATERNION:
  123. Convert(mQuaternion, mEulerAngles);
  124. break;
  125. case IS_AXIS_ANGLE:
  126. Convert(mAxisAngle, mEulerAngles);
  127. break;
  128. case IS_EULER_ANGLES:
  129. break;
  130. }
  131. return mEulerAngles;
  132. }
  133. private:
  134. enum RepresentationType
  135. {
  136. IS_MATRIX,
  137. IS_QUATERNION,
  138. IS_AXIS_ANGLE,
  139. IS_EULER_ANGLES
  140. };
  141. RepresentationType mType;
  142. mutable Matrix<N, N, Real> mMatrix;
  143. mutable Quaternion<Real> mQuaternion;
  144. mutable AxisAngle<N, Real> mAxisAngle;
  145. mutable EulerAngles<Real> mEulerAngles;
  146. // Convert a rotation matrix to a quaternion.
  147. //
  148. // x^2 = (+r00 - r11 - r22 + 1)/4
  149. // y^2 = (-r00 + r11 - r22 + 1)/4
  150. // z^2 = (-r00 - r11 + r22 + 1)/4
  151. // w^2 = (+r00 + r11 + r22 + 1)/4
  152. // x^2 + y^2 = (1 - r22)/2
  153. // z^2 + w^2 = (1 + r22)/2
  154. // y^2 - x^2 = (r11 - r00)/2
  155. // w^2 - z^2 = (r11 + r00)/2
  156. // x*y = (r01 + r10)/4
  157. // x*z = (r02 + r20)/4
  158. // y*z = (r12 + r21)/4
  159. // [GTE_USE_MAT_VEC]
  160. // x*w = (r21 - r12)/4
  161. // y*w = (r02 - r20)/4
  162. // z*w = (r10 - r01)/4
  163. // [GTE_USE_VEC_MAT]
  164. // x*w = (r12 - r21)/4
  165. // y*w = (r20 - r02)/4
  166. // z*w = (r01 - r10)/4
  167. //
  168. // If Q is the 4x1 column vector (x,y,z,w), the previous equations
  169. // give us
  170. // +- -+
  171. // | x*x x*y x*z x*w |
  172. // Q*Q^T = | y*x y*y y*z y*w |
  173. // | z*x z*y z*z z*w |
  174. // | w*x w*y w*z w*w |
  175. // +- -+
  176. // The code extracts the row of maximum length, normalizing it to
  177. // obtain the result q.
  178. static void Convert(Matrix<N, N, Real> const& r, Quaternion<Real>& q)
  179. {
  180. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  181. Real r22 = r(2, 2);
  182. if (r22 <= (Real)0) // x^2 + y^2 >= z^2 + w^2
  183. {
  184. Real dif10 = r(1, 1) - r(0, 0);
  185. Real omr22 = (Real)1 - r22;
  186. if (dif10 <= (Real)0) // x^2 >= y^2
  187. {
  188. Real fourXSqr = omr22 - dif10;
  189. Real inv4x = ((Real)0.5) / std::sqrt(fourXSqr);
  190. q[0] = fourXSqr * inv4x;
  191. q[1] = (r(0, 1) + r(1, 0)) * inv4x;
  192. q[2] = (r(0, 2) + r(2, 0)) * inv4x;
  193. #if defined(GTE_USE_MAT_VEC)
  194. q[3] = (r(2, 1) - r(1, 2)) * inv4x;
  195. #else
  196. q[3] = (r(1, 2) - r(2, 1)) * inv4x;
  197. #endif
  198. }
  199. else // y^2 >= x^2
  200. {
  201. Real fourYSqr = omr22 + dif10;
  202. Real inv4y = ((Real)0.5) / std::sqrt(fourYSqr);
  203. q[0] = (r(0, 1) + r(1, 0)) * inv4y;
  204. q[1] = fourYSqr * inv4y;
  205. q[2] = (r(1, 2) + r(2, 1)) * inv4y;
  206. #if defined(GTE_USE_MAT_VEC)
  207. q[3] = (r(0, 2) - r(2, 0)) * inv4y;
  208. #else
  209. q[3] = (r(2, 0) - r(0, 2)) * inv4y;
  210. #endif
  211. }
  212. }
  213. else // z^2 + w^2 >= x^2 + y^2
  214. {
  215. Real sum10 = r(1, 1) + r(0, 0);
  216. Real opr22 = (Real)1 + r22;
  217. if (sum10 <= (Real)0) // z^2 >= w^2
  218. {
  219. Real fourZSqr = opr22 - sum10;
  220. Real inv4z = ((Real)0.5) / std::sqrt(fourZSqr);
  221. q[0] = (r(0, 2) + r(2, 0)) * inv4z;
  222. q[1] = (r(1, 2) + r(2, 1)) * inv4z;
  223. q[2] = fourZSqr * inv4z;
  224. #if defined(GTE_USE_MAT_VEC)
  225. q[3] = (r(1, 0) - r(0, 1)) * inv4z;
  226. #else
  227. q[3] = (r(0, 1) - r(1, 0)) * inv4z;
  228. #endif
  229. }
  230. else // w^2 >= z^2
  231. {
  232. Real fourWSqr = opr22 + sum10;
  233. Real inv4w = ((Real)0.5) / std::sqrt(fourWSqr);
  234. #if defined(GTE_USE_MAT_VEC)
  235. q[0] = (r(2, 1) - r(1, 2)) * inv4w;
  236. q[1] = (r(0, 2) - r(2, 0)) * inv4w;
  237. q[2] = (r(1, 0) - r(0, 1)) * inv4w;
  238. #else
  239. q[0] = (r(1, 2) - r(2, 1)) * inv4w;
  240. q[1] = (r(2, 0) - r(0, 2)) * inv4w;
  241. q[2] = (r(0, 1) - r(1, 0)) * inv4w;
  242. #endif
  243. q[3] = fourWSqr * inv4w;
  244. }
  245. }
  246. }
  247. // Convert a quaterion q = x*i + y*j + z*k + w to a rotation matrix.
  248. // [GTE_USE_MAT_VEC]
  249. // +- -+ +- -+
  250. // R = | r00 r01 r02 | = | 1-2y^2-2z^2 2(xy-zw) 2(xz+yw) |
  251. // | r10 r11 r12 | | 2(xy+zw) 1-2x^2-2z^2 2(yz-xw) |
  252. // | r20 r21 r22 | | 2(xz-yw) 2(yz+xw) 1-2x^2-2y^2 |
  253. // +- -+ +- -+
  254. // [GTE_USE_VEC_MAT]
  255. // +- -+ +- -+
  256. // R = | r00 r01 r02 | = | 1-2y^2-2z^2 2(xy+zw) 2(xz-yw) |
  257. // | r10 r11 r12 | | 2(xy-zw) 1-2x^2-2z^2 2(yz+xw) |
  258. // | r20 r21 r22 | | 2(xz+yw) 2(yz-xw) 1-2x^2-2y^2 |
  259. // +- -+ +- -+
  260. static void Convert(Quaternion<Real> const& q, Matrix<N, N, Real>& r)
  261. {
  262. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  263. r.MakeIdentity();
  264. Real twoX = ((Real)2) * q[0];
  265. Real twoY = ((Real)2) * q[1];
  266. Real twoZ = ((Real)2) * q[2];
  267. Real twoXX = twoX * q[0];
  268. Real twoXY = twoX * q[1];
  269. Real twoXZ = twoX * q[2];
  270. Real twoXW = twoX * q[3];
  271. Real twoYY = twoY * q[1];
  272. Real twoYZ = twoY * q[2];
  273. Real twoYW = twoY * q[3];
  274. Real twoZZ = twoZ * q[2];
  275. Real twoZW = twoZ * q[3];
  276. #if defined(GTE_USE_MAT_VEC)
  277. r(0, 0) = (Real)1 - twoYY - twoZZ;
  278. r(0, 1) = twoXY - twoZW;
  279. r(0, 2) = twoXZ + twoYW;
  280. r(1, 0) = twoXY + twoZW;
  281. r(1, 1) = (Real)1 - twoXX - twoZZ;
  282. r(1, 2) = twoYZ - twoXW;
  283. r(2, 0) = twoXZ - twoYW;
  284. r(2, 1) = twoYZ + twoXW;
  285. r(2, 2) = (Real)1 - twoXX - twoYY;
  286. #else
  287. r(0, 0) = (Real)1 - twoYY - twoZZ;
  288. r(1, 0) = twoXY - twoZW;
  289. r(2, 0) = twoXZ + twoYW;
  290. r(0, 1) = twoXY + twoZW;
  291. r(1, 1) = (Real)1 - twoXX - twoZZ;
  292. r(2, 1) = twoYZ - twoXW;
  293. r(0, 2) = twoXZ - twoYW;
  294. r(1, 2) = twoYZ + twoXW;
  295. r(2, 2) = (Real)1 - twoXX - twoYY;
  296. #endif
  297. }
  298. // Convert a rotation matrix to an axis-angle pair. Let (x0,x1,x2) be
  299. // the axis let t be an angle of rotation. The rotation matrix is
  300. // [GTE_USE_MAT_VEC]
  301. // R = I + sin(t)*S + (1-cos(t))*S^2
  302. // or
  303. // [GTE_USE_VEC_MAT]
  304. // R = I - sin(t)*S + (1-cos(t))*S^2
  305. // where I is the identity and S = {{0,-x2,x1},{x2,0,-x0},{-x1,x0,0}}
  306. // where the inner-brace triples are the rows of the matrix. If
  307. // t > 0, R represents a counterclockwise rotation; see the comments
  308. // for the constructor Matrix3x3(axis,angle). It may be shown that
  309. // cos(t) = (trace(R)-1)/2 and R - Transpose(R) = 2*sin(t)*S. As long
  310. // as sin(t) is not zero, we may solve for S in the second equation,
  311. // which produces the axis direction U = (S21,S02,S10). When t = 0,
  312. // the rotation is the identity, in which case any axis direction is
  313. // valid; we choose (1,0,0). When t = pi, it must be that
  314. // R - Transpose(R) = 0, which prevents us from extracting the axis.
  315. // Instead, note that (R+I)/2 = I+S^2 = U*U^T, where U is a
  316. // unit-length axis direction.
  317. static void Convert(Matrix<N, N, Real> const& r, AxisAngle<N, Real>& a)
  318. {
  319. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  320. Real trace = r(0, 0) + r(1, 1) + r(2, 2);
  321. Real half = (Real)0.5;
  322. Real cs = half * (trace - (Real)1);
  323. cs = std::max(std::min(cs, (Real)1), (Real)-1);
  324. a.angle = std::acos(cs); // The angle is in [0,pi].
  325. a.axis.MakeZero();
  326. if (a.angle > (Real)0)
  327. {
  328. if (a.angle < (Real)GTE_C_PI)
  329. {
  330. // The angle is in (0,pi).
  331. #if defined(GTE_USE_MAT_VEC)
  332. a.axis[0] = r(2, 1) - r(1, 2);
  333. a.axis[1] = r(0, 2) - r(2, 0);
  334. a.axis[2] = r(1, 0) - r(0, 1);
  335. Normalize(a.axis);
  336. #else
  337. a.axis[0] = r(1, 2) - r(2, 1);
  338. a.axis[1] = r(2, 0) - r(0, 2);
  339. a.axis[2] = r(0, 1) - r(1, 0);
  340. Normalize(a.axis);
  341. #endif
  342. }
  343. else
  344. {
  345. // The angle is pi, in which case R is symmetric and
  346. // R+I = 2*(I+S^2) = 2*U*U^T, where U = (u0,u1,u2) is the
  347. // unit-length direction of the rotation axis. Determine
  348. // the largest diagonal entry of R+I and normalize the
  349. // corresponding row to produce U. It does not matter the
  350. // sign on u[d] for chosen diagonal d, because
  351. // R(U,pi) = R(-U,pi).
  352. Real one = (Real)1;
  353. if (r(0, 0) >= r(1, 1))
  354. {
  355. if (r(0, 0) >= r(2, 2))
  356. {
  357. // r00 is maximum diagonal term
  358. a.axis[0] = r(0, 0) + one;
  359. a.axis[1] = half * (r(0, 1) + r(1, 0));
  360. a.axis[2] = half * (r(0, 2) + r(2, 0));
  361. }
  362. else
  363. {
  364. // r22 is maximum diagonal term
  365. a.axis[0] = half * (r(2, 0) + r(0, 2));
  366. a.axis[1] = half * (r(2, 1) + r(1, 2));
  367. a.axis[2] = r(2, 2) + one;
  368. }
  369. }
  370. else
  371. {
  372. if (r(1, 1) >= r(2, 2))
  373. {
  374. // r11 is maximum diagonal term
  375. a.axis[0] = half * (r(1, 0) + r(0, 1));
  376. a.axis[1] = r(1, 1) + one;
  377. a.axis[2] = half * (r(1, 2) + r(2, 1));
  378. }
  379. else
  380. {
  381. // r22 is maximum diagonal term
  382. a.axis[0] = half * (r(2, 0) + r(0, 2));
  383. a.axis[1] = half * (r(2, 1) + r(1, 2));
  384. a.axis[2] = r(2, 2) + one;
  385. }
  386. }
  387. Normalize(a.axis);
  388. }
  389. }
  390. else
  391. {
  392. // The angle is 0 and the matrix is the identity. Any axis
  393. // will work, so choose the Unit(0) axis.
  394. a.axis[0] = (Real)1;
  395. }
  396. }
  397. // Convert an axis-angle pair to a rotation matrix. Assuming
  398. // (x0,x1,x2) is for a right-handed world (x0 to right, x1 up, x2 out
  399. // of plane of page), a positive angle corresponds to a
  400. // counterclockwise rotation from the perspective of an observer
  401. // looking at the origin of the plane of rotation and having view
  402. // direction the negative of the axis direction. The coordinate-axis
  403. // rotations are the following, where unit(0) = (1,0,0),
  404. // unit(1) = (0,1,0), unit(2) = (0,0,1),
  405. // [GTE_USE_MAT_VEC]
  406. // R(unit(0),t) = {{ 1, 0, 0}, { 0, c,-s}, { 0, s, c}}
  407. // R(unit(1),t) = {{ c, 0, s}, { 0, 1, 0}, {-s, 0, c}}
  408. // R(unit(2),t) = {{ c,-s, 0}, { s, c, 0}, { 0, 0, 1}}
  409. // or
  410. // [GTE_USE_VEC_MAT]
  411. // R(unit(0),t) = {{ 1, 0, 0}, { 0, c, s}, { 0,-s, c}}
  412. // R(unit(1),t) = {{ c, 0,-s}, { 0, 1, 0}, { s, 0, c}}
  413. // R(unit(2),t) = {{ c, s, 0}, {-s, c, 0}, { 0, 0, 1}}
  414. // where c = cos(t), s = sin(t), and the inner-brace triples are rows
  415. // of the matrix. The general matrix is
  416. // [GTE_USE_MAT_VEC]
  417. // +- -+
  418. // R = | (1-c)*x0^2 + c (1-c)*x0*x1 - s*x2 (1-c)*x0*x2 + s*x1 |
  419. // | (1-c)*x0*x1 + s*x2 (1-c)*x1^2 + c (1-c)*x1*x2 - s*x0 |
  420. // | (1-c)*x0*x2 - s*x1 (1-c)*x1*x2 + s*x0 (1-c)*x2^2 + c |
  421. // +- -+
  422. // [GTE_USE_VEC_MAT]
  423. // +- -+
  424. // R = | (1-c)*x0^2 + c (1-c)*x0*x1 + s*x2 (1-c)*x0*x2 - s*x1 |
  425. // | (1-c)*x0*x1 - s*x2 (1-c)*x1^2 + c (1-c)*x1*x2 + s*x0 |
  426. // | (1-c)*x0*x2 + s*x1 (1-c)*x1*x2 - s*x0 (1-c)*x2^2 + c |
  427. // +- -+
  428. static void Convert(AxisAngle<N, Real> const& a, Matrix<N, N, Real>& r)
  429. {
  430. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  431. r.MakeIdentity();
  432. Real cs = std::cos(a.angle);
  433. Real sn = std::sin(a.angle);
  434. Real oneMinusCos = ((Real)1) - cs;
  435. Real x0sqr = a.axis[0] * a.axis[0];
  436. Real x1sqr = a.axis[1] * a.axis[1];
  437. Real x2sqr = a.axis[2] * a.axis[2];
  438. Real x0x1m = a.axis[0] * a.axis[1] * oneMinusCos;
  439. Real x0x2m = a.axis[0] * a.axis[2] * oneMinusCos;
  440. Real x1x2m = a.axis[1] * a.axis[2] * oneMinusCos;
  441. Real x0Sin = a.axis[0] * sn;
  442. Real x1Sin = a.axis[1] * sn;
  443. Real x2Sin = a.axis[2] * sn;
  444. #if defined(GTE_USE_MAT_VEC)
  445. r(0, 0) = x0sqr * oneMinusCos + cs;
  446. r(0, 1) = x0x1m - x2Sin;
  447. r(0, 2) = x0x2m + x1Sin;
  448. r(1, 0) = x0x1m + x2Sin;
  449. r(1, 1) = x1sqr * oneMinusCos + cs;
  450. r(1, 2) = x1x2m - x0Sin;
  451. r(2, 0) = x0x2m - x1Sin;
  452. r(2, 1) = x1x2m + x0Sin;
  453. r(2, 2) = x2sqr * oneMinusCos + cs;
  454. #else
  455. r(0, 0) = x0sqr * oneMinusCos + cs;
  456. r(1, 0) = x0x1m - x2Sin;
  457. r(2, 0) = x0x2m + x1Sin;
  458. r(0, 1) = x0x1m + x2Sin;
  459. r(1, 1) = x1sqr * oneMinusCos + cs;
  460. r(2, 1) = x1x2m - x0Sin;
  461. r(0, 2) = x0x2m - x1Sin;
  462. r(1, 2) = x1x2m + x0Sin;
  463. r(2, 2) = x2sqr * oneMinusCos + cs;
  464. #endif
  465. }
  466. // Convert a rotation matrix to Euler angles. Factorization into
  467. // Euler angles is not necessarily unique. If the result is
  468. // ER_NOT_UNIQUE_SUM, then the multiple solutions occur because
  469. // angleN2+angleN0 is constant. If the result is ER_NOT_UNIQUE_DIF,
  470. // then the multiple solutions occur because angleN2-angleN0 is
  471. // constant. In either type of nonuniqueness, the function returns
  472. // angleN0=0.
  473. static void Convert(Matrix<N, N, Real> const& r, EulerAngles<Real>& e)
  474. {
  475. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  476. if (0 <= e.axis[0] && e.axis[0] < 3
  477. && 0 <= e.axis[1] && e.axis[1] < 3
  478. && 0 <= e.axis[2] && e.axis[2] < 3
  479. && e.axis[1] != e.axis[0]
  480. && e.axis[1] != e.axis[2])
  481. {
  482. if (e.axis[0] != e.axis[2])
  483. {
  484. #if defined(GTE_USE_MAT_VEC)
  485. // Map (0,1,2), (1,2,0), and (2,0,1) to +1.
  486. // Map (0,2,1), (2,1,0), and (1,0,2) to -1.
  487. int parity = (((e.axis[2] | (e.axis[1] << 2)) >> e.axis[0]) & 1);
  488. Real const sgn = (parity & 1 ? (Real)-1 : (Real)+1);
  489. if (r(e.axis[2], e.axis[0]) < (Real)1)
  490. {
  491. if (r(e.axis[2], e.axis[0]) > (Real)-1)
  492. {
  493. e.angle[2] = std::atan2(sgn * r(e.axis[1], e.axis[0]),
  494. r(e.axis[0], e.axis[0]));
  495. e.angle[1] = std::asin(-sgn * r(e.axis[2], e.axis[0]));
  496. e.angle[0] = std::atan2(sgn * r(e.axis[2], e.axis[1]),
  497. r(e.axis[2], e.axis[2]));
  498. e.result = ER_UNIQUE;
  499. }
  500. else
  501. {
  502. e.angle[2] = (Real)0;
  503. e.angle[1] = sgn * (Real)GTE_C_HALF_PI;
  504. e.angle[0] = std::atan2(-sgn * r(e.axis[1], e.axis[2]),
  505. r(e.axis[1], e.axis[1]));
  506. e.result = ER_NOT_UNIQUE_DIF;
  507. }
  508. }
  509. else
  510. {
  511. e.angle[2] = (Real)0;
  512. e.angle[1] = -sgn * (Real)GTE_C_HALF_PI;
  513. e.angle[0] = std::atan2(-sgn * r(e.axis[1], e.axis[2]),
  514. r(e.axis[1], e.axis[1]));
  515. e.result = ER_NOT_UNIQUE_SUM;
  516. }
  517. #else
  518. // Map (0,1,2), (1,2,0), and (2,0,1) to +1.
  519. // Map (0,2,1), (2,1,0), and (1,0,2) to -1.
  520. int parity = (((e.axis[0] | (e.axis[1] << 2)) >> e.axis[2]) & 1);
  521. Real const sgn = (parity & 1 ? (Real)+1 : (Real)-1);
  522. if (r(e.axis[0], e.axis[2]) < (Real)1)
  523. {
  524. if (r(e.axis[0], e.axis[2]) > (Real)-1)
  525. {
  526. e.angle[0] = std::atan2(sgn * r(e.axis[1], e.axis[2]),
  527. r(e.axis[2], e.axis[2]));
  528. e.angle[1] = std::asin(-sgn * r(e.axis[0], e.axis[2]));
  529. e.angle[2] = std::atan2(sgn * r(e.axis[0], e.axis[1]),
  530. r(e.axis[0], e.axis[0]));
  531. e.result = ER_UNIQUE;
  532. }
  533. else
  534. {
  535. e.angle[0] = (Real)0;
  536. e.angle[1] = sgn * (Real)GTE_C_HALF_PI;
  537. e.angle[2] = std::atan2(-sgn * r(e.axis[1], e.axis[0]),
  538. r(e.axis[1], e.axis[1]));
  539. e.result = ER_NOT_UNIQUE_DIF;
  540. }
  541. }
  542. else
  543. {
  544. e.angle[0] = (Real)0;
  545. e.angle[1] = -sgn * (Real)GTE_C_HALF_PI;
  546. e.angle[2] = std::atan2(-sgn * r(e.axis[1], e.axis[0]),
  547. r(e.axis[1], e.axis[1]));
  548. e.result = ER_NOT_UNIQUE_SUM;
  549. }
  550. #endif
  551. }
  552. else
  553. {
  554. #if defined(GTE_USE_MAT_VEC)
  555. // Map (0,2,0), (1,0,1), and (2,1,2) to +1.
  556. // Map (0,1,0), (1,2,1), and (2,0,2) to -1.
  557. int b0 = 3 - e.axis[1] - e.axis[2];
  558. int parity = (((b0 | (e.axis[1] << 2)) >> e.axis[2]) & 1);
  559. Real const sgn = (parity & 1 ? (Real)+1 : (Real)-1);
  560. if (r(e.axis[2], e.axis[2]) < (Real)1)
  561. {
  562. if (r(e.axis[2], e.axis[2]) > (Real)-1)
  563. {
  564. e.angle[2] = std::atan2(r(e.axis[1], e.axis[2]),
  565. sgn * r(b0, e.axis[2]));
  566. e.angle[1] = std::acos(r(e.axis[2], e.axis[2]));
  567. e.angle[0] = std::atan2(r(e.axis[2], e.axis[1]),
  568. -sgn * r(e.axis[2], b0));
  569. e.result = ER_UNIQUE;
  570. }
  571. else
  572. {
  573. e.angle[2] = (Real)0;
  574. e.angle[1] = (Real)GTE_C_PI;
  575. e.angle[0] = std::atan2(sgn * r(e.axis[1], b0),
  576. r(e.axis[1], e.axis[1]));
  577. e.result = ER_NOT_UNIQUE_DIF;
  578. }
  579. }
  580. else
  581. {
  582. e.angle[2] = (Real)0;
  583. e.angle[1] = (Real)0;
  584. e.angle[0] = std::atan2(sgn * r(e.axis[1], b0),
  585. r(e.axis[1], e.axis[1]));
  586. e.result = ER_NOT_UNIQUE_SUM;
  587. }
  588. #else
  589. // Map (0,2,0), (1,0,1), and (2,1,2) to -1.
  590. // Map (0,1,0), (1,2,1), and (2,0,2) to +1.
  591. int b2 = 3 - e.axis[0] - e.axis[1];
  592. int parity = (((b2 | (e.axis[1] << 2)) >> e.axis[0]) & 1);
  593. Real const sgn = (parity & 1 ? (Real)-1 : (Real)+1);
  594. if (r(e.axis[0], e.axis[0]) < (Real)1)
  595. {
  596. if (r(e.axis[0], e.axis[0]) > (Real)-1)
  597. {
  598. e.angle[0] = std::atan2(r(e.axis[1], e.axis[0]),
  599. sgn * r(b2, e.axis[0]));
  600. e.angle[1] = std::acos(r(e.axis[0], e.axis[0]));
  601. e.angle[2] = std::atan2(r(e.axis[0], e.axis[1]),
  602. -sgn * r(e.axis[0], b2));
  603. e.result = ER_UNIQUE;
  604. }
  605. else
  606. {
  607. e.angle[0] = (Real)0;
  608. e.angle[1] = (Real)GTE_C_PI;
  609. e.angle[2] = std::atan2(sgn * r(e.axis[1], b2),
  610. r(e.axis[1], e.axis[1]));
  611. e.result = ER_NOT_UNIQUE_DIF;
  612. }
  613. }
  614. else
  615. {
  616. e.angle[0] = (Real)0;
  617. e.angle[1] = (Real)0;
  618. e.angle[2] = std::atan2(sgn * r(e.axis[1], b2),
  619. r(e.axis[1], e.axis[1]));
  620. e.result = ER_NOT_UNIQUE_SUM;
  621. }
  622. #endif
  623. }
  624. }
  625. else
  626. {
  627. // Invalid angles.
  628. e.angle[0] = (Real)0;
  629. e.angle[1] = (Real)0;
  630. e.angle[2] = (Real)0;
  631. e.result = ER_INVALID;
  632. }
  633. }
  634. // Convert Euler angles to a rotation matrix. The three integer
  635. // inputs are in {0,1,2} and correspond to world directions
  636. // unit(0) = (1,0,0), unit(1) = (0,1,0), or unit(2) = (0,0,1). The
  637. // triples (N0,N1,N2) must be in the following set,
  638. // {(0,1,2),(0,2,1),(1,0,2),(1,2,0),(2,0,1),(2,1,0),
  639. // (0,1,0),(0,2,0),(1,0,1),(1,2,1),(2,0,2),(2,1,2)}
  640. // The rotation matrix is
  641. // [GTE_USE_MAT_VEC]
  642. // R(unit(N2),angleN2)*R(unit(N1),angleN1)*R(unit(N0),angleN0)
  643. // or
  644. // [GTE_USE_VEC_MAT]
  645. // R(unit(N0),angleN0)*R(unit(N1),angleN1)*R(unit(N2),angleN2)
  646. // The conventions of constructor Matrix3(axis,angle) apply here as
  647. // well.
  648. //
  649. // NOTE: The reversal of order is chosen so that a rotation matrix
  650. // built with one multiplication convention is the transpose of the
  651. // rotation matrix built with the other multiplication convention.
  652. // Thus,
  653. // [GTE_USE_MAT_VEC]
  654. // Matrix3x3<Real> R_mvconvention(N0,N1,N2,angleN0,angleN1,angleN2);
  655. // Vector3<Real> V(...);
  656. // Vector3<Real> U = R_mvconvention*V; // (u0,u1,u2) = R2*R1*R0*V
  657. // [GTE_USE_VEC_MAT]
  658. // Matrix3x3<Real> R_vmconvention(N0,N1,N2,angleN0,angleN1,angleN2);
  659. // Vector3<Real> V(...);
  660. // Vector3<Real> U = R_mvconvention*V; // (u0,u1,u2) = V*R0*R1*R2
  661. // In either convention, you get the same 3-tuple U.
  662. static void Convert(EulerAngles<Real> const& e, Matrix<N, N, Real>& r)
  663. {
  664. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  665. if (0 <= e.axis[0] && e.axis[0] < 3
  666. && 0 <= e.axis[1] && e.axis[1] < 3
  667. && 0 <= e.axis[2] && e.axis[2] < 3
  668. && e.axis[1] != e.axis[0]
  669. && e.axis[1] != e.axis[2])
  670. {
  671. Matrix<N, N, Real> r0, r1, r2;
  672. Convert(AxisAngle<N, Real>(Vector<N, Real>::Unit(e.axis[0]),
  673. e.angle[0]), r0);
  674. Convert(AxisAngle<N, Real>(Vector<N, Real>::Unit(e.axis[1]),
  675. e.angle[1]), r1);
  676. Convert(AxisAngle<N, Real>(Vector<N, Real>::Unit(e.axis[2]),
  677. e.angle[2]), r2);
  678. #if defined(GTE_USE_MAT_VEC)
  679. r = r2 * r1 * r0;
  680. #else
  681. r = r0 * r1 * r2;
  682. #endif
  683. }
  684. else
  685. {
  686. // Invalid angles.
  687. r.MakeIdentity();
  688. }
  689. }
  690. // Convert a quaternion to an axis-angle pair, where
  691. // q = sin(angle/2)*(axis[0]*i+axis[1]*j+axis[2]*k)+cos(angle/2)
  692. static void Convert(Quaternion<Real> const& q, AxisAngle<N, Real>& a)
  693. {
  694. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  695. a.axis.MakeZero();
  696. Real axisSqrLen = q[0] * q[0] + q[1] * q[1] + q[2] * q[2];
  697. if (axisSqrLen > (Real)0)
  698. {
  699. #if defined(GTE_USE_MAT_VEC)
  700. Real adjust = ((Real)1) / std::sqrt(axisSqrLen);
  701. #else
  702. Real adjust = ((Real)-1) / std::sqrt(axisSqrLen);
  703. #endif
  704. a.axis[0] = q[0] * adjust;
  705. a.axis[1] = q[1] * adjust;
  706. a.axis[2] = q[2] * adjust;
  707. Real cs = std::max(std::min(q[3], (Real)1), (Real)-1);
  708. a.angle = (Real)2 * std::acos(cs);
  709. }
  710. else
  711. {
  712. // The angle is 0 (modulo 2*pi). Any axis will work, so choose
  713. // the Unit(0) axis.
  714. a.axis[0] = (Real)1;
  715. a.angle = (Real)0;
  716. }
  717. }
  718. // Convert an axis-angle pair to a quaternion, where
  719. // q = sin(angle/2)*(axis[0]*i+axis[1]*j+axis[2]*k)+cos(angle/2)
  720. static void Convert(AxisAngle<N, Real> const& a, Quaternion<Real>& q)
  721. {
  722. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  723. #if defined(GTE_USE_MAT_VEC)
  724. Real halfAngle = (Real)0.5 * a.angle;
  725. #else
  726. Real halfAngle = (Real)-0.5 * a.angle;
  727. #endif
  728. Real sn = std::sin(halfAngle);
  729. q[0] = sn * a.axis[0];
  730. q[1] = sn * a.axis[1];
  731. q[2] = sn * a.axis[2];
  732. q[3] = std::cos(halfAngle);
  733. }
  734. // Convert a quaternion to Euler angles. The quaternion is converted
  735. // to a matrix which is then converted to Euler angles.
  736. static void Convert(Quaternion<Real> const& q, EulerAngles<Real>& e)
  737. {
  738. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  739. Matrix<N, N, Real> r;
  740. Convert(q, r);
  741. Convert(r, e);
  742. }
  743. // Convert Euler angles to a quaternion. The Euler angles are
  744. // converted to a matrix which is then converted to a quaternion.
  745. static void Convert(EulerAngles<Real> const& e, Quaternion<Real>& q)
  746. {
  747. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  748. Matrix<N, N, Real> r;
  749. Convert(e, r);
  750. Convert(r, q);
  751. }
  752. // Convert an axis-angle pair to Euler angles. The axis-angle pair
  753. // is converted to a quaternion which is then converted to Euler
  754. // angles.
  755. static void Convert(AxisAngle<N, Real> const& a, EulerAngles<Real>& e)
  756. {
  757. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  758. Quaternion<Real> q;
  759. Convert(a, q);
  760. Convert(q, e);
  761. }
  762. // Convert Euler angles to an axis-angle pair. The Euler angles are
  763. // converted to a quaternion which is then converted to an axis-angle
  764. // pair.
  765. static void Convert(EulerAngles<Real> const& e, AxisAngle<N, Real>& a)
  766. {
  767. static_assert(N == 3 || N == 4, "Dimension must be 3 or 4.");
  768. Quaternion<Real> q;
  769. Convert(e, q);
  770. Convert(q, a);
  771. }
  772. };
  773. }