PolyQuaternion.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /*
  2. Copyright (C) 2011 by Ivan Safrin
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. THE SOFTWARE.
  18. */
  19. #include "PolyQuaternion.h"
  20. using namespace Polycode;
  21. Quaternion::Quaternion() : x(0), y(0), z(0), w(1.0f) {
  22. }
  23. Quaternion::~Quaternion() {
  24. }
  25. void Quaternion::createFromAxisAngle(Number ax, Number ay, Number az, Number degrees)
  26. {
  27. Number angle = Number((degrees / 180.0f) * PI);
  28. Number result = (Number)sin( angle / 2.0f );
  29. w = (Number)cos( angle / 2.0f );
  30. x = Number(ax * result);
  31. y = Number(ay * result);
  32. z = Number(az * result);
  33. }
  34. Matrix4 Quaternion::createMatrix() const
  35. {
  36. Matrix4 m;
  37. Number fTx = 2.0*x;
  38. Number fTy = 2.0*y;
  39. Number fTz = 2.0*z;
  40. Number fTwx = fTx*w;
  41. Number fTwy = fTy*w;
  42. Number fTwz = fTz*w;
  43. Number fTxx = fTx*x;
  44. Number fTxy = fTy*x;
  45. Number fTxz = fTz*x;
  46. Number fTyy = fTy*y;
  47. Number fTyz = fTz*y;
  48. Number fTzz = fTz*z;
  49. m[0][0] = 1.0-(fTyy+fTzz);
  50. m[1][0] = fTxy-fTwz;
  51. m[2][0] = fTxz+fTwy;
  52. m[0][1] = fTxy+fTwz;
  53. m[1][1] = 1.0-(fTxx+fTzz);
  54. m[2][1] = fTyz-fTwx;
  55. m[0][2] = fTxz-fTwy;
  56. m[1][2] = fTyz+fTwx;
  57. m[2][2] = 1.0-(fTxx+fTyy);
  58. return m;
  59. }
  60. Number Quaternion::Dot (const Quaternion& rkQ) const
  61. {
  62. return w*rkQ.w+x*rkQ.x+y*rkQ.y+z*rkQ.z;
  63. }
  64. Quaternion Quaternion::operator* (const Quaternion& rkQ) const
  65. {
  66. return Quaternion
  67. (
  68. w * rkQ.w - x * rkQ.x - y * rkQ.y - z * rkQ.z,
  69. w * rkQ.x + x * rkQ.w + y * rkQ.z - z * rkQ.y,
  70. w * rkQ.y + y * rkQ.w + z * rkQ.x - x * rkQ.z,
  71. w * rkQ.z + z * rkQ.w + x * rkQ.y - y * rkQ.x
  72. );
  73. }
  74. Quaternion Quaternion::operator* (Number fScalar) const
  75. {
  76. return Quaternion(fScalar*w,fScalar*x,fScalar*y,fScalar*z);
  77. }
  78. Quaternion operator* (Number fScalar, const Quaternion& rkQ)
  79. {
  80. return Quaternion(fScalar*rkQ.w,fScalar*rkQ.x,fScalar*rkQ.y,
  81. fScalar*rkQ.z);
  82. }
  83. Quaternion Quaternion::operator+ (const Quaternion& rkQ) const
  84. {
  85. return Quaternion(w+rkQ.w,x+rkQ.x,y+rkQ.y,z+rkQ.z);
  86. }
  87. Quaternion Quaternion::Exp () const
  88. {
  89. // If q = A*(x*i+y*j+z*k) where (x,y,z) is unit length, then
  90. // exp(q) = cos(A)+sin(A)*(x*i+y*j+z*k). If sin(A) is near zero,
  91. // use exp(q) = cos(A)+A*(x*i+y*j+z*k) since A/sin(A) has limit 1.
  92. Number fAngle ( sqrtf(x*x+y*y+z*z) );
  93. Number fSin = sinf(fAngle);
  94. Quaternion kResult;
  95. kResult.w = cosf(fAngle);
  96. if ( fabs(fSin) >= 1e-03 )
  97. {
  98. Number fCoeff = fSin/fAngle;
  99. kResult.x = fCoeff*x;
  100. kResult.y = fCoeff*y;
  101. kResult.z = fCoeff*z;
  102. }
  103. else
  104. {
  105. kResult.x = x;
  106. kResult.y = y;
  107. kResult.z = z;
  108. }
  109. return kResult;
  110. }
  111. Quaternion Quaternion::Inverse () const
  112. {
  113. Number fNorm = w*w+x*x+y*y+z*z;
  114. if ( fNorm > 0.0 )
  115. {
  116. Number fInvNorm = 1.0/fNorm;
  117. return Quaternion(w*fInvNorm,-x*fInvNorm,-y*fInvNorm,-z*fInvNorm);
  118. }
  119. else
  120. {
  121. // return an invalid result to flag the error
  122. return Quaternion(0,0,0,0);
  123. }
  124. }
  125. Quaternion Quaternion::Log () const
  126. {
  127. Quaternion kResult;
  128. kResult.w = 0.0;
  129. if ( fabs(w) < 1.0 )
  130. {
  131. Number fAngle ( acosf(w) );
  132. Number fSin = sinf(fAngle);
  133. if ( fabs(fSin) >= 1e-03 )
  134. {
  135. Number fCoeff = fAngle/fSin;
  136. kResult.x = fCoeff*x;
  137. kResult.y = fCoeff*y;
  138. kResult.z = fCoeff*z;
  139. return kResult;
  140. }
  141. }
  142. kResult.x = x;
  143. kResult.y = y;
  144. kResult.z = z;
  145. return kResult;
  146. }
  147. Number Quaternion::Norm () const
  148. {
  149. return w*w+x*x+y*y+z*z;
  150. }
  151. Number Quaternion::Normalize()
  152. {
  153. Number len = Norm();
  154. Number factor = 1.0f / sqrtf(len);
  155. *this = *this * factor;
  156. return len;
  157. }
  158. Quaternion Quaternion::Slerp(Number fT, const Quaternion& rkP, const Quaternion& rkQ, bool shortestPath)
  159. {
  160. Number fCos = rkP.Dot(rkQ);
  161. Quaternion rkT;
  162. // Do we need to invert rotation?
  163. if (fCos < 0.0f && shortestPath)
  164. {
  165. fCos = -fCos;
  166. rkT = -rkQ;
  167. }
  168. else
  169. {
  170. rkT = rkQ;
  171. }
  172. if (fabs(fCos) < 1 - 1e-03)
  173. {
  174. // Standard case (slerp)
  175. Number fSin = sqrtf(1 - (fCos*fCos));
  176. Number fAngle = atan2f(fSin, fCos);
  177. Number fInvSin = 1.0f / fSin;
  178. Number fCoeff0 = sinf((1.0f - fT) * fAngle) * fInvSin;
  179. Number fCoeff1 = sinf(fT * fAngle) * fInvSin;
  180. return fCoeff0 * rkP + fCoeff1 * rkT;
  181. }
  182. else
  183. {
  184. // There are two situations:
  185. // 1. "rkP" and "rkQ" are very close (fCos ~= +1), so we can do a linear
  186. // interpolation safely.
  187. // 2. "rkP" and "rkQ" are almost inverse of each other (fCos ~= -1), there
  188. // are an infinite number of possibilities interpolation. but we haven't
  189. // have method to fix this case, so just use linear interpolation here.
  190. Quaternion t = (1.0f - fT) * rkP + fT * rkT;
  191. // taking the complement requires renormalisation
  192. t.Normalize();
  193. return t;
  194. }
  195. }
  196. Quaternion Quaternion::Squad (Number fT,
  197. const Quaternion& rkP, const Quaternion& rkA,
  198. const Quaternion& rkB, const Quaternion& rkQ, bool shortestPath)
  199. {
  200. Number fSlerpT = 2.0*fT*(1.0-fT);
  201. Quaternion kSlerpP = Slerp(fT, rkP, rkQ, shortestPath);
  202. Quaternion kSlerpQ = Slerp(fT, rkA, rkB, shortestPath);
  203. return Slerp(fSlerpT, kSlerpP ,kSlerpQ, shortestPath);
  204. }
  205. Quaternion Quaternion::operator *(Quaternion q)
  206. {
  207. Quaternion r;
  208. r.w = w*q.w - x*q.x - y*q.y - z*q.z;
  209. r.x = w*q.x + x*q.w + y*q.z - z*q.y;
  210. r.y = w*q.y + y*q.w + z*q.x - x*q.z;
  211. r.z = w*q.z + z*q.w + x*q.y - y*q.x;
  212. return r;
  213. }