PolyQuaternion.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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. #pragma once
  20. #include "PolyGlobals.h"
  21. #include "PolyMatrix4.h"
  22. #include "PolyVector3.h"
  23. namespace Polycode {
  24. /**
  25. * Rotation quaternion.
  26. */
  27. class _PolyExport Quaternion : public PolyBase {
  28. public:
  29. /**
  30. * Construct from w,x,y,z values.
  31. * @param w W value.
  32. * @param x X value.
  33. * @param y Y value.
  34. * @param z Z value.
  35. */
  36. Quaternion(Number w, Number x, Number y, Number z) {
  37. set(w,x,y,z);
  38. }
  39. /**
  40. * Default constructor.
  41. */
  42. Quaternion();
  43. ~Quaternion();
  44. // ----------------------------------------------------------------------------------------------------------------
  45. /** @name Public members
  46. * Available public members
  47. */
  48. //@{
  49. inline void setFromMatrix(const Matrix4 &_mat) {
  50. Number fTrace = _mat.m[0][0]+_mat.m[1][1]+_mat.m[2][2];
  51. Number fRoot;
  52. if ( fTrace > 0.0 ) {
  53. fRoot = sqrtf(fTrace + 1.0); // 2w
  54. w = 0.5*fRoot;
  55. fRoot = 0.5/fRoot;
  56. x = (_mat.m[2][1]-_mat.m[1][2])*fRoot;
  57. y = (_mat.m[0][2]-_mat.m[2][0])*fRoot;
  58. z = (_mat.m[1][0]-_mat.m[0][1])*fRoot;
  59. }
  60. else
  61. {
  62. static size_t s_iNext[3] = { 1, 2, 0 };
  63. size_t i = 0;
  64. if ( _mat.m[1][1] > _mat.m[0][0] )
  65. i = 1;
  66. if ( _mat.m[2][2] > _mat.m[i][i] )
  67. i = 2;
  68. size_t j = s_iNext[i];
  69. size_t k = s_iNext[j];
  70. fRoot = sqrtf(_mat.m[i][i]-_mat.m[j][j]-_mat.m[k][k] + 1.0);
  71. Number* apkQuat[3] = { &x, &y, &z };
  72. *apkQuat[i] = 0.5*fRoot;
  73. fRoot = 0.5/fRoot;
  74. w = (_mat.m[k][j]-_mat.m[j][k])*fRoot;
  75. *apkQuat[j] = (_mat.m[j][i]+_mat.m[i][j])*fRoot;
  76. *apkQuat[k] = (_mat.m[k][i]+_mat.m[i][k])*fRoot;
  77. }
  78. }
  79. static Quaternion Slerp(Number fT, const Quaternion& rkP, const Quaternion& rkQ, bool shortestPath=false);
  80. Number Dot(const Quaternion& rkQ) const;
  81. Quaternion Log () const;
  82. Quaternion Exp () const;
  83. Number Norm () const;
  84. Number Normalize();
  85. Quaternion operator+ (const Quaternion& rkQ) const;
  86. Quaternion operator* (const Quaternion& rkQ) const;
  87. Quaternion operator* (Number fScalar) const;
  88. // TODO: implement
  89. inline void lookAt(const Vector3 &D, const Vector3 &upVector) {
  90. /*
  91. Vector3 D;
  92. Vector3 back = D * -1;
  93. back.Normalize();
  94. Vector3 right = back.crossProduct(upVector) ;
  95. right.Normalize();
  96. right = right * -1;
  97. Vector3 up = back.crossProduct(right);
  98. set( y.z - z.y , z.x - x.z, x.y - y.x, tr + 1.0f );
  99. */
  100. }
  101. void createFromMatrix(const Matrix4& matrix) {
  102. Number tr, s, q[4];
  103. int i, j, k;
  104. static const int nxt[3] = {1, 2, 0};
  105. tr = matrix.m[0][0] + matrix.m[1][1] + matrix.m[2][2];
  106. // check the diagonal
  107. if (tr > 0.0f)
  108. {
  109. s = sqrtf(tr + 1.0f);
  110. w = s / 2.0f;
  111. s = 0.5f / s;
  112. x = (matrix.m[1][2] - matrix.m[2][1]) * s;
  113. y = (matrix.m[2][0] - matrix.m[0][2]) * s;
  114. z = (matrix.m[0][1] - matrix.m[1][0]) * s;
  115. }
  116. else
  117. {
  118. // diagonal is negative
  119. i = 0;
  120. if (matrix.m[1][1] > matrix.m[0][0]) i = 1;
  121. if (matrix.m[2][2] > matrix.m[i][i]) i = 2;
  122. j = nxt[i];
  123. k = nxt[j];
  124. s = sqrtf((matrix.m[i][i] - (matrix.m[j][j] + matrix.m[k][k])) + 1.0f);
  125. q[i] = s * 0.5f;
  126. if (s != 0.0f) s = 0.5f / s;
  127. q[3] = (matrix.m[j][k] - matrix.m[k][j]) * s;
  128. q[j] = (matrix.m[i][j] + matrix.m[j][i]) * s;
  129. q[k] = (matrix.m[i][k] + matrix.m[k][i]) * s;
  130. x = q[0];
  131. y = q[1];
  132. z = q[2];
  133. w = q[3];
  134. }
  135. }
  136. inline bool operator== (const Quaternion& rhs) const
  137. {
  138. return (rhs.x == x) && (rhs.y == y) &&
  139. (rhs.z == z) && (rhs.w == w);
  140. }
  141. inline bool operator!= (const Quaternion& rhs) const
  142. {
  143. return (rhs.x != x) && (rhs.y != y) &&
  144. (rhs.z != z) && (rhs.w != w);
  145. }
  146. static Quaternion Squad(Number fT, const Quaternion& rkP, const Quaternion& rkA, const Quaternion& rkB, const Quaternion& rkQ, bool shortestPath);
  147. Quaternion Inverse() const;
  148. Quaternion operator- () const
  149. {
  150. return Quaternion(-w,-x,-y,-z);
  151. }
  152. void set(Number w, Number x, Number y, Number z) {
  153. this->w = w;
  154. this->x = x;
  155. this->y = y;
  156. this->z = z;
  157. }
  158. Quaternion Inverse() {
  159. Number fNorm = w*w+x*x+y*y+z*z;
  160. Number fInvNorm = 1.0/fNorm;
  161. return Quaternion(w*fInvNorm,-x*fInvNorm,-y*fInvNorm,-z*fInvNorm);
  162. }
  163. Number InvSqrt(Number x) {
  164. Number xhalf = 0.5f * x;
  165. int i = *(int*)&x; // store Numbering-point bits in integer
  166. i = 0x5f3759d5 - (i >> 1); // initial guess for Newton's method
  167. x = *(Number*)&i; // convert new bits into Number
  168. x = x*(1.5f - xhalf*x*x); // One round of Newton's method
  169. return x;
  170. }
  171. inline void fromAxes(Number az, Number ay, Number ax) {
  172. ax *= TORADIANS;
  173. ay *= TORADIANS;
  174. az *= TORADIANS;
  175. Number c1 = cos(ay / 2.0f);
  176. Number c2 = cos(ax / 2.0f);
  177. Number c3 = cos(az / 2.0f);
  178. Number s1 = sin(ay / 2.0f);
  179. Number s2 = sin(ax / 2.0f);
  180. Number s3 = sin(az / 2.0f);
  181. w = (c1*c2*c3) - (s1*s2*s3);
  182. x = (s1*s2*c3) + (c1*c2*s3);
  183. y = (s1*c2*c3) + (c1*s2*s3);
  184. z = (c1*s2*c3) - (s1*c2*s3);
  185. }
  186. void fromAngleAxis(const Number& rfAngle,
  187. const Vector3& rkAxis)
  188. {
  189. Number fHalfAngle ( 0.5*rfAngle );
  190. Number fSin = sin(fHalfAngle);
  191. w = cos(fHalfAngle);
  192. x = fSin*rkAxis.x;
  193. y = fSin*rkAxis.y;
  194. z = fSin*rkAxis.z;
  195. }
  196. Vector3 toEulerAngles () const {
  197. return Vector3(atan2( 2 * ( w * x + y * z), 1 - 2 * (x * x + y * y)), asin(2 * ( w * y - z * x)), atan2( 2 * ( w * z + x * y), 1 - 2 * (y * y + z * z) ));
  198. }
  199. //-----------------------------------------------------------------------
  200. void toAngleAxis (Number& rfAngle, Vector3& rkAxis)
  201. {
  202. // The quaternion representing the rotation is
  203. // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
  204. Number fSqrLength = x*x+y*y+z*z;
  205. if ( fSqrLength > 0.0 )
  206. {
  207. rfAngle = 2.0*acos(w);
  208. Number fInvLength = InvSqrt(fSqrLength);
  209. rkAxis.x = x*fInvLength;
  210. rkAxis.y = y*fInvLength;
  211. rkAxis.z = z*fInvLength;
  212. }
  213. else
  214. {
  215. // angle is 0 (mod 2*pi), so any axis will do
  216. rfAngle = Number(0.0);
  217. rkAxis.x = 1.0;
  218. rkAxis.y = 0.0;
  219. rkAxis.z = 0.0;
  220. }
  221. }
  222. void createFromAxisAngle(Number x, Number y, Number z, Number degrees);
  223. Matrix4 createMatrix() const;
  224. /**
  225. * Rotate a Vector3 by this Quaternion.
  226. * @param v Vector to operate on.
  227. */
  228. Vector3 applyTo(Vector3 v) const
  229. {
  230. const Quaternion &q = *this;
  231. Quaternion result = q * Quaternion(0,v.x,v.y,v.z) * q.Inverse();
  232. return Vector3(result.x,result.y,result.z);
  233. }
  234. Quaternion operator *(Quaternion q);
  235. Number x;
  236. Number y;
  237. Number z;
  238. Number w;
  239. //@}
  240. protected:
  241. };
  242. }