2
0

CmQuaternion.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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 CamelotFramework
  35. {
  36. const float Quaternion::EPSILON = 1e-03f;
  37. const Quaternion Quaternion::ZERO(0.0f, 0.0f, 0.0f, 0.0f);
  38. const Quaternion Quaternion::IDENTITY(1.0f, 0.0f, 0.0f, 0.0f);
  39. const Quaternion::EulerAngleOrderData Quaternion::EA_LOOKUP[6] =
  40. { { 0, 1, 2}, { 0, 2, 1}, { 1, 0, 2},
  41. { 1, 2, 0}, { 2, 0, 1}, { 2, 1, 0} };;
  42. void Quaternion::fromRotationMatrix(const Matrix3& mat)
  43. {
  44. // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
  45. // article "Quaternion Calculus and Fast Animation".
  46. float trace = mat[0][0]+mat[1][1]+mat[2][2];
  47. float root;
  48. if (trace > 0.0f)
  49. {
  50. // |w| > 1/2, may as well choose w > 1/2
  51. root = Math::sqrt(trace + 1.0f); // 2w
  52. w = 0.5f*root;
  53. root = 0.5f/root; // 1/(4w)
  54. x = (mat[2][1]-mat[1][2])*root;
  55. y = (mat[0][2]-mat[2][0])*root;
  56. z = (mat[1][0]-mat[0][1])*root;
  57. }
  58. else
  59. {
  60. // |w| <= 1/2
  61. static size_t nextLookup[3] = { 1, 2, 0 };
  62. size_t i = 0;
  63. if (mat[1][1] > mat[0][0])
  64. i = 1;
  65. if (mat[2][2] > mat[i][i])
  66. i = 2;
  67. size_t j = nextLookup[i];
  68. size_t k = nextLookup[j];
  69. root = Math::sqrt(mat[i][i]-mat[j][j]-mat[k][k] + 1.0f);
  70. float* cmpntLookup[3] = { &x, &y, &z };
  71. *cmpntLookup[i] = 0.5f*root;
  72. root = 0.5f/root;
  73. w = (mat[k][j]-mat[j][k])*root;
  74. *cmpntLookup[j] = (mat[j][i]+mat[i][j])*root;
  75. *cmpntLookup[k] = (mat[k][i]+mat[i][k])*root;
  76. }
  77. normalize();
  78. }
  79. void Quaternion::fromAxisAngle(const Vector3& axis, const Radian& angle)
  80. {
  81. // Assert: axis[] is unit length
  82. Radian fHalfAngle (0.5f*angle);
  83. float fSin = Math::sin(fHalfAngle);
  84. w = Math::cos(fHalfAngle);
  85. x = fSin*axis.x;
  86. y = fSin*axis.y;
  87. z = fSin*axis.z;
  88. }
  89. void Quaternion::fromAxes(const Vector3& xaxis, const Vector3& yaxis, const Vector3& zaxis)
  90. {
  91. Matrix3 kRot;
  92. kRot[0][0] = xaxis.x;
  93. kRot[1][0] = xaxis.y;
  94. kRot[2][0] = xaxis.z;
  95. kRot[0][1] = yaxis.x;
  96. kRot[1][1] = yaxis.y;
  97. kRot[2][1] = yaxis.z;
  98. kRot[0][2] = zaxis.x;
  99. kRot[1][2] = zaxis.y;
  100. kRot[2][2] = zaxis.z;
  101. fromRotationMatrix(kRot);
  102. }
  103. void Quaternion::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle)
  104. {
  105. Quaternion quats[3];
  106. quats[0].fromAxisAngle(Vector3::UNIT_X, xAngle);
  107. quats[1].fromAxisAngle(Vector3::UNIT_Y, yAngle);
  108. quats[2].fromAxisAngle(Vector3::UNIT_Z, zAngle);
  109. *this = quats[2]*(quats[0] * quats[1]);
  110. }
  111. void Quaternion::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle, EulerAngleOrder order)
  112. {
  113. const EulerAngleOrderData& l = EA_LOOKUP[(int)order];
  114. Quaternion quats[3];
  115. quats[0].fromAxisAngle(Vector3::UNIT_X, xAngle);
  116. quats[1].fromAxisAngle(Vector3::UNIT_Y, yAngle);
  117. quats[2].fromAxisAngle(Vector3::UNIT_Z, zAngle);
  118. *this = quats[l.c]*(quats[l.a] * quats[l.b]);
  119. }
  120. void Quaternion::toRotationMatrix(Matrix3& mat) const
  121. {
  122. float fTx = x+x;
  123. float fTy = y+y;
  124. float fTz = z+z;
  125. float fTwx = fTx*w;
  126. float fTwy = fTy*w;
  127. float fTwz = fTz*w;
  128. float fTxx = fTx*x;
  129. float fTxy = fTy*x;
  130. float fTxz = fTz*x;
  131. float fTyy = fTy*y;
  132. float fTyz = fTz*y;
  133. float fTzz = fTz*z;
  134. mat[0][0] = 1.0f-(fTyy+fTzz);
  135. mat[0][1] = fTxy-fTwz;
  136. mat[0][2] = fTxz+fTwy;
  137. mat[1][0] = fTxy+fTwz;
  138. mat[1][1] = 1.0f-(fTxx+fTzz);
  139. mat[1][2] = fTyz-fTwx;
  140. mat[2][0] = fTxz-fTwy;
  141. mat[2][1] = fTyz+fTwx;
  142. mat[2][2] = 1.0f-(fTxx+fTyy);
  143. }
  144. void Quaternion::toAxisAngle(Vector3& axis, Radian& angle) const
  145. {
  146. float fSqrLength = x*x+y*y+z*z;
  147. if ( fSqrLength > 0.0 )
  148. {
  149. angle = 2.0*Math::acos(w);
  150. float fInvLength = Math::invSqrt(fSqrLength);
  151. axis.x = x*fInvLength;
  152. axis.y = y*fInvLength;
  153. axis.z = z*fInvLength;
  154. }
  155. else
  156. {
  157. // Angle is 0 (mod 2*pi), so any axis will do
  158. angle = Radian(0.0);
  159. axis.x = 1.0;
  160. axis.y = 0.0;
  161. axis.z = 0.0;
  162. }
  163. }
  164. void Quaternion::toAxes(Vector3& xaxis, Vector3& yaxis, Vector3& zaxis) const
  165. {
  166. Matrix3 matRot;
  167. toRotationMatrix(matRot);
  168. xaxis.x = matRot[0][0];
  169. xaxis.y = matRot[1][0];
  170. xaxis.z = matRot[2][0];
  171. yaxis.x = matRot[0][1];
  172. yaxis.y = matRot[1][1];
  173. yaxis.z = matRot[2][1];
  174. zaxis.x = matRot[0][2];
  175. zaxis.y = matRot[1][2];
  176. zaxis.z = matRot[2][2];
  177. }
  178. bool Quaternion::toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle) const
  179. {
  180. Matrix3 matRot;
  181. toRotationMatrix(matRot);
  182. return matRot.toEulerAngles(xAngle, yAngle, zAngle);
  183. }
  184. bool Quaternion::toEulerAngles(Radian& xAngle, Radian& yAngle, Radian& zAngle, EulerAngleOrder order) const
  185. {
  186. Matrix3 matRot;
  187. toRotationMatrix(matRot);
  188. return matRot.toEulerAngles(xAngle, yAngle, zAngle, order);
  189. }
  190. Vector3 Quaternion::xAxis() const
  191. {
  192. float fTy = 2.0f*y;
  193. float fTz = 2.0f*z;
  194. float fTwy = fTy*w;
  195. float fTwz = fTz*w;
  196. float fTxy = fTy*x;
  197. float fTxz = fTz*x;
  198. float fTyy = fTy*y;
  199. float fTzz = fTz*z;
  200. return Vector3(1.0f-(fTyy+fTzz), fTxy+fTwz, fTxz-fTwy);
  201. }
  202. Vector3 Quaternion::yAxis() const
  203. {
  204. float fTx = 2.0f*x;
  205. float fTy = 2.0f*y;
  206. float fTz = 2.0f*z;
  207. float fTwx = fTx*w;
  208. float fTwz = fTz*w;
  209. float fTxx = fTx*x;
  210. float fTxy = fTy*x;
  211. float fTyz = fTz*y;
  212. float fTzz = fTz*z;
  213. return Vector3(fTxy-fTwz, 1.0f-(fTxx+fTzz), fTyz+fTwx);
  214. }
  215. Vector3 Quaternion::zAxis() const
  216. {
  217. float fTx = 2.0f*x;
  218. float fTy = 2.0f*y;
  219. float fTz = 2.0f*z;
  220. float fTwx = fTx*w;
  221. float fTwy = fTy*w;
  222. float fTxx = fTx*x;
  223. float fTxz = fTz*x;
  224. float fTyy = fTy*y;
  225. float fTyz = fTz*y;
  226. return Vector3(fTxz+fTwy, fTyz-fTwx, 1.0f-(fTxx+fTyy));
  227. }
  228. Quaternion Quaternion::operator+ (const Quaternion& rhs) const
  229. {
  230. return Quaternion(w+rhs.w,x+rhs.x,y+rhs.y,z+rhs.z);
  231. }
  232. Quaternion Quaternion::operator- (const Quaternion& rhs) const
  233. {
  234. return Quaternion(w-rhs.w,x-rhs.x,y-rhs.y,z-rhs.z);
  235. }
  236. Quaternion Quaternion::operator* (const Quaternion& rhs) const
  237. {
  238. return Quaternion
  239. (
  240. w * rhs.w - x * rhs.x - y * rhs.y - z * rhs.z,
  241. w * rhs.x + x * rhs.w + y * rhs.z - z * rhs.y,
  242. w * rhs.y + y * rhs.w + z * rhs.x - x * rhs.z,
  243. w * rhs.z + z * rhs.w + x * rhs.y - y * rhs.x
  244. );
  245. }
  246. Quaternion Quaternion::operator* (float rhs) const
  247. {
  248. return Quaternion(rhs*w,rhs*x,rhs*y,rhs*z);
  249. }
  250. Quaternion Quaternion::operator- () const
  251. {
  252. return Quaternion(-w,-x,-y,-z);
  253. }
  254. float Quaternion::dot(const Quaternion& other) const
  255. {
  256. return w*other.w+x*other.x+y*other.y+z*other.z;
  257. }
  258. Quaternion Quaternion::inverse() const
  259. {
  260. float fNorm = w*w+x*x+y*y+z*z;
  261. if (fNorm > 0.0f)
  262. {
  263. float fInvNorm = 1.0f/fNorm;
  264. return Quaternion(w*fInvNorm,-x*fInvNorm,-y*fInvNorm,-z*fInvNorm);
  265. }
  266. else
  267. {
  268. // Return an invalid result to flag the error
  269. return ZERO;
  270. }
  271. }
  272. Vector3 Quaternion::rotate(const Vector3& v) const
  273. {
  274. Matrix3 rot;
  275. toRotationMatrix(rot);
  276. return rot.transform(v);
  277. }
  278. Quaternion Quaternion::slerp(float t, const Quaternion& p, const Quaternion& q, bool shortestPath)
  279. {
  280. float cos = p.dot(q);
  281. Quaternion quat;
  282. if (cos < 0.0f && shortestPath)
  283. {
  284. cos = -cos;
  285. quat = -q;
  286. }
  287. else
  288. {
  289. quat = q;
  290. }
  291. if (Math::abs(cos) < 1 - EPSILON)
  292. {
  293. // Standard case (slerp)
  294. float sin = Math::sqrt(1 - Math::sqr(cos));
  295. Radian angle = Math::tan2(sin, cos);
  296. float invSin = 1.0f / sin;
  297. float coeff0 = Math::sin((1.0f - t) * angle) * invSin;
  298. float coeff1 = Math::sin(t * angle) * invSin;
  299. return coeff0 * p + coeff1 * quat;
  300. }
  301. else
  302. {
  303. // There are two situations:
  304. // 1. "p" and "q" are very close (fCos ~= +1), so we can do a linear
  305. // interpolation safely.
  306. // 2. "p" and "q" are almost inverse of each other (fCos ~= -1), there
  307. // are an infinite number of possibilities interpolation. but we haven't
  308. // have method to fix this case, so just use linear interpolation here.
  309. Quaternion ret = (1.0f - t) * p + t * quat;
  310. // Taking the complement requires renormalization
  311. ret.normalize();
  312. return ret;
  313. }
  314. }
  315. float Quaternion::normalize()
  316. {
  317. float len = w*w+x*x+y*y+z*z;
  318. float factor = 1.0f / Math::sqrt(len);
  319. *this = *this * factor;
  320. return len;
  321. }
  322. Quaternion operator* (float lhs, const Quaternion& rhs)
  323. {
  324. return Quaternion(lhs*rhs.w,lhs*rhs.x,lhs*rhs.y,
  325. lhs*rhs.z);
  326. }
  327. }