Quaternion.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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/Vector.h>
  9. #include <Mathematics/Matrix.h>
  10. #include <Mathematics/ChebyshevRatio.h>
  11. // A quaternion is of the form
  12. // q = x * i + y * j + z * k + w * 1 = x * i + y * j + z * k + w
  13. // where w, x, y, and z are real numbers. The scalar and vector parts are
  14. // Vector(q) = x * i + y * j + z * k
  15. // Scalar(q) = w
  16. // q = Vector(q) + Scalar(q)
  17. // I assume that you are familiar with the arithmetic and algebraic properties
  18. // of quaternions. See
  19. // https://www.geometrictools.com/Documentation/Quaternions.pdf
  20. namespace WwiseGTE
  21. {
  22. template <typename Real>
  23. class Quaternion
  24. {
  25. public:
  26. // The quaternions are of the form q = x*i + y*j + z*k + w. In tuple
  27. // form, q = (x,y,z,w).
  28. // Construction. The default constructor does not initialize the
  29. // members.
  30. Quaternion() = default;
  31. Quaternion(Real x, Real y, Real z, Real w)
  32. {
  33. mTuple[0] = x;
  34. mTuple[1] = y;
  35. mTuple[2] = z;
  36. mTuple[3] = w;
  37. }
  38. // Member access.
  39. inline Real const& operator[](int i) const
  40. {
  41. return mTuple[i];
  42. }
  43. inline Real& operator[](int i)
  44. {
  45. return mTuple[i];
  46. }
  47. // Comparisons.
  48. inline bool operator==(Quaternion const& q) const
  49. {
  50. return mTuple == q.mTuple;
  51. }
  52. inline bool operator!=(Quaternion const& q) const
  53. {
  54. return mTuple != q.mTuple;
  55. }
  56. inline bool operator<(Quaternion const& q) const
  57. {
  58. return mTuple < q.mTuple;
  59. }
  60. inline bool operator<=(Quaternion const& q) const
  61. {
  62. return mTuple <= q.mTuple;
  63. }
  64. inline bool operator>(Quaternion const& q) const
  65. {
  66. return mTuple > q.mTuple;
  67. }
  68. inline bool operator>=(Quaternion const& q) const
  69. {
  70. return mTuple >= q.mTuple;
  71. }
  72. // Special quaternions.
  73. // z = 0*i + 0*j + 0*k + 0
  74. static Quaternion Zero()
  75. {
  76. return Quaternion((Real)0, (Real)0, (Real)0, (Real)0);
  77. }
  78. // i = 1*i + 0*j + 0*k + 0
  79. static Quaternion I()
  80. {
  81. return Quaternion((Real)1, (Real)0, (Real)0, (Real)0);
  82. }
  83. // j = 0*i + 1*j + 0*k + 0
  84. static Quaternion J()
  85. {
  86. return Quaternion((Real)0, (Real)1, (Real)0, (Real)0);
  87. }
  88. // k = 0*i + 0*j + 1*k + 0
  89. static Quaternion K()
  90. {
  91. return Quaternion((Real)0, (Real)0, (Real)1, (Real)0);
  92. }
  93. // 1 = 0*i + 0*j + 0*k + 1
  94. static Quaternion Identity()
  95. {
  96. return Quaternion((Real)0, (Real)0, (Real)0, (Real)1);
  97. }
  98. protected:
  99. std::array<Real, 4> mTuple;
  100. };
  101. // Unary operations.
  102. template <typename Real>
  103. Quaternion<Real> operator+(Quaternion<Real> const& q)
  104. {
  105. return q;
  106. }
  107. template <typename Real>
  108. Quaternion<Real> operator-(Quaternion<Real> const& q)
  109. {
  110. Quaternion<Real> result;
  111. for (int i = 0; i < 4; ++i)
  112. {
  113. result[i] = -q[i];
  114. }
  115. return result;
  116. }
  117. // Linear algebraic operations.
  118. template <typename Real>
  119. Quaternion<Real> operator+(Quaternion<Real> const& q0, Quaternion<Real> const& q1)
  120. {
  121. Quaternion<Real> result = q0;
  122. return result += q1;
  123. }
  124. template <typename Real>
  125. Quaternion<Real> operator-(Quaternion<Real> const& q0, Quaternion<Real> const& q1)
  126. {
  127. Quaternion<Real> result = q0;
  128. return result -= q1;
  129. }
  130. template <typename Real>
  131. Quaternion<Real> operator*(Quaternion<Real> const& q, Real scalar)
  132. {
  133. Quaternion<Real> result = q;
  134. return result *= scalar;
  135. }
  136. template <typename Real>
  137. Quaternion<Real> operator*(Real scalar, Quaternion<Real> const& q)
  138. {
  139. Quaternion<Real> result = q;
  140. return result *= scalar;
  141. }
  142. template <typename Real>
  143. Quaternion<Real> operator/(Quaternion<Real> const& q, Real scalar)
  144. {
  145. Quaternion<Real> result = q;
  146. return result /= scalar;
  147. }
  148. template <typename Real>
  149. Quaternion<Real>& operator+=(Quaternion<Real>& q0, Quaternion<Real> const& q1)
  150. {
  151. for (int i = 0; i < 4; ++i)
  152. {
  153. q0[i] += q1[i];
  154. }
  155. return q0;
  156. }
  157. template <typename Real>
  158. Quaternion<Real>& operator-=(Quaternion<Real>& q0, Quaternion<Real> const& q1)
  159. {
  160. for (int i = 0; i < 4; ++i)
  161. {
  162. q0[i] -= q1[i];
  163. }
  164. return q0;
  165. }
  166. template <typename Real>
  167. Quaternion<Real>& operator*=(Quaternion<Real>& q, Real scalar)
  168. {
  169. for (int i = 0; i < 4; ++i)
  170. {
  171. q[i] *= scalar;
  172. }
  173. return q;
  174. }
  175. template <typename Real>
  176. Quaternion<Real>& operator/=(Quaternion<Real>& q, Real scalar)
  177. {
  178. if (scalar != (Real)0)
  179. {
  180. for (int i = 0; i < 4; ++i)
  181. {
  182. q[i] /= scalar;
  183. }
  184. }
  185. else
  186. {
  187. for (int i = 0; i < 4; ++i)
  188. {
  189. q[i] = (Real)0;
  190. }
  191. }
  192. return q;
  193. }
  194. // Geometric operations.
  195. template <typename Real>
  196. Real Dot(Quaternion<Real> const& q0, Quaternion<Real> const& q1)
  197. {
  198. Real dot = q0[0] * q1[0];
  199. for (int i = 1; i < 4; ++i)
  200. {
  201. dot += q0[i] * q1[i];
  202. }
  203. return dot;
  204. }
  205. template <typename Real>
  206. Real Length(Quaternion<Real> const& q)
  207. {
  208. return std::sqrt(Dot(q, q));
  209. }
  210. template <typename Real>
  211. Real Normalize(Quaternion<Real>& q)
  212. {
  213. Real length = std::sqrt(Dot(q, q));
  214. if (length > (Real)0)
  215. {
  216. q /= length;
  217. }
  218. else
  219. {
  220. for (int i = 0; i < 4; ++i)
  221. {
  222. q[i] = (Real)0;
  223. }
  224. }
  225. return length;
  226. }
  227. // Multiplication of quaternions. This operation is not generally
  228. // commutative; that is, q0*q1 and q1*q0 are not usually the same value.
  229. // (x0*i + y0*j + z0*k + w0)*(x1*i + y1*j + z1*k + w1)
  230. // =
  231. // i*(+x0*w1 + y0*z1 - z0*y1 + w0*x1) +
  232. // j*(-x0*z1 + y0*w1 + z0*x1 + w0*y1) +
  233. // k*(+x0*y1 - y0*x1 + z0*w1 + w0*z1) +
  234. // 1*(-x0*x1 - y0*y1 - z0*z1 + w0*w1)
  235. template <typename Real>
  236. Quaternion<Real> operator*(Quaternion<Real> const& q0, Quaternion<Real> const& q1)
  237. {
  238. // (x0*i + y0*j + z0*k + w0)*(x1*i + y1*j + z1*k + w1)
  239. // =
  240. // i*(+x0*w1 + y0*z1 - z0*y1 + w0*x1) +
  241. // j*(-x0*z1 + y0*w1 + z0*x1 + w0*y1) +
  242. // k*(+x0*y1 - y0*x1 + z0*w1 + w0*z1) +
  243. // 1*(-x0*x1 - y0*y1 - z0*z1 + w0*w1)
  244. return Quaternion<Real>
  245. (
  246. +q0[0] * q1[3] + q0[1] * q1[2] - q0[2] * q1[1] + q0[3] * q1[0],
  247. -q0[0] * q1[2] + q0[1] * q1[3] + q0[2] * q1[0] + q0[3] * q1[1],
  248. +q0[0] * q1[1] - q0[1] * q1[0] + q0[2] * q1[3] + q0[3] * q1[2],
  249. -q0[0] * q1[0] - q0[1] * q1[1] - q0[2] * q1[2] + q0[3] * q1[3]
  250. );
  251. }
  252. // For a nonzero quaternion q = (x,y,z,w), inv(q) = (-x,-y,-z,w)/|q|^2,
  253. // where |q| is the length of the quaternion. When q is zero, the
  254. // function returns zero, which is considered to be an improbable case.
  255. template <typename Real>
  256. Quaternion<Real> Inverse(Quaternion<Real> const& q)
  257. {
  258. Real sqrLen = Dot(q, q);
  259. if (sqrLen > (Real)0)
  260. {
  261. Quaternion<Real> inverse = Conjugate(q) / sqrLen;
  262. return inverse;
  263. }
  264. else
  265. {
  266. return Quaternion<Real>::Zero();
  267. }
  268. }
  269. // The conjugate of q = (x,y,z,w) is conj(q) = (-x,-y,-z,w).
  270. template <typename Real>
  271. Quaternion<Real> Conjugate(Quaternion<Real> const& q)
  272. {
  273. return Quaternion<Real>(-q[0], -q[1], -q[2], +q[3]);
  274. }
  275. // Rotate a vector using quaternion multiplication. The input quaternion
  276. // must be unit length.
  277. template <typename Real>
  278. Vector<4, Real> Rotate(Quaternion<Real> const& q, Vector<4, Real> const& v)
  279. {
  280. Quaternion<Real> input(v[0], v[1], v[2], (Real)0);
  281. Quaternion<Real> output = q * input * Conjugate(q);
  282. Vector<4, Real> u{ output[0], output[1], output[2], (Real)0 };
  283. return u;
  284. }
  285. // The spherical linear interpolation (slerp) of unit-length quaternions
  286. // q0 and q1 for t in [0,1] is
  287. // slerp(t,q0,q1) = [sin(t*theta)*q0 + sin((1-t)*theta)*q1]/sin(theta)
  288. // where theta is the angle between q0 and q1 [cos(theta) = Dot(q0,q1)].
  289. // This function is a parameterization of the great spherical arc between
  290. // q0 and q1 on the unit hypersphere. Moreover, the parameterization is
  291. // one of normalized arclength--a particle traveling along the arc through
  292. // time t does so with constant speed.
  293. //
  294. // When using slerp in animations involving sequences of quaternions, it
  295. // is typical that the quaternions are preprocessed so that consecutive
  296. // ones form an acute angle A in [0,pi/2]. Other preprocessing can help
  297. // with performance. See the function comments below.
  298. //
  299. // See GteSlerpEstimate.{h,inl} for various approximations, including
  300. // SLERP<Real>::EstimateRPH that gives good performance and accurate
  301. // results for preprocessed quaternions.
  302. // The angle between q0 and q1 is in [0,pi). There are no angle
  303. // restrictions and nothing is precomputed.
  304. template <typename Real>
  305. Quaternion<Real> Slerp(Real t, Quaternion<Real> const& q0, Quaternion<Real> const& q1)
  306. {
  307. Real cosA = Dot(q0, q1);
  308. Real sign;
  309. if (cosA >= (Real)0)
  310. {
  311. sign = (Real)1;
  312. }
  313. else
  314. {
  315. cosA = -cosA;
  316. sign = (Real)-1;
  317. }
  318. Real f0, f1;
  319. ChebyshevRatio<Real>::Get(t, cosA, f0, f1);
  320. return q0 * f0 + q1 * (sign * f1);
  321. }
  322. // The angle between q0 and q1 must be in [0,pi/2]. The suffix R is for
  323. // 'Restricted'. The preprocessing code is
  324. // Quaternion<Real> q[n]; // assuming initialized
  325. // for (i0 = 0, i1 = 1; i1 < n; i0 = i1++)
  326. // {
  327. // cosA = Dot(q[i0], q[i1]);
  328. // if (cosA < 0)
  329. // {
  330. // q[i1] = -q[i1]; // now Dot(q[i0], q[i]1) >= 0
  331. // }
  332. // }
  333. template <typename Real>
  334. Quaternion<Real> SlerpR(Real t, Quaternion<Real> const& q0, Quaternion<Real> const& q1)
  335. {
  336. Real f0, f1;
  337. ChebyshevRatio<Real>::Get(t, Dot(q0, q1), f0, f1);
  338. return q0 * f0 + q1 * f1;
  339. }
  340. // The angle between q0 and q1 must be in [0,pi/2]. The suffix R is for
  341. // 'Restricted' and the suffix P is for 'Preprocessed'. The preprocessing
  342. // code is
  343. // Quaternion<Real> q[n]; // assuming initialized
  344. // Real cosA[n-1], omcosA[n-1]; // to be precomputed
  345. // for (i0 = 0, i1 = 1; i1 < n; i0 = i1++)
  346. // {
  347. // cs = Dot(q[i0], q[i1]);
  348. // if (cosA[i0] < 0)
  349. // {
  350. // q[i1] = -q[i1];
  351. // cs = -cs;
  352. // }
  353. //
  354. // // for Quaterion<Real>::SlerpRP
  355. // cosA[i0] = cs;
  356. //
  357. // // for SLERP<Real>::EstimateRP
  358. // omcosA[i0] = 1 - cs;
  359. // }
  360. template <typename Real>
  361. Quaternion<Real> SlerpRP(Real t, Quaternion<Real> const& q0, Quaternion<Real> const& q1, Real cosA)
  362. {
  363. Real f0, f1;
  364. ChebyshevRatio<Real>::Get(t, cosA, f0, f1);
  365. return q0 * f0 + q1 * f1;
  366. }
  367. // The angle between q0 and q1 is A and must be in [0,pi/2]. The suffix R
  368. // is for 'Restricted', the suffix P is for 'Preprocessed' and the suffix
  369. // H is for 'Half' (the quaternion qh halfway between q0 and q1 is
  370. // precomputed). Quaternion qh is slerp(1/2,q0,q1) = (q0+q1)/|q0+q1|, so
  371. // the angle between q0 and qh is A/2 and the angle between qh and q1 is
  372. // A/2. The preprocessing code is
  373. // Quaternion<Real> q[n]; // assuming initialized
  374. // Quaternion<Real> qh[n-1]; // to be precomputed
  375. // Real omcosAH[n-1]; // to be precomputed
  376. // for (i0 = 0, i1 = 1; i1 < n; i0 = i1++)
  377. // {
  378. // cosA = Dot(q[i0], q[i1]);
  379. // if (cosA < 0)
  380. // {
  381. // q[i1] = -q[i1];
  382. // cosA = -cosA;
  383. // }
  384. //
  385. // // for Quaternion<Real>::SlerpRPH and SLERP<Real>::EstimateRPH
  386. // cosAH[i0] = sqrt((1+cosA)/2);
  387. // qh[i0] = (q0 + q1) / (2 * cosAH[i0]);
  388. //
  389. // // for SLERP<Real>::EstimateRPH
  390. // omcosAH[i0] = 1 - cosAH[i0];
  391. // }
  392. template <typename Real>
  393. Quaternion<Real> SlerpRPH(Real t, Quaternion<Real> const& q0, Quaternion<Real> const& q1,
  394. Quaternion<Real> const& qh, Real cosAH)
  395. {
  396. Real f0, f1;
  397. Real twoT = static_cast<Real>(2) * t;
  398. if (twoT <= static_cast<Real>(1))
  399. {
  400. ChebyshevRatio<Real>::Get(twoT, cosAH, f0, f1);
  401. return q0 * f0 + qh * f1;
  402. }
  403. else
  404. {
  405. ChebyshevRatio<Real>::Get(twoT - static_cast<Real>(1), cosAH, f0, f1);
  406. return qh * f0 + q1 * f1;
  407. }
  408. }
  409. }