PolyQuaternion.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * PolyQuaternion.cpp
  3. * TAU
  4. *
  5. * Created by Ivan Safrin on 3/26/08.
  6. * Copyright 2008 __MyCompanyName__. All rights reserved.
  7. *
  8. */
  9. #include "PolyQuaternion.h"
  10. using namespace Polycode;
  11. Quaternion::Quaternion() : x(0), y(0), z(0), w(1.0f) {
  12. }
  13. Quaternion::~Quaternion() {
  14. }
  15. void Quaternion::createFromAxisAngle(float ax, float ay, float az, float degrees)
  16. {
  17. float angle = float((degrees / 180.0f) * PI);
  18. float result = (float)sin( angle / 2.0f );
  19. w = (float)cos( angle / 2.0f );
  20. x = float(ax * result);
  21. y = float(ay * result);
  22. z = float(az * result);
  23. }
  24. Matrix4 Quaternion::createMatrix()
  25. {
  26. Matrix4 m;
  27. float fTx = 2.0*x;
  28. float fTy = 2.0*y;
  29. float fTz = 2.0*z;
  30. float fTwx = fTx*w;
  31. float fTwy = fTy*w;
  32. float fTwz = fTz*w;
  33. float fTxx = fTx*x;
  34. float fTxy = fTy*x;
  35. float fTxz = fTz*x;
  36. float fTyy = fTy*y;
  37. float fTyz = fTz*y;
  38. float fTzz = fTz*z;
  39. m[0][0] = 1.0-(fTyy+fTzz);
  40. m[1][0] = fTxy-fTwz;
  41. m[2][0] = fTxz+fTwy;
  42. m[0][1] = fTxy+fTwz;
  43. m[1][1] = 1.0-(fTxx+fTzz);
  44. m[2][1] = fTyz-fTwx;
  45. m[0][2] = fTxz-fTwy;
  46. m[1][2] = fTyz+fTwx;
  47. m[2][2] = 1.0-(fTxx+fTyy);
  48. return m;
  49. }
  50. float Quaternion::Dot (const Quaternion& rkQ) const
  51. {
  52. return w*rkQ.w+x*rkQ.x+y*rkQ.y+z*rkQ.z;
  53. }
  54. Quaternion Quaternion::operator* (const Quaternion& rkQ) const
  55. {
  56. return Quaternion
  57. (
  58. w * rkQ.w - x * rkQ.x - y * rkQ.y - z * rkQ.z,
  59. w * rkQ.x + x * rkQ.w + y * rkQ.z - z * rkQ.y,
  60. w * rkQ.y + y * rkQ.w + z * rkQ.x - x * rkQ.z,
  61. w * rkQ.z + z * rkQ.w + x * rkQ.y - y * rkQ.x
  62. );
  63. }
  64. Quaternion Quaternion::operator* (float fScalar) const
  65. {
  66. return Quaternion(fScalar*w,fScalar*x,fScalar*y,fScalar*z);
  67. }
  68. Quaternion operator* (float fScalar, const Quaternion& rkQ)
  69. {
  70. return Quaternion(fScalar*rkQ.w,fScalar*rkQ.x,fScalar*rkQ.y,
  71. fScalar*rkQ.z);
  72. }
  73. Quaternion Quaternion::operator+ (const Quaternion& rkQ) const
  74. {
  75. return Quaternion(w+rkQ.w,x+rkQ.x,y+rkQ.y,z+rkQ.z);
  76. }
  77. Quaternion Quaternion::Exp () const
  78. {
  79. // If q = A*(x*i+y*j+z*k) where (x,y,z) is unit length, then
  80. // exp(q) = cos(A)+sin(A)*(x*i+y*j+z*k). If sin(A) is near zero,
  81. // use exp(q) = cos(A)+A*(x*i+y*j+z*k) since A/sin(A) has limit 1.
  82. float fAngle ( sqrtf(x*x+y*y+z*z) );
  83. float fSin = sinf(fAngle);
  84. Quaternion kResult;
  85. kResult.w = cosf(fAngle);
  86. if ( fabs(fSin) >= 1e-03 )
  87. {
  88. float fCoeff = fSin/fAngle;
  89. kResult.x = fCoeff*x;
  90. kResult.y = fCoeff*y;
  91. kResult.z = fCoeff*z;
  92. }
  93. else
  94. {
  95. kResult.x = x;
  96. kResult.y = y;
  97. kResult.z = z;
  98. }
  99. return kResult;
  100. }
  101. Quaternion Quaternion::Inverse () const
  102. {
  103. float fNorm = w*w+x*x+y*y+z*z;
  104. if ( fNorm > 0.0 )
  105. {
  106. float fInvNorm = 1.0/fNorm;
  107. return Quaternion(w*fInvNorm,-x*fInvNorm,-y*fInvNorm,-z*fInvNorm);
  108. }
  109. else
  110. {
  111. // return an invalid result to flag the error
  112. return Quaternion(0,0,0,0);
  113. }
  114. }
  115. Quaternion Quaternion::Log () const
  116. {
  117. Quaternion kResult;
  118. kResult.w = 0.0;
  119. if ( fabs(w) < 1.0 )
  120. {
  121. float fAngle ( acosf(w) );
  122. float fSin = sinf(fAngle);
  123. if ( fabs(fSin) >= 1e-03 )
  124. {
  125. float fCoeff = fAngle/fSin;
  126. kResult.x = fCoeff*x;
  127. kResult.y = fCoeff*y;
  128. kResult.z = fCoeff*z;
  129. return kResult;
  130. }
  131. }
  132. kResult.x = x;
  133. kResult.y = y;
  134. kResult.z = z;
  135. return kResult;
  136. }
  137. float Quaternion::Norm () const
  138. {
  139. return w*w+x*x+y*y+z*z;
  140. }
  141. float Quaternion::normalise(void)
  142. {
  143. float len = Norm();
  144. float factor = 1.0f / sqrtf(len);
  145. *this = *this * factor;
  146. return len;
  147. }
  148. Quaternion Quaternion::Slerp(float fT, const Quaternion& rkP, const Quaternion& rkQ, bool shortestPath)
  149. {
  150. float fCos = rkP.Dot(rkQ);
  151. Quaternion rkT;
  152. // Do we need to invert rotation?
  153. if (fCos < 0.0f && shortestPath)
  154. {
  155. fCos = -fCos;
  156. rkT = -rkQ;
  157. }
  158. else
  159. {
  160. rkT = rkQ;
  161. }
  162. if (fabs(fCos) < 1 - 1e-03)
  163. {
  164. // Standard case (slerp)
  165. float fSin = sqrtf(1 - (fCos*fCos));
  166. float fAngle = atan2f(fSin, fCos);
  167. float fInvSin = 1.0f / fSin;
  168. float fCoeff0 = sinf((1.0f - fT) * fAngle) * fInvSin;
  169. float fCoeff1 = sinf(fT * fAngle) * fInvSin;
  170. return fCoeff0 * rkP + fCoeff1 * rkT;
  171. }
  172. else
  173. {
  174. // There are two situations:
  175. // 1. "rkP" and "rkQ" are very close (fCos ~= +1), so we can do a linear
  176. // interpolation safely.
  177. // 2. "rkP" and "rkQ" are almost inverse of each other (fCos ~= -1), there
  178. // are an infinite number of possibilities interpolation. but we haven't
  179. // have method to fix this case, so just use linear interpolation here.
  180. Quaternion t = (1.0f - fT) * rkP + fT * rkT;
  181. // taking the complement requires renormalisation
  182. t.normalise();
  183. return t;
  184. }
  185. }
  186. Quaternion Quaternion::Squad (float fT,
  187. const Quaternion& rkP, const Quaternion& rkA,
  188. const Quaternion& rkB, const Quaternion& rkQ, bool shortestPath)
  189. {
  190. float fSlerpT = 2.0*fT*(1.0-fT);
  191. Quaternion kSlerpP = Slerp(fT, rkP, rkQ, shortestPath);
  192. Quaternion kSlerpQ = Slerp(fT, rkA, rkB);
  193. return Slerp(fSlerpT, kSlerpP ,kSlerpQ);
  194. }
  195. Quaternion Quaternion::operator *(Quaternion q)
  196. {
  197. Quaternion r;
  198. r.w = w*q.w - x*q.x - y*q.y - z*q.z;
  199. r.x = w*q.x + x*q.w + y*q.z - z*q.y;
  200. r.y = w*q.y + y*q.w + z*q.x - x*q.z;
  201. r.z = w*q.z + z*q.w + x*q.y - y*q.x;
  202. return r;
  203. }