Quaternion.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*
  2. Copyright (c) 2009 Christopher A. Taylor. All rights reserved.
  3. Redistribution and use in source and binary forms, with or without
  4. modification, are permitted provided that the following conditions are met:
  5. * Redistributions of source code must retain the above copyright notice,
  6. this list of conditions and the following disclaimer.
  7. * Redistributions in binary form must reproduce the above copyright notice,
  8. this list of conditions and the following disclaimer in the documentation
  9. and/or other materials provided with the distribution.
  10. * Neither the name of LibCat nor the names of its contributors may be used
  11. to endorse or promote products derived from this software without
  12. specific prior written permission.
  13. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  14. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  17. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  18. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  19. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  20. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  21. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  22. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  23. POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. /*
  26. Based on code from "Physics for Game Developers", David M. Bourg
  27. slerp() code adapted from this website:
  28. http://www.number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/index.html
  29. */
  30. #ifndef CAT_QUATERNION_HPP
  31. #define CAT_QUATERNION_HPP
  32. #include <cat/gfx/Vector.hpp>
  33. #include <cat/gfx/Matrix.hpp>
  34. namespace cat {
  35. // Generic quaternion class for linear algebra
  36. template <typename Scalar, typename Double>
  37. class Quaternion
  38. {
  39. protected:
  40. // Backed by a 4D vector with elements arranged as <x,y,z,w>
  41. Vector<4, Scalar, Double> _v;
  42. public:
  43. // Short-hand for the current quaternion type
  44. typedef Quaternion<Scalar, Double> mytype;
  45. // Short-hand for the vector type
  46. typedef Vector<3, Scalar, Double> vectype;
  47. // Uninitialized quaternion is not cleared
  48. Quaternion() { }
  49. // Copy constructor
  50. Quaternion(const mytype &u)
  51. : _v(u._v)
  52. {
  53. }
  54. // Initialization constructor
  55. Quaternion(const vectype &v, Scalar w)
  56. : _v(v)
  57. {
  58. }
  59. // Initialization constructor
  60. Quaternion(Scalar x, Scalar y, Scalar z, Scalar w)
  61. : _v(x, y, z, w)
  62. {
  63. }
  64. // Assignment operator
  65. mytype &operator=(const mytype &u)
  66. {
  67. _v.copy(u._v);
  68. return *this;
  69. }
  70. // Convert from Euler angle representation
  71. // Pre-condition: angles in radians (see Deg2Rad in Scalar.hpp)
  72. void setFromEulerAngles(f32 xroll, f32 ypitch, f32 zyaw)
  73. {
  74. f64 croll = cos(0.5f * xroll);
  75. f64 cpitch = cos(0.5f * ypitch);
  76. f64 cyaw = cos(0.5f * zyaw);
  77. f64 sroll = sin(0.5f * xroll);
  78. f64 spitch = sin(0.5f * ypitch);
  79. f64 syaw = sin(0.5f * zyaw);
  80. f64 cyawcpitch = cyaw * cpitch;
  81. f64 syawspitch = syaw * spitch;
  82. f64 cyawspitch = cyaw * spitch;
  83. f64 syawcpitch = syaw * cpitch;
  84. _v(0) = static_cast<Scalar>( cyawcpitch * sroll - syawspitch * croll );
  85. _v(1) = static_cast<Scalar>( cyawspitch * croll + syawcpitch * sroll );
  86. _v(2) = static_cast<Scalar>( syawcpitch * croll - cyawspitch * sroll );
  87. _v(3) = static_cast<Scalar>( cyawcpitch * croll + syawspitch * sroll );
  88. _v.normalize();
  89. }
  90. // Convert from axis-angle representation
  91. // Pre-condition: axis must be unit-length
  92. void setFromAxisAngle(const vectype &axis, f32 angle)
  93. {
  94. angle *= 0.5f;
  95. Scalar theta = static_cast<Scalar>( sin(angle) );
  96. _v(0) = theta * axis(0);
  97. _v(1) = theta * axis(1);
  98. _v(2) = theta * axis(2);
  99. _v(3) = static_cast<Scalar>( cos(angle) );
  100. }
  101. // Conjugate
  102. mytype operator~() const
  103. {
  104. return mytype(-_v(0), -_v(1), -_v(2), _v(3));
  105. }
  106. // Conjugate in-place
  107. mytype &conjugate() const
  108. {
  109. _v(0) = -_v(0);
  110. _v(1) = -_v(1);
  111. _v(2) = -_v(2);
  112. return *this;
  113. }
  114. // Multiply by quaternion
  115. mytype operator*(const mytype &u)
  116. {
  117. // Cache each of the elements since each is used 4 times
  118. Double x1 = _v(0), x2 = u._v(0);
  119. Double y1 = _v(1), y2 = u._v(1);
  120. Double z1 = _v(2), z2 = u._v(2);
  121. Double w1 = _v(3), w2 = u._v(3);
  122. // Quaternion multiplication formula:
  123. Scalar x3 = static_cast<Scalar>( w1*x2 + x1*w2 + y1*z2 - z1*y2 );
  124. Scalar y3 = static_cast<Scalar>( w1*y2 - x1*z2 + y1*w2 + z1*x2 );
  125. Scalar z3 = static_cast<Scalar>( w1*z2 + x1*y2 - y1*x2 + z1*w2 );
  126. Scalar w3 = static_cast<Scalar>( w1*w2 - x1*x2 - y1*y2 - z1*z2 );
  127. return mytype(x3, y3, z3, w3);
  128. }
  129. // Multiply by quaternion in-place: this = this * u
  130. mytype &operator*=(const mytype &u)
  131. {
  132. // Cache each of the elements since each is used 4 times
  133. Double x1 = _v(0), x2 = u._v(0);
  134. Double y1 = _v(1), y2 = u._v(1);
  135. Double z1 = _v(2), z2 = u._v(2);
  136. Double w1 = _v(3), w2 = u._v(3);
  137. // Quaternion multiplication formula:
  138. _v(0) = static_cast<Scalar>( w1*x2 + x1*w2 + y1*z2 - z1*y2 );
  139. _v(1) = static_cast<Scalar>( w1*y2 - x1*z2 + y1*w2 + z1*x2 );
  140. _v(2) = static_cast<Scalar>( w1*z2 + x1*y2 - y1*x2 + z1*w2 );
  141. _v(3) = static_cast<Scalar>( w1*w2 - x1*x2 - y1*y2 - z1*z2 );
  142. return *this;
  143. }
  144. // Multiply by quaternion in-place: this = u * this
  145. mytype &postMultiply(const mytype &u)
  146. {
  147. // Cache each of the elements since each is used 4 times
  148. Double x2 = _v(0), x1 = u._v(0);
  149. Double y2 = _v(1), y1 = u._v(1);
  150. Double z2 = _v(2), z1 = u._v(2);
  151. Double w2 = _v(3), w1 = u._v(3);
  152. // Quaternion multiplication formula:
  153. _v(0) = static_cast<Scalar>( w1*x2 + x1*w2 + y1*z2 - z1*y2 );
  154. _v(1) = static_cast<Scalar>( w1*y2 - x1*z2 + y1*w2 + z1*x2 );
  155. _v(2) = static_cast<Scalar>( w1*z2 + x1*y2 - y1*x2 + z1*w2 );
  156. _v(3) = static_cast<Scalar>( w1*w2 - x1*x2 - y1*y2 - z1*z2 );
  157. return *this;
  158. }
  159. // Rotate given vector in-place
  160. void rotate(vectype &u)
  161. {
  162. // Implements the simple formula: (q1 * u2 * ~q1).getVector()
  163. // Cache each of the elements since each is used 4 times
  164. Double x1 = _v(0), x2 = u(0);
  165. Double y1 = _v(1), y2 = u(1);
  166. Double z1 = _v(2), z2 = u(2);
  167. Double w1 = _v(3);
  168. // Quaternion-vector multiplication formula (q3 = q1 * u2):
  169. Double x3 = w1*x2 + y1*z2 - z1*y2;
  170. Double y3 = w1*y2 - x1*z2 + z1*x2;
  171. Double z3 = w1*z2 + x1*y2 - y1*x2;
  172. Double w3 = -(x1*x2 + y1*y2 + z1*z2);
  173. // Quaternion multiplication formula (q2' = q3 * ~q1):
  174. u(0) = static_cast<Scalar>( w1*x3 - x1*w3 + y1*z3 - z1*y3 );
  175. u(1) = static_cast<Scalar>( w1*y3 - x1*z3 - y1*w3 + z1*x3 );
  176. u(2) = static_cast<Scalar>( w1*z3 + x1*y3 - y1*x3 - z1*w3 );
  177. }
  178. // NLERP: Very fast, non-constant velocity and torque-minimal
  179. // Precondition: q1, q2 are unit length
  180. friend void nlerp(const mytype &q1, const mytype &q2, Scalar t, mytype &result)
  181. {
  182. // Linearly interpolate and normalize result
  183. // This formula is a little more work than "q1 + (q2 - q1) * t"
  184. // but less likely to lose precision when it matters
  185. // Cosine of phi, the angle between the two vectors
  186. Double cos_phi = q1._v.dotProduct(q2._v);
  187. // I have read this may try to rotate around the "long way" sometimes and to
  188. // fix that we check if cos(phi) is negative and invert one of the inputs.
  189. if (cos_phi < 0.0)
  190. {
  191. result._v = -q1._v;
  192. }
  193. else
  194. {
  195. result._v = q1._v;
  196. }
  197. // Simple linear interpolation
  198. Scalar scale0 = static_cast<Scalar>(1) - t;
  199. Scalar scale1 = t;
  200. result._v *= scale0;
  201. result._v += q2._v * scale1;
  202. result._v.normalize();
  203. }
  204. // SLERP: Slower, constant velocity and torque-minimal
  205. // Precondition: q1, q2 are unit length
  206. friend void slerp(const mytype &q1, const mytype &q2, Scalar t, mytype &result)
  207. {
  208. // Cosine of phi, the angle between the two vectors
  209. Double cos_phi = q1._v.dotProduct(q2._v);
  210. // I have read this may try to rotate around the "long way" sometimes and to
  211. // fix that we check if cos(phi) is negative and invert one of the inputs.
  212. if (cos_phi < 0.0)
  213. {
  214. cos_phi = -cos_phi;
  215. result._v = -q1._v;
  216. }
  217. else
  218. {
  219. result._v = q1._v;
  220. }
  221. // Default to simple linear interpolation
  222. Scalar scale0 = static_cast<Scalar>(1) - t;
  223. Scalar scale1 = t;
  224. // If the distance is not small we need to do full slerp:
  225. if (cos_phi < 0.9995)
  226. {
  227. // cos_phi is guaranteed to be within the domain of acos(), 0..1
  228. Double phi = static_cast<Double>( acos(cos_phi) );
  229. Double inv_sin_phi = static_cast<Double>(1) / sin(phi);
  230. scale0 = static_cast<Scalar>( sin(scale0 * phi) * inv_sin_phi );
  231. scale1 = static_cast<Scalar>( sin(scale1 * phi) * inv_sin_phi );
  232. }
  233. result._v *= scale0;
  234. result._v += q2._v * scale1;
  235. result._v.normalize();
  236. }
  237. // Get angle of rotation
  238. Scalar getAngle()
  239. {
  240. return static_cast<Scalar>( 2 ) * static_cast<Scalar>( acos(_v(3)) );
  241. }
  242. // Get axis of rotation
  243. vectype getAxis()
  244. {
  245. return vectype(_v(0), _v(1), _v(2)).normalize();
  246. }
  247. // Get matrix form of the rotation represented by this quaternion
  248. void getMatrix4x4(Matrix<4, 4, Scalar> &result)
  249. {
  250. Double dx = _v(0);
  251. Double dy = _v(1);
  252. Double dz = _v(2);
  253. Double dw = _v(3);
  254. Double x2 = dx * dx;
  255. Double y2 = dy * dy;
  256. Double z2 = dz * dz;
  257. Double xy = dx * dy;
  258. Double yz = dy * dz;
  259. Double zx = dz * dx;
  260. Double xw = dx * dw;
  261. Double yw = dy * dw;
  262. Double zw = dz * dw;
  263. const Double ONE = static_cast<Double>( 1 );
  264. const Double TWO = static_cast<Double>( 2 );
  265. // Result is written in OpenGL column-major matrix order:
  266. result( 0) = static_cast<Scalar>( ONE - TWO * (y2 + z2) );
  267. result( 1) = static_cast<Scalar>( TWO * (xy - zw) );
  268. result( 2) = static_cast<Scalar>( TWO * (zx + yw) );
  269. result( 3) = static_cast<Scalar>( 0 );
  270. result( 4) = static_cast<Scalar>( TWO * (xy + zw) );
  271. result( 5) = static_cast<Scalar>( ONE - TWO * (x2 + z2) );
  272. result( 6) = static_cast<Scalar>( TWO * (yz - xw) );
  273. result( 7) = static_cast<Scalar>( 0 );
  274. result( 8) = static_cast<Scalar>( TWO * (zx - yw) );
  275. result( 9) = static_cast<Scalar>( TWO * (yz + xw) );
  276. result(10) = static_cast<Scalar>( ONE - TWO * (x2 + y2) );
  277. result(11) = static_cast<Scalar>( 0 );
  278. result(12) = static_cast<Scalar>( 0 );
  279. result(13) = static_cast<Scalar>( 0 );
  280. result(14) = static_cast<Scalar>( 0 );
  281. result(15) = static_cast<Scalar>( ONE );
  282. }
  283. // Get Euler angles
  284. vectype Quaternion::getEulerAngles()
  285. {
  286. Double dx = _v(0);
  287. Double dy = _v(1);
  288. Double dz = _v(2);
  289. Double dw = _v(3);
  290. Double x2 = dx * dx;
  291. Double y2 = dy * dy;
  292. Double z2 = dz * dz;
  293. Double w2 = dw * dw;
  294. Double xy = dx * dy;
  295. Double yz = dy * dz;
  296. Double xw = dx * dw;
  297. Double yw = dy * dw;
  298. Double zw = dz * dw;
  299. const Double TWO = static_cast<Double>( 2 );
  300. Double r11 = w2 + x2 - y2 - z2;
  301. Double r21 = TWO * (xy + zw);
  302. Double r31 = TWO * (xy - yw);
  303. Double r32 = TWO * (yz + xw);
  304. Double r33 = w2 - x2 - y2 + z2;
  305. Double tmp = fabs(r31);
  306. const Double LIMIT = static_cast<Double>( 0.999999 );
  307. if (tmp > LIMIT)
  308. {
  309. Double xz = dx * dz;
  310. Double r12 = TWO * (yz - zw);
  311. Double r13 = TWO * (xz + yw);
  312. return vectype(static_cast<Scalar>( 0 ),
  313. static_cast<Scalar>( -CAT_HALF_PI_64 * r31 / tmp ),
  314. static_cast<Scalar>( atan2(-r12, -r31 * r13) ));
  315. }
  316. return vectype(static_cast<Scalar>( atan2(r32, r33) ),
  317. static_cast<Scalar>( asin(-r31) ),
  318. static_cast<Scalar>( atan2(r21, r11) ));
  319. }
  320. };
  321. // Short-hand for common usages:
  322. typedef Quaternion<f32, f64> Quaternion4f;
  323. typedef Quaternion<f64, f64> Quaternion4d;
  324. } // namespace cat
  325. #endif // CAT_QUATERNION_HPP
粤ICP备19079148号