CmQuaternion.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  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. normalise();
  75. }
  76. //-----------------------------------------------------------------------
  77. void Quaternion::ToRotationMatrix (Matrix3& kRot) const
  78. {
  79. float fTx = x+x;
  80. float fTy = y+y;
  81. float fTz = z+z;
  82. float fTwx = fTx*w;
  83. float fTwy = fTy*w;
  84. float fTwz = fTz*w;
  85. float fTxx = fTx*x;
  86. float fTxy = fTy*x;
  87. float fTxz = fTz*x;
  88. float fTyy = fTy*y;
  89. float fTyz = fTz*y;
  90. float fTzz = fTz*z;
  91. kRot[0][0] = 1.0f-(fTyy+fTzz);
  92. kRot[0][1] = fTxy-fTwz;
  93. kRot[0][2] = fTxz+fTwy;
  94. kRot[1][0] = fTxy+fTwz;
  95. kRot[1][1] = 1.0f-(fTxx+fTzz);
  96. kRot[1][2] = fTyz-fTwx;
  97. kRot[2][0] = fTxz-fTwy;
  98. kRot[2][1] = fTyz+fTwx;
  99. kRot[2][2] = 1.0f-(fTxx+fTyy);
  100. }
  101. //-----------------------------------------------------------------------
  102. void Quaternion::FromAngleAxis (const Radian& rfAngle,
  103. const Vector3& rkAxis)
  104. {
  105. // assert: axis[] is unit length
  106. //
  107. // The quaternion representing the rotation is
  108. // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
  109. Radian fHalfAngle ( 0.5*rfAngle );
  110. float fSin = Math::Sin(fHalfAngle);
  111. w = Math::Cos(fHalfAngle);
  112. x = fSin*rkAxis.x;
  113. y = fSin*rkAxis.y;
  114. z = fSin*rkAxis.z;
  115. }
  116. //-----------------------------------------------------------------------
  117. void Quaternion::ToAngleAxis (Radian& rfAngle, Vector3& rkAxis) const
  118. {
  119. // The quaternion representing the rotation is
  120. // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
  121. float fSqrLength = x*x+y*y+z*z;
  122. if ( fSqrLength > 0.0 )
  123. {
  124. rfAngle = 2.0*Math::ACos(w);
  125. float fInvLength = Math::InvSqrt(fSqrLength);
  126. rkAxis.x = x*fInvLength;
  127. rkAxis.y = y*fInvLength;
  128. rkAxis.z = z*fInvLength;
  129. }
  130. else
  131. {
  132. // angle is 0 (mod 2*pi), so any axis will do
  133. rfAngle = Radian(0.0);
  134. rkAxis.x = 1.0;
  135. rkAxis.y = 0.0;
  136. rkAxis.z = 0.0;
  137. }
  138. }
  139. //-----------------------------------------------------------------------
  140. void Quaternion::FromAxes (const Vector3* akAxis)
  141. {
  142. Matrix3 kRot;
  143. for (size_t iCol = 0; iCol < 3; iCol++)
  144. {
  145. kRot[0][iCol] = akAxis[iCol].x;
  146. kRot[1][iCol] = akAxis[iCol].y;
  147. kRot[2][iCol] = akAxis[iCol].z;
  148. }
  149. FromRotationMatrix(kRot);
  150. }
  151. //-----------------------------------------------------------------------
  152. void Quaternion::FromAxes (const Vector3& xaxis, const Vector3& yaxis, const Vector3& zaxis)
  153. {
  154. Matrix3 kRot;
  155. kRot[0][0] = xaxis.x;
  156. kRot[1][0] = xaxis.y;
  157. kRot[2][0] = xaxis.z;
  158. kRot[0][1] = yaxis.x;
  159. kRot[1][1] = yaxis.y;
  160. kRot[2][1] = yaxis.z;
  161. kRot[0][2] = zaxis.x;
  162. kRot[1][2] = zaxis.y;
  163. kRot[2][2] = zaxis.z;
  164. FromRotationMatrix(kRot);
  165. }
  166. //-----------------------------------------------------------------------
  167. void Quaternion::ToAxes (Vector3* akAxis) const
  168. {
  169. Matrix3 kRot;
  170. ToRotationMatrix(kRot);
  171. for (size_t iCol = 0; iCol < 3; iCol++)
  172. {
  173. akAxis[iCol].x = kRot[0][iCol];
  174. akAxis[iCol].y = kRot[1][iCol];
  175. akAxis[iCol].z = kRot[2][iCol];
  176. }
  177. }
  178. //-----------------------------------------------------------------------
  179. Vector3 Quaternion::xAxis(void) const
  180. {
  181. //float fTx = 2.0*x;
  182. float fTy = 2.0f*y;
  183. float fTz = 2.0f*z;
  184. float fTwy = fTy*w;
  185. float fTwz = fTz*w;
  186. float fTxy = fTy*x;
  187. float fTxz = fTz*x;
  188. float fTyy = fTy*y;
  189. float fTzz = fTz*z;
  190. return Vector3(1.0f-(fTyy+fTzz), fTxy+fTwz, fTxz-fTwy);
  191. }
  192. //-----------------------------------------------------------------------
  193. Vector3 Quaternion::yAxis(void) const
  194. {
  195. float fTx = 2.0f*x;
  196. float fTy = 2.0f*y;
  197. float fTz = 2.0f*z;
  198. float fTwx = fTx*w;
  199. float fTwz = fTz*w;
  200. float fTxx = fTx*x;
  201. float fTxy = fTy*x;
  202. float fTyz = fTz*y;
  203. float fTzz = fTz*z;
  204. return Vector3(fTxy-fTwz, 1.0f-(fTxx+fTzz), fTyz+fTwx);
  205. }
  206. //-----------------------------------------------------------------------
  207. Vector3 Quaternion::zAxis(void) const
  208. {
  209. float fTx = 2.0f*x;
  210. float fTy = 2.0f*y;
  211. float fTz = 2.0f*z;
  212. float fTwx = fTx*w;
  213. float fTwy = fTy*w;
  214. float fTxx = fTx*x;
  215. float fTxz = fTz*x;
  216. float fTyy = fTy*y;
  217. float fTyz = fTz*y;
  218. return Vector3(fTxz+fTwy, fTyz-fTwx, 1.0f-(fTxx+fTyy));
  219. }
  220. //-----------------------------------------------------------------------
  221. void Quaternion::ToAxes (Vector3& xaxis, Vector3& yaxis, Vector3& zaxis) const
  222. {
  223. Matrix3 kRot;
  224. ToRotationMatrix(kRot);
  225. xaxis.x = kRot[0][0];
  226. xaxis.y = kRot[1][0];
  227. xaxis.z = kRot[2][0];
  228. yaxis.x = kRot[0][1];
  229. yaxis.y = kRot[1][1];
  230. yaxis.z = kRot[2][1];
  231. zaxis.x = kRot[0][2];
  232. zaxis.y = kRot[1][2];
  233. zaxis.z = kRot[2][2];
  234. }
  235. //-----------------------------------------------------------------------
  236. Quaternion Quaternion::operator+ (const Quaternion& rkQ) const
  237. {
  238. return Quaternion(w+rkQ.w,x+rkQ.x,y+rkQ.y,z+rkQ.z);
  239. }
  240. //-----------------------------------------------------------------------
  241. Quaternion Quaternion::operator- (const Quaternion& rkQ) const
  242. {
  243. return Quaternion(w-rkQ.w,x-rkQ.x,y-rkQ.y,z-rkQ.z);
  244. }
  245. //-----------------------------------------------------------------------
  246. Quaternion Quaternion::operator* (const Quaternion& rkQ) const
  247. {
  248. // NOTE: Multiplication is not generally commutative, so in most
  249. // cases p*q != q*p.
  250. return Quaternion
  251. (
  252. w * rkQ.w - x * rkQ.x - y * rkQ.y - z * rkQ.z,
  253. w * rkQ.x + x * rkQ.w + y * rkQ.z - z * rkQ.y,
  254. w * rkQ.y + y * rkQ.w + z * rkQ.x - x * rkQ.z,
  255. w * rkQ.z + z * rkQ.w + x * rkQ.y - y * rkQ.x
  256. );
  257. }
  258. //-----------------------------------------------------------------------
  259. Quaternion Quaternion::operator* (float fScalar) const
  260. {
  261. return Quaternion(fScalar*w,fScalar*x,fScalar*y,fScalar*z);
  262. }
  263. //-----------------------------------------------------------------------
  264. Quaternion operator* (float fScalar, const Quaternion& rkQ)
  265. {
  266. return Quaternion(fScalar*rkQ.w,fScalar*rkQ.x,fScalar*rkQ.y,
  267. fScalar*rkQ.z);
  268. }
  269. //-----------------------------------------------------------------------
  270. Quaternion Quaternion::operator- () const
  271. {
  272. return Quaternion(-w,-x,-y,-z);
  273. }
  274. //-----------------------------------------------------------------------
  275. float Quaternion::Dot (const Quaternion& rkQ) const
  276. {
  277. return w*rkQ.w+x*rkQ.x+y*rkQ.y+z*rkQ.z;
  278. }
  279. //-----------------------------------------------------------------------
  280. float Quaternion::Norm () const
  281. {
  282. return w*w+x*x+y*y+z*z;
  283. }
  284. //-----------------------------------------------------------------------
  285. Quaternion Quaternion::Inverse () const
  286. {
  287. float fNorm = w*w+x*x+y*y+z*z;
  288. if ( fNorm > 0.0 )
  289. {
  290. float fInvNorm = 1.0f/fNorm;
  291. return Quaternion(w*fInvNorm,-x*fInvNorm,-y*fInvNorm,-z*fInvNorm);
  292. }
  293. else
  294. {
  295. // return an invalid result to flag the error
  296. return ZERO;
  297. }
  298. }
  299. //-----------------------------------------------------------------------
  300. Quaternion Quaternion::UnitInverse () const
  301. {
  302. // assert: 'this' is unit length
  303. return Quaternion(w,-x,-y,-z);
  304. }
  305. //-----------------------------------------------------------------------
  306. Quaternion Quaternion::Exp () const
  307. {
  308. // If q = A*(x*i+y*j+z*k) where (x,y,z) is unit length, then
  309. // exp(q) = cos(A)+sin(A)*(x*i+y*j+z*k). If sin(A) is near zero,
  310. // use exp(q) = cos(A)+A*(x*i+y*j+z*k) since A/sin(A) has limit 1.
  311. Radian fAngle ( Math::Sqrt(x*x+y*y+z*z) );
  312. float fSin = Math::Sin(fAngle);
  313. Quaternion kResult;
  314. kResult.w = Math::Cos(fAngle);
  315. if ( Math::Abs(fSin) >= ms_fEpsilon )
  316. {
  317. float fCoeff = fSin/(fAngle.valueRadians());
  318. kResult.x = fCoeff*x;
  319. kResult.y = fCoeff*y;
  320. kResult.z = fCoeff*z;
  321. }
  322. else
  323. {
  324. kResult.x = x;
  325. kResult.y = y;
  326. kResult.z = z;
  327. }
  328. return kResult;
  329. }
  330. //-----------------------------------------------------------------------
  331. Quaternion Quaternion::Log () const
  332. {
  333. // If q = cos(A)+sin(A)*(x*i+y*j+z*k) where (x,y,z) is unit length, then
  334. // log(q) = A*(x*i+y*j+z*k). If sin(A) is near zero, use log(q) =
  335. // sin(A)*(x*i+y*j+z*k) since sin(A)/A has limit 1.
  336. Quaternion kResult;
  337. kResult.w = 0.0;
  338. if ( Math::Abs(w) < 1.0 )
  339. {
  340. Radian fAngle ( Math::ACos(w) );
  341. float fSin = Math::Sin(fAngle);
  342. if ( Math::Abs(fSin) >= ms_fEpsilon )
  343. {
  344. float fCoeff = fAngle.valueRadians()/fSin;
  345. kResult.x = fCoeff*x;
  346. kResult.y = fCoeff*y;
  347. kResult.z = fCoeff*z;
  348. return kResult;
  349. }
  350. }
  351. kResult.x = x;
  352. kResult.y = y;
  353. kResult.z = z;
  354. return kResult;
  355. }
  356. //-----------------------------------------------------------------------
  357. Vector3 Quaternion::operator* (const Vector3& v) const
  358. {
  359. // nVidia SDK implementation
  360. Vector3 uv, uuv;
  361. Vector3 qvec(x, y, z);
  362. uv = qvec.crossProduct(v);
  363. uuv = qvec.crossProduct(uv);
  364. uv *= (2.0f * w);
  365. uuv *= 2.0f;
  366. return v + uv + uuv;
  367. }
  368. //-----------------------------------------------------------------------
  369. bool Quaternion::equals(const Quaternion& rhs, const Radian& tolerance) const
  370. {
  371. float fCos = Dot(rhs);
  372. Radian angle = Math::ACos(fCos);
  373. return (Math::Abs(angle.valueRadians()) <= tolerance.valueRadians())
  374. || Math::RealEqual(angle.valueRadians(), Math::PI, tolerance.valueRadians());
  375. }
  376. //-----------------------------------------------------------------------
  377. Quaternion Quaternion::Slerp (float fT, const Quaternion& rkP,
  378. const Quaternion& rkQ, bool shortestPath)
  379. {
  380. float fCos = rkP.Dot(rkQ);
  381. Quaternion rkT;
  382. // Do we need to invert rotation?
  383. if (fCos < 0.0f && shortestPath)
  384. {
  385. fCos = -fCos;
  386. rkT = -rkQ;
  387. }
  388. else
  389. {
  390. rkT = rkQ;
  391. }
  392. if (Math::Abs(fCos) < 1 - ms_fEpsilon)
  393. {
  394. // Standard case (slerp)
  395. float fSin = Math::Sqrt(1 - Math::Sqr(fCos));
  396. Radian fAngle = Math::ATan2(fSin, fCos);
  397. float fInvSin = 1.0f / fSin;
  398. float fCoeff0 = Math::Sin((1.0f - fT) * fAngle) * fInvSin;
  399. float fCoeff1 = Math::Sin(fT * fAngle) * fInvSin;
  400. return fCoeff0 * rkP + fCoeff1 * rkT;
  401. }
  402. else
  403. {
  404. // There are two situations:
  405. // 1. "rkP" and "rkQ" are very close (fCos ~= +1), so we can do a linear
  406. // interpolation safely.
  407. // 2. "rkP" and "rkQ" are almost inverse of each other (fCos ~= -1), there
  408. // are an infinite number of possibilities interpolation. but we haven't
  409. // have method to fix this case, so just use linear interpolation here.
  410. Quaternion t = (1.0f - fT) * rkP + fT * rkT;
  411. // taking the complement requires renormalisation
  412. t.normalise();
  413. return t;
  414. }
  415. }
  416. //-----------------------------------------------------------------------
  417. Quaternion Quaternion::SlerpExtraSpins (float fT,
  418. const Quaternion& rkP, const Quaternion& rkQ, int iExtraSpins)
  419. {
  420. float fCos = rkP.Dot(rkQ);
  421. Radian fAngle ( Math::ACos(fCos) );
  422. if ( Math::Abs(fAngle.valueRadians()) < ms_fEpsilon )
  423. return rkP;
  424. float fSin = Math::Sin(fAngle);
  425. Radian fPhase ( Math::PI*iExtraSpins*fT );
  426. float fInvSin = 1.0f/fSin;
  427. float fCoeff0 = Math::Sin((1.0f-fT)*fAngle - fPhase)*fInvSin;
  428. float fCoeff1 = Math::Sin(fT*fAngle + fPhase)*fInvSin;
  429. return fCoeff0*rkP + fCoeff1*rkQ;
  430. }
  431. //-----------------------------------------------------------------------
  432. void Quaternion::Intermediate (const Quaternion& rkQ0,
  433. const Quaternion& rkQ1, const Quaternion& rkQ2,
  434. Quaternion& rkA, Quaternion& rkB)
  435. {
  436. // assert: q0, q1, q2 are unit quaternions
  437. Quaternion kQ0inv = rkQ0.UnitInverse();
  438. Quaternion kQ1inv = rkQ1.UnitInverse();
  439. Quaternion rkP0 = kQ0inv*rkQ1;
  440. Quaternion rkP1 = kQ1inv*rkQ2;
  441. Quaternion kArg = 0.25*(rkP0.Log()-rkP1.Log());
  442. Quaternion kMinusArg = -kArg;
  443. rkA = rkQ1*kArg.Exp();
  444. rkB = rkQ1*kMinusArg.Exp();
  445. }
  446. //-----------------------------------------------------------------------
  447. Quaternion Quaternion::Squad (float fT,
  448. const Quaternion& rkP, const Quaternion& rkA,
  449. const Quaternion& rkB, const Quaternion& rkQ, bool shortestPath)
  450. {
  451. float fSlerpT = 2.0f*fT*(1.0f-fT);
  452. Quaternion kSlerpP = Slerp(fT, rkP, rkQ, shortestPath);
  453. Quaternion kSlerpQ = Slerp(fT, rkA, rkB);
  454. return Slerp(fSlerpT, kSlerpP ,kSlerpQ);
  455. }
  456. //-----------------------------------------------------------------------
  457. float Quaternion::normalise(void)
  458. {
  459. float len = Norm();
  460. float factor = 1.0f / Math::Sqrt(len);
  461. *this = *this * factor;
  462. return len;
  463. }
  464. //-----------------------------------------------------------------------
  465. Radian Quaternion::getRoll(bool reprojectAxis) const
  466. {
  467. if (reprojectAxis)
  468. {
  469. // roll = atan2(localx.y, localx.x)
  470. // pick parts of xAxis() implementation that we need
  471. // float fTx = 2.0*x;
  472. float fTy = 2.0f*y;
  473. float fTz = 2.0f*z;
  474. float fTwz = fTz*w;
  475. float fTxy = fTy*x;
  476. float fTyy = fTy*y;
  477. float fTzz = fTz*z;
  478. // Vector3(1.0-(fTyy+fTzz), fTxy+fTwz, fTxz-fTwy);
  479. return Radian(Math::ATan2(fTxy+fTwz, 1.0f-(fTyy+fTzz)));
  480. }
  481. else
  482. {
  483. return Radian(Math::ATan2(2*(x*y + w*z), w*w + x*x - y*y - z*z));
  484. }
  485. }
  486. //-----------------------------------------------------------------------
  487. Radian Quaternion::getPitch(bool reprojectAxis) const
  488. {
  489. if (reprojectAxis)
  490. {
  491. // pitch = atan2(localy.z, localy.y)
  492. // pick parts of yAxis() implementation that we need
  493. float fTx = 2.0f*x;
  494. // float fTy = 2.0f*y;
  495. float fTz = 2.0f*z;
  496. float fTwx = fTx*w;
  497. float fTxx = fTx*x;
  498. float fTyz = fTz*y;
  499. float fTzz = fTz*z;
  500. // Vector3(fTxy-fTwz, 1.0-(fTxx+fTzz), fTyz+fTwx);
  501. return Radian(Math::ATan2(fTyz+fTwx, 1.0f-(fTxx+fTzz)));
  502. }
  503. else
  504. {
  505. // internal version
  506. return Radian(Math::ATan2(2*(y*z + w*x), w*w - x*x - y*y + z*z));
  507. }
  508. }
  509. //-----------------------------------------------------------------------
  510. Radian Quaternion::getYaw(bool reprojectAxis) const
  511. {
  512. if (reprojectAxis)
  513. {
  514. // yaw = atan2(localz.x, localz.z)
  515. // pick parts of zAxis() implementation that we need
  516. float fTx = 2.0f*x;
  517. float fTy = 2.0f*y;
  518. float fTz = 2.0f*z;
  519. float fTwy = fTy*w;
  520. float fTxx = fTx*x;
  521. float fTxz = fTz*x;
  522. float fTyy = fTy*y;
  523. // Vector3(fTxz+fTwy, fTyz-fTwx, 1.0-(fTxx+fTyy));
  524. return Radian(Math::ATan2(fTxz+fTwy, 1.0f-(fTxx+fTyy)));
  525. }
  526. else
  527. {
  528. // internal version
  529. return Radian(Math::ASin(-2*(x*z - w*y)));
  530. }
  531. }
  532. //-----------------------------------------------------------------------
  533. Quaternion Quaternion::nlerp(float fT, const Quaternion& rkP,
  534. const Quaternion& rkQ, bool shortestPath)
  535. {
  536. Quaternion result;
  537. float fCos = rkP.Dot(rkQ);
  538. if (fCos < 0.0f && shortestPath)
  539. {
  540. result = rkP + fT * ((-rkQ) - rkP);
  541. }
  542. else
  543. {
  544. result = rkP + fT * (rkQ - rkP);
  545. }
  546. result.normalise();
  547. return result;
  548. }
  549. }