CmQuaternion.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. /*
  2. -----------------------------------------------------------------------------
  3. This source file is part of OGRE
  4. (Object-oriented Graphics Rendering Engine)
  5. For the latest info, see http://www.ogre3d.org/
  6. Copyright (c) 2000-2011 Torus Knot Software Ltd
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in
  14. all copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. THE SOFTWARE.
  22. -----------------------------------------------------------------------------
  23. */
  24. // NOTE THAT THIS FILE IS BASED ON MATERIAL FROM:
  25. // Geometric Tools, LLC
  26. // Copyright (c) 1998-2010
  27. // Distributed under the Boost Software License, Version 1.0.
  28. // http://www.boost.org/LICENSE_1_0.txt
  29. // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  30. #include "CmQuaternion.h"
  31. #include "CmMath.h"
  32. #include "CmMatrix3.h"
  33. #include "CmVector3.h"
  34. namespace CamelotEngine {
  35. const float Quaternion::ms_fEpsilon = 1e-03f;
  36. const Quaternion Quaternion::ZERO(0.0,0.0,0.0,0.0);
  37. const Quaternion Quaternion::IDENTITY(1.0,0.0,0.0,0.0);
  38. //-----------------------------------------------------------------------
  39. void Quaternion::FromRotationMatrix (const Matrix3& kRot)
  40. {
  41. // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
  42. // article "Quaternion Calculus and Fast Animation".
  43. float fTrace = kRot[0][0]+kRot[1][1]+kRot[2][2];
  44. float fRoot;
  45. if ( fTrace > 0.0 )
  46. {
  47. // |w| > 1/2, may as well choose w > 1/2
  48. fRoot = Math::Sqrt(fTrace + 1.0f); // 2w
  49. w = 0.5f*fRoot;
  50. fRoot = 0.5f/fRoot; // 1/(4w)
  51. x = (kRot[2][1]-kRot[1][2])*fRoot;
  52. y = (kRot[0][2]-kRot[2][0])*fRoot;
  53. z = (kRot[1][0]-kRot[0][1])*fRoot;
  54. }
  55. else
  56. {
  57. // |w| <= 1/2
  58. static size_t s_iNext[3] = { 1, 2, 0 };
  59. size_t i = 0;
  60. if ( kRot[1][1] > kRot[0][0] )
  61. i = 1;
  62. if ( kRot[2][2] > kRot[i][i] )
  63. i = 2;
  64. size_t j = s_iNext[i];
  65. size_t k = s_iNext[j];
  66. fRoot = Math::Sqrt(kRot[i][i]-kRot[j][j]-kRot[k][k] + 1.0f);
  67. float* apkQuat[3] = { &x, &y, &z };
  68. *apkQuat[i] = 0.5f*fRoot;
  69. fRoot = 0.5f/fRoot;
  70. w = (kRot[k][j]-kRot[j][k])*fRoot;
  71. *apkQuat[j] = (kRot[j][i]+kRot[i][j])*fRoot;
  72. *apkQuat[k] = (kRot[k][i]+kRot[i][k])*fRoot;
  73. }
  74. }
  75. //-----------------------------------------------------------------------
  76. void Quaternion::ToRotationMatrix (Matrix3& kRot) const
  77. {
  78. float fTx = x+x;
  79. float fTy = y+y;
  80. float fTz = z+z;
  81. float fTwx = fTx*w;
  82. float fTwy = fTy*w;
  83. float fTwz = fTz*w;
  84. float fTxx = fTx*x;
  85. float fTxy = fTy*x;
  86. float fTxz = fTz*x;
  87. float fTyy = fTy*y;
  88. float fTyz = fTz*y;
  89. float fTzz = fTz*z;
  90. kRot[0][0] = 1.0f-(fTyy+fTzz);
  91. kRot[0][1] = fTxy-fTwz;
  92. kRot[0][2] = fTxz+fTwy;
  93. kRot[1][0] = fTxy+fTwz;
  94. kRot[1][1] = 1.0f-(fTxx+fTzz);
  95. kRot[1][2] = fTyz-fTwx;
  96. kRot[2][0] = fTxz-fTwy;
  97. kRot[2][1] = fTyz+fTwx;
  98. kRot[2][2] = 1.0f-(fTxx+fTyy);
  99. }
  100. //-----------------------------------------------------------------------
  101. void Quaternion::FromAngleAxis (const Radian& rfAngle,
  102. const Vector3& rkAxis)
  103. {
  104. // assert: axis[] is unit length
  105. //
  106. // The quaternion representing the rotation is
  107. // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
  108. Radian fHalfAngle ( 0.5*rfAngle );
  109. float fSin = Math::Sin(fHalfAngle);
  110. w = Math::Cos(fHalfAngle);
  111. x = fSin*rkAxis.x;
  112. y = fSin*rkAxis.y;
  113. z = fSin*rkAxis.z;
  114. }
  115. //-----------------------------------------------------------------------
  116. void Quaternion::ToAngleAxis (Radian& rfAngle, Vector3& rkAxis) const
  117. {
  118. // The quaternion representing the rotation is
  119. // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
  120. float fSqrLength = x*x+y*y+z*z;
  121. if ( fSqrLength > 0.0 )
  122. {
  123. rfAngle = 2.0*Math::ACos(w);
  124. float fInvLength = Math::InvSqrt(fSqrLength);
  125. rkAxis.x = x*fInvLength;
  126. rkAxis.y = y*fInvLength;
  127. rkAxis.z = z*fInvLength;
  128. }
  129. else
  130. {
  131. // angle is 0 (mod 2*pi), so any axis will do
  132. rfAngle = Radian(0.0);
  133. rkAxis.x = 1.0;
  134. rkAxis.y = 0.0;
  135. rkAxis.z = 0.0;
  136. }
  137. }
  138. //-----------------------------------------------------------------------
  139. void Quaternion::FromAxes (const Vector3* akAxis)
  140. {
  141. Matrix3 kRot;
  142. for (size_t iCol = 0; iCol < 3; iCol++)
  143. {
  144. kRot[0][iCol] = akAxis[iCol].x;
  145. kRot[1][iCol] = akAxis[iCol].y;
  146. kRot[2][iCol] = akAxis[iCol].z;
  147. }
  148. FromRotationMatrix(kRot);
  149. }
  150. //-----------------------------------------------------------------------
  151. void Quaternion::FromAxes (const Vector3& xaxis, const Vector3& yaxis, const Vector3& zaxis)
  152. {
  153. Matrix3 kRot;
  154. kRot[0][0] = xaxis.x;
  155. kRot[1][0] = xaxis.y;
  156. kRot[2][0] = xaxis.z;
  157. kRot[0][1] = yaxis.x;
  158. kRot[1][1] = yaxis.y;
  159. kRot[2][1] = yaxis.z;
  160. kRot[0][2] = zaxis.x;
  161. kRot[1][2] = zaxis.y;
  162. kRot[2][2] = zaxis.z;
  163. FromRotationMatrix(kRot);
  164. }
  165. //-----------------------------------------------------------------------
  166. void Quaternion::ToAxes (Vector3* akAxis) const
  167. {
  168. Matrix3 kRot;
  169. ToRotationMatrix(kRot);
  170. for (size_t iCol = 0; iCol < 3; iCol++)
  171. {
  172. akAxis[iCol].x = kRot[0][iCol];
  173. akAxis[iCol].y = kRot[1][iCol];
  174. akAxis[iCol].z = kRot[2][iCol];
  175. }
  176. }
  177. //-----------------------------------------------------------------------
  178. Vector3 Quaternion::xAxis(void) const
  179. {
  180. //float fTx = 2.0*x;
  181. float fTy = 2.0f*y;
  182. float fTz = 2.0f*z;
  183. float fTwy = fTy*w;
  184. float fTwz = fTz*w;
  185. float fTxy = fTy*x;
  186. float fTxz = fTz*x;
  187. float fTyy = fTy*y;
  188. float fTzz = fTz*z;
  189. return Vector3(1.0f-(fTyy+fTzz), fTxy+fTwz, fTxz-fTwy);
  190. }
  191. //-----------------------------------------------------------------------
  192. Vector3 Quaternion::yAxis(void) const
  193. {
  194. float fTx = 2.0f*x;
  195. float fTy = 2.0f*y;
  196. float fTz = 2.0f*z;
  197. float fTwx = fTx*w;
  198. float fTwz = fTz*w;
  199. float fTxx = fTx*x;
  200. float fTxy = fTy*x;
  201. float fTyz = fTz*y;
  202. float fTzz = fTz*z;
  203. return Vector3(fTxy-fTwz, 1.0f-(fTxx+fTzz), fTyz+fTwx);
  204. }
  205. //-----------------------------------------------------------------------
  206. Vector3 Quaternion::zAxis(void) const
  207. {
  208. float fTx = 2.0f*x;
  209. float fTy = 2.0f*y;
  210. float fTz = 2.0f*z;
  211. float fTwx = fTx*w;
  212. float fTwy = fTy*w;
  213. float fTxx = fTx*x;
  214. float fTxz = fTz*x;
  215. float fTyy = fTy*y;
  216. float fTyz = fTz*y;
  217. return Vector3(fTxz+fTwy, fTyz-fTwx, 1.0f-(fTxx+fTyy));
  218. }
  219. //-----------------------------------------------------------------------
  220. void Quaternion::ToAxes (Vector3& xaxis, Vector3& yaxis, Vector3& zaxis) const
  221. {
  222. Matrix3 kRot;
  223. ToRotationMatrix(kRot);
  224. xaxis.x = kRot[0][0];
  225. xaxis.y = kRot[1][0];
  226. xaxis.z = kRot[2][0];
  227. yaxis.x = kRot[0][1];
  228. yaxis.y = kRot[1][1];
  229. yaxis.z = kRot[2][1];
  230. zaxis.x = kRot[0][2];
  231. zaxis.y = kRot[1][2];
  232. zaxis.z = kRot[2][2];
  233. }
  234. //-----------------------------------------------------------------------
  235. Quaternion Quaternion::operator+ (const Quaternion& rkQ) const
  236. {
  237. return Quaternion(w+rkQ.w,x+rkQ.x,y+rkQ.y,z+rkQ.z);
  238. }
  239. //-----------------------------------------------------------------------
  240. Quaternion Quaternion::operator- (const Quaternion& rkQ) const
  241. {
  242. return Quaternion(w-rkQ.w,x-rkQ.x,y-rkQ.y,z-rkQ.z);
  243. }
  244. //-----------------------------------------------------------------------
  245. Quaternion Quaternion::operator* (const Quaternion& rkQ) const
  246. {
  247. // NOTE: Multiplication is not generally commutative, so in most
  248. // cases p*q != q*p.
  249. return Quaternion
  250. (
  251. w * rkQ.w - x * rkQ.x - y * rkQ.y - z * rkQ.z,
  252. w * rkQ.x + x * rkQ.w + y * rkQ.z - z * rkQ.y,
  253. w * rkQ.y + y * rkQ.w + z * rkQ.x - x * rkQ.z,
  254. w * rkQ.z + z * rkQ.w + x * rkQ.y - y * rkQ.x
  255. );
  256. }
  257. //-----------------------------------------------------------------------
  258. Quaternion Quaternion::operator* (float fScalar) const
  259. {
  260. return Quaternion(fScalar*w,fScalar*x,fScalar*y,fScalar*z);
  261. }
  262. //-----------------------------------------------------------------------
  263. Quaternion operator* (float fScalar, const Quaternion& rkQ)
  264. {
  265. return Quaternion(fScalar*rkQ.w,fScalar*rkQ.x,fScalar*rkQ.y,
  266. fScalar*rkQ.z);
  267. }
  268. //-----------------------------------------------------------------------
  269. Quaternion Quaternion::operator- () const
  270. {
  271. return Quaternion(-w,-x,-y,-z);
  272. }
  273. //-----------------------------------------------------------------------
  274. float Quaternion::Dot (const Quaternion& rkQ) const
  275. {
  276. return w*rkQ.w+x*rkQ.x+y*rkQ.y+z*rkQ.z;
  277. }
  278. //-----------------------------------------------------------------------
  279. float Quaternion::Norm () const
  280. {
  281. return w*w+x*x+y*y+z*z;
  282. }
  283. //-----------------------------------------------------------------------
  284. Quaternion Quaternion::Inverse () const
  285. {
  286. float fNorm = w*w+x*x+y*y+z*z;
  287. if ( fNorm > 0.0 )
  288. {
  289. float fInvNorm = 1.0f/fNorm;
  290. return Quaternion(w*fInvNorm,-x*fInvNorm,-y*fInvNorm,-z*fInvNorm);
  291. }
  292. else
  293. {
  294. // return an invalid result to flag the error
  295. return ZERO;
  296. }
  297. }
  298. //-----------------------------------------------------------------------
  299. Quaternion Quaternion::UnitInverse () const
  300. {
  301. // assert: 'this' is unit length
  302. return Quaternion(w,-x,-y,-z);
  303. }
  304. //-----------------------------------------------------------------------
  305. Quaternion Quaternion::Exp () const
  306. {
  307. // If q = A*(x*i+y*j+z*k) where (x,y,z) is unit length, then
  308. // exp(q) = cos(A)+sin(A)*(x*i+y*j+z*k). If sin(A) is near zero,
  309. // use exp(q) = cos(A)+A*(x*i+y*j+z*k) since A/sin(A) has limit 1.
  310. Radian fAngle ( Math::Sqrt(x*x+y*y+z*z) );
  311. float fSin = Math::Sin(fAngle);
  312. Quaternion kResult;
  313. kResult.w = Math::Cos(fAngle);
  314. if ( Math::Abs(fSin) >= ms_fEpsilon )
  315. {
  316. float fCoeff = fSin/(fAngle.valueRadians());
  317. kResult.x = fCoeff*x;
  318. kResult.y = fCoeff*y;
  319. kResult.z = fCoeff*z;
  320. }
  321. else
  322. {
  323. kResult.x = x;
  324. kResult.y = y;
  325. kResult.z = z;
  326. }
  327. return kResult;
  328. }
  329. //-----------------------------------------------------------------------
  330. Quaternion Quaternion::Log () const
  331. {
  332. // If q = cos(A)+sin(A)*(x*i+y*j+z*k) where (x,y,z) is unit length, then
  333. // log(q) = A*(x*i+y*j+z*k). If sin(A) is near zero, use log(q) =
  334. // sin(A)*(x*i+y*j+z*k) since sin(A)/A has limit 1.
  335. Quaternion kResult;
  336. kResult.w = 0.0;
  337. if ( Math::Abs(w) < 1.0 )
  338. {
  339. Radian fAngle ( Math::ACos(w) );
  340. float fSin = Math::Sin(fAngle);
  341. if ( Math::Abs(fSin) >= ms_fEpsilon )
  342. {
  343. float fCoeff = fAngle.valueRadians()/fSin;
  344. kResult.x = fCoeff*x;
  345. kResult.y = fCoeff*y;
  346. kResult.z = fCoeff*z;
  347. return kResult;
  348. }
  349. }
  350. kResult.x = x;
  351. kResult.y = y;
  352. kResult.z = z;
  353. return kResult;
  354. }
  355. //-----------------------------------------------------------------------
  356. Vector3 Quaternion::operator* (const Vector3& v) const
  357. {
  358. // nVidia SDK implementation
  359. Vector3 uv, uuv;
  360. Vector3 qvec(x, y, z);
  361. uv = qvec.crossProduct(v);
  362. uuv = qvec.crossProduct(uv);
  363. uv *= (2.0f * w);
  364. uuv *= 2.0f;
  365. return v + uv + uuv;
  366. }
  367. //-----------------------------------------------------------------------
  368. bool Quaternion::equals(const Quaternion& rhs, const Radian& tolerance) const
  369. {
  370. float fCos = Dot(rhs);
  371. Radian angle = Math::ACos(fCos);
  372. return (Math::Abs(angle.valueRadians()) <= tolerance.valueRadians())
  373. || Math::RealEqual(angle.valueRadians(), Math::PI, tolerance.valueRadians());
  374. }
  375. //-----------------------------------------------------------------------
  376. Quaternion Quaternion::Slerp (float fT, const Quaternion& rkP,
  377. const Quaternion& rkQ, bool shortestPath)
  378. {
  379. float fCos = rkP.Dot(rkQ);
  380. Quaternion rkT;
  381. // Do we need to invert rotation?
  382. if (fCos < 0.0f && shortestPath)
  383. {
  384. fCos = -fCos;
  385. rkT = -rkQ;
  386. }
  387. else
  388. {
  389. rkT = rkQ;
  390. }
  391. if (Math::Abs(fCos) < 1 - ms_fEpsilon)
  392. {
  393. // Standard case (slerp)
  394. float fSin = Math::Sqrt(1 - Math::Sqr(fCos));
  395. Radian fAngle = Math::ATan2(fSin, fCos);
  396. float fInvSin = 1.0f / fSin;
  397. float fCoeff0 = Math::Sin((1.0f - fT) * fAngle) * fInvSin;
  398. float fCoeff1 = Math::Sin(fT * fAngle) * fInvSin;
  399. return fCoeff0 * rkP + fCoeff1 * rkT;
  400. }
  401. else
  402. {
  403. // There are two situations:
  404. // 1. "rkP" and "rkQ" are very close (fCos ~= +1), so we can do a linear
  405. // interpolation safely.
  406. // 2. "rkP" and "rkQ" are almost inverse of each other (fCos ~= -1), there
  407. // are an infinite number of possibilities interpolation. but we haven't
  408. // have method to fix this case, so just use linear interpolation here.
  409. Quaternion t = (1.0f - fT) * rkP + fT * rkT;
  410. // taking the complement requires renormalisation
  411. t.normalise();
  412. return t;
  413. }
  414. }
  415. //-----------------------------------------------------------------------
  416. Quaternion Quaternion::SlerpExtraSpins (float fT,
  417. const Quaternion& rkP, const Quaternion& rkQ, int iExtraSpins)
  418. {
  419. float fCos = rkP.Dot(rkQ);
  420. Radian fAngle ( Math::ACos(fCos) );
  421. if ( Math::Abs(fAngle.valueRadians()) < ms_fEpsilon )
  422. return rkP;
  423. float fSin = Math::Sin(fAngle);
  424. Radian fPhase ( Math::PI*iExtraSpins*fT );
  425. float fInvSin = 1.0f/fSin;
  426. float fCoeff0 = Math::Sin((1.0f-fT)*fAngle - fPhase)*fInvSin;
  427. float fCoeff1 = Math::Sin(fT*fAngle + fPhase)*fInvSin;
  428. return fCoeff0*rkP + fCoeff1*rkQ;
  429. }
  430. //-----------------------------------------------------------------------
  431. void Quaternion::Intermediate (const Quaternion& rkQ0,
  432. const Quaternion& rkQ1, const Quaternion& rkQ2,
  433. Quaternion& rkA, Quaternion& rkB)
  434. {
  435. // assert: q0, q1, q2 are unit quaternions
  436. Quaternion kQ0inv = rkQ0.UnitInverse();
  437. Quaternion kQ1inv = rkQ1.UnitInverse();
  438. Quaternion rkP0 = kQ0inv*rkQ1;
  439. Quaternion rkP1 = kQ1inv*rkQ2;
  440. Quaternion kArg = 0.25*(rkP0.Log()-rkP1.Log());
  441. Quaternion kMinusArg = -kArg;
  442. rkA = rkQ1*kArg.Exp();
  443. rkB = rkQ1*kMinusArg.Exp();
  444. }
  445. //-----------------------------------------------------------------------
  446. Quaternion Quaternion::Squad (float fT,
  447. const Quaternion& rkP, const Quaternion& rkA,
  448. const Quaternion& rkB, const Quaternion& rkQ, bool shortestPath)
  449. {
  450. float fSlerpT = 2.0f*fT*(1.0f-fT);
  451. Quaternion kSlerpP = Slerp(fT, rkP, rkQ, shortestPath);
  452. Quaternion kSlerpQ = Slerp(fT, rkA, rkB);
  453. return Slerp(fSlerpT, kSlerpP ,kSlerpQ);
  454. }
  455. //-----------------------------------------------------------------------
  456. float Quaternion::normalise(void)
  457. {
  458. float len = Norm();
  459. float factor = 1.0f / Math::Sqrt(len);
  460. *this = *this * factor;
  461. return len;
  462. }
  463. //-----------------------------------------------------------------------
  464. Radian Quaternion::getRoll(bool reprojectAxis) const
  465. {
  466. if (reprojectAxis)
  467. {
  468. // roll = atan2(localx.y, localx.x)
  469. // pick parts of xAxis() implementation that we need
  470. // float fTx = 2.0*x;
  471. float fTy = 2.0f*y;
  472. float fTz = 2.0f*z;
  473. float fTwz = fTz*w;
  474. float fTxy = fTy*x;
  475. float fTyy = fTy*y;
  476. float fTzz = fTz*z;
  477. // Vector3(1.0-(fTyy+fTzz), fTxy+fTwz, fTxz-fTwy);
  478. return Radian(Math::ATan2(fTxy+fTwz, 1.0f-(fTyy+fTzz)));
  479. }
  480. else
  481. {
  482. return Radian(Math::ATan2(2*(x*y + w*z), w*w + x*x - y*y - z*z));
  483. }
  484. }
  485. //-----------------------------------------------------------------------
  486. Radian Quaternion::getPitch(bool reprojectAxis) const
  487. {
  488. if (reprojectAxis)
  489. {
  490. // pitch = atan2(localy.z, localy.y)
  491. // pick parts of yAxis() implementation that we need
  492. float fTx = 2.0f*x;
  493. // float fTy = 2.0f*y;
  494. float fTz = 2.0f*z;
  495. float fTwx = fTx*w;
  496. float fTxx = fTx*x;
  497. float fTyz = fTz*y;
  498. float fTzz = fTz*z;
  499. // Vector3(fTxy-fTwz, 1.0-(fTxx+fTzz), fTyz+fTwx);
  500. return Radian(Math::ATan2(fTyz+fTwx, 1.0f-(fTxx+fTzz)));
  501. }
  502. else
  503. {
  504. // internal version
  505. return Radian(Math::ATan2(2*(y*z + w*x), w*w - x*x - y*y + z*z));
  506. }
  507. }
  508. //-----------------------------------------------------------------------
  509. Radian Quaternion::getYaw(bool reprojectAxis) const
  510. {
  511. if (reprojectAxis)
  512. {
  513. // yaw = atan2(localz.x, localz.z)
  514. // pick parts of zAxis() implementation that we need
  515. float fTx = 2.0f*x;
  516. float fTy = 2.0f*y;
  517. float fTz = 2.0f*z;
  518. float fTwy = fTy*w;
  519. float fTxx = fTx*x;
  520. float fTxz = fTz*x;
  521. float fTyy = fTy*y;
  522. // Vector3(fTxz+fTwy, fTyz-fTwx, 1.0-(fTxx+fTyy));
  523. return Radian(Math::ATan2(fTxz+fTwy, 1.0f-(fTxx+fTyy)));
  524. }
  525. else
  526. {
  527. // internal version
  528. return Radian(Math::ASin(-2*(x*z - w*y)));
  529. }
  530. }
  531. //-----------------------------------------------------------------------
  532. Quaternion Quaternion::nlerp(float fT, const Quaternion& rkP,
  533. const Quaternion& rkQ, bool shortestPath)
  534. {
  535. Quaternion result;
  536. float fCos = rkP.Dot(rkQ);
  537. if (fCos < 0.0f && shortestPath)
  538. {
  539. result = rkP + fT * ((-rkQ) - rkP);
  540. }
  541. else
  542. {
  543. result = rkP + fT * (rkQ - rkP);
  544. }
  545. result.normalise();
  546. return result;
  547. }
  548. }