PageRenderTime 147ms CodeModel.GetById 24ms RepoModel.GetById 6ms app.codeStats 0ms

/extern/prmath/quaternion.hpp

https://github.com/joeld42/luddite
C++ Header | 557 lines | 389 code | 84 blank | 84 comment | 32 complexity | bb06c423fc84deae79438856ba1d60c5 MD5 | raw file
Possible License(s): MIT
  1. /*
  2. Twilight Prophecy SDK
  3. A multi-platform development system for virtual reality and multimedia.
  4. Copyright (C) 1997-2003 Twilight 3D Finland Oy Ltd.
  5. */
  6. #ifndef PRMATH_QUATERNION_HPP
  7. #define PRMATH_QUATERNION_HPP
  8. #include "minmax.hpp"
  9. #include <cmath>
  10. #include <limits>
  11. #include "vector3.hpp"
  12. #include "euler.hpp"
  13. #include "matrix4x4.hpp"
  14. namespace prmath
  15. {
  16. template <typename T>
  17. struct Matrix4x4;
  18. template <typename T>
  19. struct Quaternion
  20. {
  21. // members
  22. T x;
  23. T y;
  24. T z;
  25. T w;
  26. // constructors
  27. Quaternion()
  28. {
  29. }
  30. Quaternion(const T& qx, const T& qy, const T& qz, const T& qw)
  31. : x(qx), y(qy), z(qz), w(qw)
  32. {
  33. }
  34. Quaternion(const T v[])
  35. : x(v[0]), y(v[1]), z(v[2]), w(v[3])
  36. {
  37. }
  38. Quaternion(const Quaternion& q)
  39. : x(q.x), y(q.y), z(q.z), w(q.w)
  40. {
  41. }
  42. Quaternion(const T& angle, const Vector3<T>& axis)
  43. {
  44. SetAngleAxis(angle,axis);
  45. }
  46. Quaternion(const Matrix4x4<T>& u)
  47. {
  48. *this = u;
  49. }
  50. // operators
  51. Quaternion operator + () const
  52. {
  53. return *this;
  54. }
  55. Quaternion operator - () const
  56. {
  57. return Quaternion(-x, -y, -z, -w);
  58. }
  59. Quaternion operator + (const Quaternion& q) const
  60. {
  61. return Quaternion(x + q.x, y + q.y, z + q.z, w + q.w);
  62. }
  63. Quaternion operator - (const Quaternion& q) const
  64. {
  65. return Quaternion(x - q.x, y - q.y, z - q.z, w - q.w);
  66. }
  67. Quaternion operator * (const Quaternion& q) const
  68. {
  69. return Quaternion(
  70. w*q.x + x*q.w + y*q.z - z*q.y,
  71. w*q.y + y*q.w + z*q.x - x*q.z,
  72. w*q.z + z*q.w + x*q.y - y*q.x,
  73. w*q.w - x*q.x - y*q.y - z*q.z);
  74. }
  75. Quaternion operator * (const T& s) const
  76. {
  77. return Quaternion(x * s, y * s, z * s, w * s);
  78. }
  79. Quaternion& operator += (const Quaternion& q)
  80. {
  81. x += q.x;
  82. y += q.y;
  83. z += q.z;
  84. w += q.w;
  85. return *this;
  86. }
  87. Quaternion& operator -= (const Quaternion& q)
  88. {
  89. x -= q.x;
  90. y -= q.y;
  91. z -= q.z;
  92. w -= q.w;
  93. return *this;
  94. }
  95. Quaternion& operator *= (const Quaternion& q)
  96. {
  97. T sx = w*q.x + x*q.w + y*q.z - z*q.y;
  98. T sy = w*q.y + y*q.w + z*q.x - x*q.z;
  99. T sz = w*q.z + z*q.w + x*q.y - y*q.x;
  100. T sw = w*q.w - x*q.x - y*q.y - z*q.z;
  101. x = sx;
  102. y = sy;
  103. z = sz;
  104. w = sw;
  105. return *this;
  106. }
  107. Quaternion& operator *= (const T& s)
  108. {
  109. x *= s;
  110. y *= s;
  111. z *= s;
  112. w *= s;
  113. return *this;
  114. }
  115. Quaternion& operator = (const Quaternion& q)
  116. {
  117. x = q.x;
  118. y = q.y;
  119. z = q.z;
  120. w = q.w;
  121. return *this;
  122. }
  123. void operator = (const Matrix4x4<T>& u)
  124. {
  125. T tr = u.m44[0][0] + u.m44[1][1] + u.m44[2][2];
  126. if ( tr > 0 )
  127. {
  128. T s = static_cast<T>(sqrt(tr + 1));
  129. w = s * static_cast<T>(0.5);
  130. s = static_cast<T>(0.5) / s;
  131. x = (u.m44[1][2] - u.m44[2][1]) * s;
  132. y = (u.m44[2][0] - u.m44[0][2]) * s;
  133. z = (u.m44[0][1] - u.m44[1][0]) * s;
  134. }
  135. else
  136. {
  137. int i = 0;
  138. if ( u.m44[1][1] > u.m44[0][0] ) i = 1;
  139. if ( u.m44[2][2] > u.m44[i][i] ) i = 2;
  140. int j = i + 1; if ( j > 2 ) j = 0;
  141. int k = j + 1; if ( k > 2 ) k = 0;
  142. T s = static_cast<T>(sqrt(u.m44[i][i] - u.m44[j][j] - u.m44[k][k] + 1));
  143. if ( s < std::numeric_limits<T>::epsilon() )
  144. {
  145. x = y = z = 0;
  146. w = 1;
  147. }
  148. else
  149. {
  150. T* pq = reinterpret_cast<T*>(this);
  151. pq[i] = s * static_cast<T>(0.5);
  152. s = static_cast<T>(0.5) / s;
  153. pq[3] = (u.m44[j][k] - u.m44[k][j]) * s;
  154. pq[j] = (u.m44[i][j] + u.m44[j][i]) * s;
  155. pq[k] = (u.m44[i][k] + u.m44[k][i]) * s;
  156. }
  157. }
  158. }
  159. bool operator == (const Quaternion& q) const
  160. {
  161. return x == q.x && y == q.y && z == q.z && w == q.w;
  162. }
  163. bool operator != (const Quaternion& q) const
  164. {
  165. return x != q.x || y != q.y || z != q.z || w != q.w;
  166. }
  167. // methods
  168. void SetQuaternion(const T& qx, const T& qy, const T& qz, const T& qw)
  169. {
  170. x = qx;
  171. y = qy;
  172. z = qz;
  173. w = qw;
  174. }
  175. void SetAngleAxis(const T& angle, const Vector3<T>& axis)
  176. {
  177. T theta = angle * static_cast<T>(0.5);
  178. T s = static_cast<T>(sin(theta) / Length(axis));
  179. T c = static_cast<T>(cos(theta));
  180. x = axis.x * s;
  181. y = axis.y * s;
  182. z = axis.z * s;
  183. w = c;
  184. }
  185. void GetAngleAxis(T& angle, Vector3<T>& axis) const
  186. {
  187. T s = 1 / static_cast<T>(sqrt(1 - w*w));
  188. angle = static_cast<T>(acos(w) * 2.0);
  189. axis.x = x * s;
  190. axis.y = y * s;
  191. axis.z = z * s;
  192. }
  193. void SetEuler(const Vector3<T>& anglevec, EulerOrder euler)
  194. {
  195. T ex = 0;
  196. T ey = 0;
  197. T ez = 0;
  198. switch ( euler )
  199. {
  200. case EULER_XYZ: ex = anglevec.x; ey = anglevec.y; ez = anglevec.z; break;
  201. case EULER_XZY: ex = anglevec.x; ey = anglevec.z; ez = anglevec.y; break;
  202. case EULER_YXZ: ex = anglevec.y; ey = anglevec.x; ez = anglevec.z; break;
  203. case EULER_YZX: ex = anglevec.y; ey = anglevec.z; ez = anglevec.x; break;
  204. case EULER_ZXY: ex = anglevec.z; ey = anglevec.x; ez = anglevec.y; break;
  205. case EULER_ZYX: ex = anglevec.z; ey = anglevec.y; ez = anglevec.x; break;
  206. }
  207. ex *= static_cast<T>(0.5);
  208. ey *= static_cast<T>(0.5);
  209. ez *= static_cast<T>(0.5);
  210. T cx = static_cast<T>(cos(ex));
  211. T cy = static_cast<T>(cos(ey));
  212. T cz = static_cast<T>(cos(ez));
  213. T sx = static_cast<T>(sin(ex));
  214. T sy = static_cast<T>(sin(ey));
  215. T sz = static_cast<T>(sin(ez));
  216. T cycz = cy * cz;
  217. T sysz = sy * sz;
  218. T sycz = sy * cz;
  219. T cysz = cy * sz;
  220. x = sx * cycz - cx * sysz;
  221. y = sx * cysz + cx * sycz;
  222. z = cx * cysz - sx * sycz;
  223. w = cx * cycz + sx * sysz;
  224. }
  225. T Norm() const
  226. {
  227. return x*x + y*y + z*z + w*w;
  228. }
  229. T Mod() const
  230. {
  231. return static_cast<T>(sqrt(x*x + y*y + z*z + w*w));
  232. }
  233. void Identity()
  234. {
  235. x = y = z = 0;
  236. w = 1;
  237. }
  238. void Normalize()
  239. {
  240. T s = Norm();
  241. if ( s == 0 )
  242. {
  243. x = y = z = 0;
  244. w = 1;
  245. }
  246. else
  247. {
  248. T is = 1 / static_cast<T>(sqrt(s));
  249. x *= is;
  250. y *= is;
  251. z *= is;
  252. w *= is;
  253. }
  254. }
  255. void Conjugate()
  256. {
  257. x = -x;
  258. y = -y;
  259. z = -z;
  260. }
  261. void Inverse()
  262. {
  263. T n = -1 / Norm();
  264. x *= n;
  265. y *= n;
  266. z *= n;
  267. w *= -n;
  268. }
  269. void Negate()
  270. {
  271. T nim = -1 / Mod();
  272. x *= nim;
  273. y *= nim;
  274. z *= nim;
  275. w *= -nim;
  276. }
  277. void Exp()
  278. {
  279. T s = static_cast<T>(sqrt(x*x + y*y + z*z));
  280. w = static_cast<T>(cos(s));
  281. if ( s > std::numeric_limits<T>::epsilon() * 100 )
  282. {
  283. s = static_cast<T>(sin(s)) / s;
  284. x *= s;
  285. y *= s;
  286. z *= s;
  287. }
  288. }
  289. void Log()
  290. {
  291. T s = w ? static_cast<T>(atan2(sqrt(x*x + y*y + z*z),w)) : static_cast<T>(pi * 2);
  292. x *= s;
  293. y *= s;
  294. z *= s;
  295. w = 0;
  296. }
  297. void LnDif(const Quaternion& q)
  298. {
  299. Quaternion invp = *this;
  300. invp.Inverse();
  301. Quaternion mulp = invp * q;
  302. T length = static_cast<T>(sqrt(mulp.x*mulp.x + mulp.y*mulp.y + mulp.z*mulp.z));
  303. T scale = x*x + y*y + z*z + w*w;
  304. T mval = scale ? static_cast<T>(atan2(length,scale)) : static_cast<T>(pi * 2);
  305. if ( length != 0 ) mval /= length;
  306. x = mulp.x * mval;
  307. y = mulp.y * mval;
  308. z = mulp.z * mval;
  309. w = 0;
  310. }
  311. };
  312. // inline functions
  313. template <typename T>
  314. inline T DotProduct(const Quaternion<T>& a, const Quaternion<T>& b)
  315. {
  316. return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
  317. }
  318. template <typename T>
  319. inline Quaternion<T> Lerp(const Quaternion<T>& a, const Quaternion<T>& b, const T& time)
  320. {
  321. return Quaternion<T>(
  322. a.x + (b.x - a.x) * time,
  323. a.y + (b.y - a.y) * time,
  324. a.z + (b.z - a.z) * time,
  325. a.w + (b.w - a.w) * time);
  326. }
  327. template <typename T>
  328. inline Quaternion<T> Slerp(const Quaternion<T>& a, const Quaternion<T>& b, const T& time)
  329. {
  330. // ====================================================
  331. // AART - Advanced Animation and Rendering Techniques
  332. // ====================================================
  333. T cosom = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
  334. if ( (1 + cosom) > std::numeric_limits<T>::epsilon() )
  335. {
  336. T sp;
  337. T sq;
  338. if ( (1 - cosom) > std::numeric_limits<T>::epsilon() )
  339. {
  340. double omega = acos(cosom);
  341. double sinom = 1.0 / sin(omega);
  342. sp = static_cast<T>(sin((1 - time) * omega) * sinom);
  343. sq = static_cast<T>(sin(time * omega) * sinom);
  344. }
  345. else
  346. {
  347. sp = 1 - time;
  348. sq = time;
  349. }
  350. return Quaternion<T>(
  351. a.x*sp + b.x*sq,
  352. a.y*sp + b.y*sq,
  353. a.z*sp + b.z*sq,
  354. a.w*sp + b.w*sq);
  355. }
  356. else
  357. {
  358. T halfpi = static_cast<T>(pi / 2);
  359. T sp = static_cast<T>(sin((1 - time) * halfpi));
  360. T sq = static_cast<T>(sin(time * halfpi));
  361. return Quaternion<T>(
  362. a.x*sp - a.y*sq,
  363. a.y*sp + a.x*sq,
  364. a.z*sp - a.w*sq,
  365. a.z);
  366. }
  367. // ====================================================
  368. // Rusty's code
  369. // ====================================================
  370. /*
  371. T om, sinom;
  372. T sp, sq;
  373. Quaternion<T> qq, qret;
  374. T l = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
  375. if ( (1 + l) > std::numeric_limits<T>::epsilon() )
  376. {
  377. T al = fabsf(l);
  378. if ( al > 1 )
  379. l /= al;
  380. om = static_cast<T>(acosf(l));
  381. sinom = static_cast<T>(sin(om));
  382. if ( fabsf(sinom) > std::numeric_limits<T>::epsilon() )
  383. {
  384. sp = static_cast<T>(sin((1-time)*om)) / sinom;
  385. sq = static_cast<T>(sin(time*om)) / sinom;
  386. }
  387. else
  388. {
  389. sp = 1 - time;
  390. sq = time;
  391. }
  392. qret.x = sp * a.x + sq * b.x;
  393. qret.y = sp * a.y + sq * b.y;
  394. qret.z = sp * a.z + sq * b.z;
  395. qret.w = sp * a.w + sq * b.w;
  396. }
  397. else
  398. {
  399. qq.x = -a.y;
  400. qq.y = a.x;
  401. qq.z = -a.w;
  402. qq.w = a.z;
  403. T twopi = static_cast<T>(pi * 2);
  404. sp = static_cast<T>(sin((1-time) * twopi));
  405. sq = static_cast<T>(sin(time * twopi));
  406. qret.x = sp * a.x + sq * b.x;
  407. qret.y = sp * a.y + sq * b.y;
  408. qret.z = sp * a.z + sq * b.z;
  409. qret.w = sp * a.w + sq * b.w;
  410. }
  411. return qret;
  412. */
  413. // ====================================================
  414. // Original Version
  415. // ====================================================
  416. /*
  417. T cs = DotProduct(a,b);
  418. T sn = static_cast<T>(sqrt(fabs(1-cs*cs)));
  419. if ( fabs(sn) < std::numeric_limits<T>::epsilon() * 100 )
  420. return a;
  421. if ( cs < 0 )
  422. cs = -cs;
  423. T angle = static_cast<T>(atan2(sn,cs));
  424. sn = 1 / sn;
  425. return a * sn * static_cast<T>(sin(angle*(1-time))) + b * sn * static_cast<T>(sin(angle*time));
  426. */
  427. }
  428. template <typename T>
  429. inline Quaternion<T> Slerp(const Quaternion<T>& a, const Quaternion<T>& b, const T& time, int spin)
  430. {
  431. T bflip = 1;
  432. T tcos = DotProduct(a,b);
  433. if ( tcos < 0 )
  434. {
  435. tcos = -tcos;
  436. bflip = -1;
  437. }
  438. if ( (1 - tcos) < std::numeric_limits<T>::epsilon() * 100 )
  439. {
  440. // linear interpolate
  441. return a * (1 - time) + b * (time * bflip);
  442. }
  443. T theta = static_cast<T>(acos(tcos));
  444. T phi = theta + static_cast<T>(spin * pi);
  445. T tsin = static_cast<T>(sin(theta));
  446. T beta = static_cast<T>(sin(theta - time*phi)) / tsin;
  447. T alpha = static_cast<T>(sin(time*phi)) / tsin * bflip;
  448. return a * beta + b * alpha;
  449. }
  450. template <typename T>
  451. inline Quaternion<T> Squad(const Quaternion<T>& p, const Quaternion<T>& a, const Quaternion<T>& b, const Quaternion<T>& q, const T& time)
  452. {
  453. Quaternion<T> qa = Slerp(p,q,time,0);
  454. Quaternion<T> qb = Slerp(a,b,time,0);
  455. T qtime = 2 * time * (1 - time);
  456. return Slerp(qa,qb,qtime,0);
  457. }
  458. } // namespace prmath
  459. #ifndef PRMATH_NOTYPENAME
  460. typedef prmath::Quaternion<float> quat4f;
  461. typedef prmath::Quaternion<double> quat4d;
  462. #endif // PRMATH_NOTYPENAME
  463. #endif