quaternion.h
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:20k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // quaternion.h
  2. // 
  3. // Copyright (C) 2000-2006, Chris Laurel <claurel@shatters.net>
  4. //
  5. // Template-ized quaternion math library.
  6. //
  7. // This program is free software; you can redistribute it and/or
  8. // modify it under the terms of the GNU General Public License
  9. // as published by the Free Software Foundation; either version 2
  10. // of the License, or (at your option) any later version.
  11. #ifndef _QUATERNION_H_
  12. #define _QUATERNION_H_
  13. #include <limits>
  14. #include <celmath/mathlib.h>
  15. #include <celmath/vecmath.h>
  16. template<class T> class Quaternion
  17. {
  18. public:
  19.     inline Quaternion();
  20.     inline Quaternion(const Quaternion<T>&);
  21.     inline Quaternion(T);
  22.     inline Quaternion(const Vector3<T>&);
  23.     inline Quaternion(T, const Vector3<T>&);
  24.     inline Quaternion(T, T, T, T);
  25.     inline Quaternion(const Matrix3<T>&);
  26.     inline Quaternion& operator+=(Quaternion);
  27.     inline Quaternion& operator-=(Quaternion);
  28.     inline Quaternion& operator*=(T);
  29.     Quaternion& operator*=(Quaternion);
  30.     inline Quaternion operator~() const;    // conjugate
  31.     inline Quaternion operator-() const;
  32.     inline Quaternion operator+() const;
  33.     void setAxisAngle(Vector3<T> axis, T angle);
  34.     void getAxisAngle(Vector3<T>& axis, T& angle) const;
  35.     Matrix4<T> toMatrix4() const;
  36.     Matrix3<T> toMatrix3() const;
  37.     static Quaternion<T> slerp(const Quaternion<T>&, const Quaternion<T>&, T);
  38.     static Quaternion<T> vecToVecRotation(const Vector3<T>& v0,
  39.                                           const Vector3<T>& v1);
  40.     static Quaternion<T> matrixToQuaternion(const Matrix3<T>& m);
  41.     void rotate(Vector3<T> axis, T angle);
  42.     void xrotate(T angle);
  43.     void yrotate(T angle);
  44.     void zrotate(T angle);
  45.     bool isPure() const;
  46.     bool isReal() const;
  47.     T normalize();
  48.     static Quaternion<T> xrotation(T);
  49.     static Quaternion<T> yrotation(T);
  50.     static Quaternion<T> zrotation(T);
  51. static Quaternion<T> lookAt(const Point3<T>& from, const Point3<T>& to, const Vector3<T>& up);
  52.     T w, x, y, z;
  53. };
  54. typedef Quaternion<float> Quatf;
  55. typedef Quaternion<double> Quatd;
  56. template<class T> Quaternion<T>::Quaternion() : w(0), x(0), y(0), z(0)
  57. {
  58. }
  59. template<class T> Quaternion<T>::Quaternion(const Quaternion<T>& q) :
  60.     w(q.w), x(q.x), y(q.y), z(q.z)
  61. {
  62. }
  63. template<class T> Quaternion<T>::Quaternion(T re) :
  64.     w(re), x(0), y(0), z(0)
  65. {
  66. }
  67. // Create a 'pure' quaternion
  68. template<class T> Quaternion<T>::Quaternion(const Vector3<T>& im) :
  69.      w(0), x(im.x), y(im.y), z(im.z)
  70. {
  71. }
  72. template<class T> Quaternion<T>::Quaternion(T re, const Vector3<T>& im) :
  73.      w(re), x(im.x), y(im.y), z(im.z)
  74. {
  75. }
  76. template<class T> Quaternion<T>::Quaternion(T _w, T _x, T _y, T _z) :
  77.     w(_w), x(_x), y(_y), z(_z)
  78. {
  79. }
  80. // Create a quaternion from a rotation matrix
  81. // TODO: purge this from code--it is replaced by the matrixToQuaternion()
  82. // function.
  83. template<class T> Quaternion<T>::Quaternion(const Matrix3<T>& m)
  84. {
  85.     T trace = m[0][0] + m[1][1] + m[2][2];
  86.     T root;
  87.     if (trace >= (T) -1.0 + 1.0e-4f)
  88.     {
  89.         root = (T) sqrt(trace + 1);
  90.         w = (T) 0.5 * root;
  91.         root = (T) 0.5 / root;
  92.         x = (m[2][1] - m[1][2]) * root;
  93.         y = (m[0][2] - m[2][0]) * root;
  94.         z = (m[1][0] - m[0][1]) * root;
  95.     }
  96.     else
  97.     {
  98.         // Identify the largest element of the diagonal
  99.         int i = 0;
  100.         if (m[1][1] > m[i][i])
  101.             i = 1;
  102.         if (m[2][2] > m[i][i])
  103.             i = 2;
  104.         int j = (i == 2) ? 0 : i + 1;
  105.         int k = (j == 2) ? 0 : j + 1;
  106.         root = (T) sqrt(m[i][i] - m[j][j] - m[k][k] + 1);
  107.         T* xyz[3] = { &x, &y, &z };
  108.         *xyz[i] = (T) 0.5 * root;
  109.         root = (T) 0.5 / root;
  110.         w = (m[k][j] - m[j][k]) * root;
  111.         *xyz[j] = (m[j][i] + m[i][j]) * root;
  112.         *xyz[k] = (m[k][i] + m[i][k]) * root;
  113.     }
  114. }
  115. template<class T> Quaternion<T>& Quaternion<T>::operator+=(Quaternion<T> a)
  116. {
  117.     x += a.x; y += a.y; z += a.z; w += a.w;
  118.     return *this;
  119. }
  120. template<class T> Quaternion<T>& Quaternion<T>::operator-=(Quaternion<T> a)
  121. {
  122.     x -= a.x; y -= a.y; z -= a.z; w -= a.w;
  123.     return *this;
  124. }
  125. template<class T> Quaternion<T>& Quaternion<T>::operator*=(Quaternion<T> q)
  126. {
  127.     *this = Quaternion<T>(w * q.w - x * q.x - y * q.y - z * q.z,
  128.                           w * q.x + x * q.w + y * q.z - z * q.y,
  129.                           w * q.y + y * q.w + z * q.x - x * q.z,
  130.                           w * q.z + z * q.w + x * q.y - y * q.x);
  131.                           
  132.     return *this;
  133. }
  134. template<class T> Quaternion<T>& Quaternion<T>::operator*=(T s)
  135. {
  136.     x *= s; y *= s; z *= s; w *= s;
  137.     return *this;
  138. }
  139. // conjugate operator
  140. template<class T> Quaternion<T> Quaternion<T>::operator~() const
  141. {
  142.     return Quaternion<T>(w, -x, -y, -z);
  143. }
  144. template<class T> Quaternion<T> Quaternion<T>::operator-() const
  145. {
  146.     return Quaternion<T>(-w, -x, -y, -z);
  147. }
  148. template<class T> Quaternion<T> Quaternion<T>::operator+() const
  149. {
  150.     return *this;
  151. }
  152. template<class T> Quaternion<T> operator+(Quaternion<T> a, Quaternion<T> b)
  153. {
  154.     return Quaternion<T>(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z);
  155. }
  156. template<class T> Quaternion<T> operator-(Quaternion<T> a, Quaternion<T> b)
  157. {
  158.     return Quaternion<T>(a.w - b.w, a.x - b.x, a.y - b.y, a.z - b.z);
  159. }
  160. template<class T> Quaternion<T> operator*(Quaternion<T> a, Quaternion<T> b)
  161. {
  162.     return Quaternion<T>(a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
  163.                          a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
  164.                          a.w * b.y + a.y * b.w + a.z * b.x - a.x * b.z,
  165.                          a.w * b.z + a.z * b.w + a.x * b.y - a.y * b.x);
  166. }
  167. template<class T> Quaternion<T> operator*(T s, Quaternion<T> q)
  168. {
  169.     return Quaternion<T>(s * q.w, s * q.x, s * q.y, s * q.z);
  170. }
  171. template<class T> Quaternion<T> operator*(Quaternion<T> q, T s)
  172. {
  173.     return Quaternion<T>(s * q.w, s * q.x, s * q.y, s * q.z);
  174. }
  175. // equivalent to multiplying by the quaternion (0, v)
  176. template<class T> Quaternion<T> operator*(Vector3<T> v, Quaternion<T> q)
  177. {
  178.     return Quaternion<T>(-v.x * q.x - v.y * q.y - v.z * q.z,
  179.                          v.x * q.w + v.y * q.z - v.z * q.y,
  180.                          v.y * q.w + v.z * q.x - v.x * q.z,
  181.                          v.z * q.w + v.x * q.y - v.y * q.x);
  182. }
  183. template<class T> Quaternion<T> operator/(Quaternion<T> q, T s)
  184. {
  185.     return q * (1 / s);
  186. }
  187. template<class T> Quaternion<T> operator/(Quaternion<T> a, Quaternion<T> b)
  188. {
  189.     return a * (~b / abs(b));
  190. }
  191. template<class T> bool operator==(Quaternion<T> a, Quaternion<T> b)
  192. {
  193.     return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w;
  194. }
  195. template<class T> bool operator!=(Quaternion<T> a, Quaternion<T> b)
  196. {
  197.     return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w;
  198. }
  199. // elementary functions
  200. template<class T> Quaternion<T> conjugate(Quaternion<T> q)
  201. {
  202.     return Quaternion<T>(q.w, -q.x, -q.y, -q.z);
  203. }
  204. template<class T> T norm(Quaternion<T> q)
  205. {
  206.     return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
  207. }
  208. template<class T> T abs(Quaternion<T> q)
  209. {
  210.     return (T) sqrt(norm(q));
  211. }
  212. template<class T> Quaternion<T> exp(Quaternion<T> q)
  213. {
  214.     if (q.isReal())
  215.     {
  216.         return Quaternion<T>((T) exp(q.w));
  217.     }
  218.     else
  219.     {
  220.         T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
  221.         T s = (T) sin(l);
  222.         T c = (T) cos(l);
  223.         T e = (T) exp(q.w);
  224.         T t = e * s / l;
  225.         return Quaternion<T>(e * c, t * q.x, t * q.y, t * q.z);
  226.     }
  227. }
  228. template<class T> Quaternion<T> log(Quaternion<T> q)
  229. {
  230.     if (q.isReal())
  231.     {
  232.         if (q.w > 0)
  233.         {
  234.             return Quaternion<T>((T) log(q.w));
  235.         }
  236.         else if (q.w < 0)
  237.         {
  238.             // The log of a negative purely real quaternion has
  239.             // infinitely many values, all of the form (ln(-w), PI * I),
  240.             // where I is any unit vector.  We arbitrarily choose an I
  241.             // of (1, 0, 0) here and whereever else a similar choice is
  242.             // necessary.  Geometrically, the set of roots is a sphere
  243.             // of radius PI centered at ln(-w) on the real axis.
  244.             return Quaternion<T>((T) log(-q.w), (T) PI, 0, 0);
  245.         }
  246.         else
  247.         {
  248.             // error . . . ln(0) not defined
  249.             return Quaternion<T>(0);
  250.         }
  251.     }
  252.     else
  253.     {
  254.         T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
  255.         T r = (T) sqrt(l * l + q.w * q.w);
  256.         T theta = (T) atan2(l, q.w);
  257.         T t = theta / l;
  258.         return Quaternion<T>((T) log(r), t * q.x, t * q.y, t * q.z);
  259.     }
  260. }
  261. template<class T> Quaternion<T> pow(Quaternion<T> q, T s)
  262. {
  263.     return exp(s * log(q));
  264. }
  265. template<class T> Quaternion<T> pow(Quaternion<T> q, Quaternion<T> p)
  266. {
  267.     return exp(p * log(q));
  268. }
  269. template<class T> Quaternion<T> sin(Quaternion<T> q)
  270. {
  271.     if (q.isReal())
  272.     {
  273.         return Quaternion<T>((T) sin(q.w));
  274.     }
  275.     else
  276.     {
  277.         T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
  278.         T m = q.w;
  279.         T s = (T) sin(m);
  280.         T c = (T) cos(m);
  281.         T il = 1 / l;
  282.         T e0 = (T) exp(-l);
  283.         T e1 = (T) exp(l);
  284.         T c0 = (T) -0.5 * e0 * il * c;
  285.         T c1 = (T)  0.5 * e1 * il * c;
  286.         return Quaternion<T>((T) 0.5 * e0 * s, c0 * q.x, c0 * q.y, c0 * q.z) +
  287.             Quaternion<T>((T) 0.5 * e1 * s, c1 * q.x, c1 * q.y, c1 * q.z);
  288.     }
  289. }
  290. template<class T> Quaternion<T> cos(Quaternion<T> q)
  291. {
  292.     if (q.isReal())
  293.     {
  294.         return Quaternion<T>((T) cos(q.w));
  295.     }
  296.     else
  297.     {
  298.         T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
  299.         T m = q.w;
  300.         T s = (T) sin(m);
  301.         T c = (T) cos(m);
  302.         T il = 1 / l;
  303.         T e0 = (T) exp(-l);
  304.         T e1 = (T) exp(l);
  305.         T c0 = (T)  0.5 * e0 * il * s;
  306.         T c1 = (T) -0.5 * e1 * il * s;
  307.         return Quaternion<T>((T) 0.5 * e0 * c, c0 * q.x, c0 * q.y, c0 * q.z) +
  308.             Quaternion<T>((T) 0.5 * e1 * c, c1 * q.x, c1 * q.y, c1 * q.z);
  309.     }
  310. }
  311. template<class T> Quaternion<T> sqrt(Quaternion<T> q)
  312. {
  313.     // In general, the square root of a quaternion has two values, one
  314.     // of which is the negative of the other.  However, any negative purely
  315.     // real quaternion has an infinite number of square roots.
  316.     // This function returns the positive root for positive reals and
  317.     // the root on the positive i axis for negative reals.
  318.     if (q.isReal())
  319.     {
  320.         if (q.w >= 0)
  321.             return Quaternion<T>((T) sqrt(q.w), 0, 0, 0);
  322.         else
  323.             return Quaternion<T>(0, (T) sqrt(-q.w), 0, 0);
  324.     }
  325.     else
  326.     {
  327.         T b = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
  328.         T r = (T) sqrt(q.w * q.w + b * b);
  329.         if (q.w >= 0)
  330.         {
  331.             T m = (T) sqrt((T) 0.5 * (r + q.w));
  332.             T l = b / (2 * m);
  333.             T t = l / b;
  334.             return Quaternion<T>(m, q.x * t, q.y * t, q.z * t);
  335.         }
  336.         else
  337.         {
  338.             T l = (T) sqrt((T) 0.5 * (r - q.w));
  339.             T m = b / (2 * l);
  340.             T t = l / b;
  341.             return Quaternion<T>(m, q.x * t, q.y * t, q.z * t);
  342.         }
  343.     }
  344. }
  345. template<class T> T real(Quaternion<T> q)
  346. {
  347.     return q.w;
  348. }
  349. template<class T> Vector3<T> imag(Quaternion<T> q)
  350. {
  351.     return Vector3<T>(q.x, q.y, q.z);
  352. }
  353. // Quaternion methods
  354. template<class T> bool Quaternion<T>::isReal() const
  355. {
  356.     return (x == 0 && y == 0 && z == 0);
  357. }
  358. template<class T> bool Quaternion<T>::isPure() const
  359. {
  360.     return w == 0;
  361. }
  362. template<class T> T Quaternion<T>::normalize()
  363. {
  364.     T s = (T) sqrt(w * w + x * x + y * y + z * z);
  365.     T invs = (T) 1 / (T) s;
  366.     x *= invs;
  367.     y *= invs;
  368.     z *= invs;
  369.     w *= invs;
  370.     return s;
  371. }
  372. // Set to the unit quaternion representing an axis angle rotation.  Assume
  373. // that axis is a unit vector
  374. template<class T> void Quaternion<T>::setAxisAngle(Vector3<T> axis, T angle)
  375. {
  376.     T s, c;
  377.     
  378.     Math<T>::sincos(angle * (T) 0.5, s, c);
  379.     x = s * axis.x;
  380.     y = s * axis.y;
  381.     z = s * axis.z;
  382.     w = c;
  383. }
  384. // Assuming that this a unit quaternion, return the in axis/angle form the
  385. // orientation which it represents.
  386. template<class T> void Quaternion<T>::getAxisAngle(Vector3<T>& axis,
  387.                                                    T& angle) const
  388. {
  389.     // The quaternion has the form:
  390.     // w = cos(angle/2), (x y z) = sin(angle/2)*axis
  391.     T magSquared = x * x + y * y + z * z;
  392.     if (magSquared > (T) 1e-10)
  393.     {
  394.         T s =  (T) 1 / (T) sqrt(magSquared);
  395.         axis.x = x * s;
  396.         axis.y = y * s;
  397.         axis.z = z * s;
  398.         if (w <= -1 || w >= 1)
  399.             angle = 0;
  400.         else
  401.             angle = (T) acos(w) * 2;
  402.     }
  403.     else
  404.     {
  405.         // The angle is zero, so we pick an arbitrary unit axis
  406.         axis.x = 1;
  407.         axis.y = 0;
  408.         axis.z = 0;
  409.         angle = 0;
  410.     }
  411. }
  412. // Convert this (assumed to be normalized) quaternion to a rotation matrix
  413. template<class T> Matrix4<T> Quaternion<T>::toMatrix4() const
  414. {
  415.     T wx = w * x * 2;
  416.     T wy = w * y * 2;
  417.     T wz = w * z * 2;
  418.     T xx = x * x * 2;
  419.     T xy = x * y * 2;
  420.     T xz = x * z * 2;
  421.     T yy = y * y * 2;
  422.     T yz = y * z * 2;
  423.     T zz = z * z * 2;
  424.     return Matrix4<T>(Vector4<T>(1 - yy - zz, xy - wz, xz + wy, 0),
  425.                       Vector4<T>(xy + wz, 1 - xx - zz, yz - wx, 0),
  426.                       Vector4<T>(xz - wy, yz + wx, 1 - xx - yy, 0),
  427.                       Vector4<T>(0, 0, 0, 1));
  428. }
  429. // Convert this (assumed to be normalized) quaternion to a rotation matrix
  430. template<class T> Matrix3<T> Quaternion<T>::toMatrix3() const
  431. {
  432.     T wx = w * x * 2;
  433.     T wy = w * y * 2;
  434.     T wz = w * z * 2;
  435.     T xx = x * x * 2;
  436.     T xy = x * y * 2;
  437.     T xz = x * z * 2;
  438.     T yy = y * y * 2;
  439.     T yz = y * z * 2;
  440.     T zz = z * z * 2;
  441.     return Matrix3<T>(Vector3<T>(1 - yy - zz, xy - wz, xz + wy),
  442.                       Vector3<T>(xy + wz, 1 - xx - zz, yz - wx),
  443.                       Vector3<T>(xz - wy, yz + wx, 1 - xx - yy));
  444. }
  445. template<class T> T dot(Quaternion<T> a, Quaternion<T> b)
  446. {
  447.     return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
  448. }
  449. /*! Spherical linear interpolation of two unit quaternions. Designed for
  450.  *  interpolating rotations, so shortest path between rotations will be
  451.  *  taken.
  452.  */
  453. template<class T> Quaternion<T> Quaternion<T>::slerp(const Quaternion<T>& q0,
  454.                                                      const Quaternion<T>& q1,
  455.                                                      T t)
  456. {
  457.     const double Nlerp_Threshold = 0.99999;
  458.     T cosAngle = dot(q0, q1);
  459.     // Assuming the quaternions representat rotations, ensure that we interpolate
  460.     // through the shortest path by inverting one of the quaternions if the
  461.     // angle between them is negative.
  462.     Quaternion qstart;
  463.     if (cosAngle < 0)
  464.     {
  465.         qstart = -q0;
  466.         cosAngle  = -cosAngle;
  467.     }
  468.     else
  469.     {
  470.         qstart = q0;
  471.     }
  472.     // Avoid precision troubles when we're near the limit of acos range and
  473.     // perform a linear interpolation followed by a normalize when interpolating
  474.     // very small angles.
  475.     if (cosAngle > (T) Nlerp_Threshold)
  476.     {
  477.         Quaternion<T> q = (1 - t) * qstart + t * q1;
  478.         q.normalize();
  479.         return q;
  480.     }
  481.     // Below code unnecessary since we've already inverted cosAngle if it's negative.
  482.     // It will be necessary if we change slerp to not assume that we want the shortest
  483.     // path between two rotations.
  484. #if 0
  485.     // Because of potential rounding errors, we must clamp c to the domain of acos.
  486.     if (cosAngle < (T) -1.0)
  487.         cosAngle = (T) -1.0;
  488. #endif
  489.     T angle = (T) acos(cosAngle);
  490.     T interpolatedAngle = t * angle;
  491.     // qstart and q2 will form an orthonormal basis in the plane of interpolation.
  492.     Quaternion q2 = q1 - qstart * cosAngle;
  493.     q2.normalize();
  494.     return qstart * (T) cos(interpolatedAngle) + q2 * (T) sin(interpolatedAngle);
  495. #if 0
  496.     T s = (T) sin(angle);
  497.     T is = (T) 1.0 / s;
  498.     return q0 * ((T) sin((1 - t) * angle) * is) +
  499.            q1 * ((T) sin(t * angle) * is);
  500. #endif
  501. }
  502. /*! Return a unit quaternion that representing a rotation that will
  503.  *  rotation v0 to v1 about the axis perpendicular to them both. If the
  504.  *  vectors point in opposite directions, there is no unique axis and
  505.  *  (arbitrarily) a rotation about the x axis will be chosen.
  506.  */
  507. template<class T> Quaternion<T> Quaternion<T>::vecToVecRotation(const Vector3<T>& v0,
  508.                                                                 const Vector3<T>& v1)
  509. {
  510.     // We need sine and cosine of half the angle between v0 and v1, so
  511.     // compute the vector halfway between v0 and v1. The cross product of
  512.     // half and v1 gives the imaginary part of the quaternion
  513.     // (axis * sin(angle/2)), and the dot product of half and v1 gives
  514.     // the real part.
  515.     Vector3<T> half = (v0 + v1) * (T) 0.5;
  516.     T hl = half.length();
  517.     if (hl > (T) 0.0)
  518.     {
  519.         half = half / hl; // normalize h
  520.         // The magnitude of rotAxis is the sine of half the angle between
  521.         // v0 and v1.
  522.         Vector3<T> rotAxis = half ^ v1;
  523.         T cosAngle = half * v1;
  524.         return Quaternion<T>(cosAngle, rotAxis.x, rotAxis.y, rotAxis.z);
  525.     }
  526.     else
  527.     {
  528.         // The vectors point in exactly opposite directions, so there is
  529.         // no unique axis of rotation. Rotating v0 180 degrees about any
  530.         // axis will map it to v1; we'll choose the x-axis.
  531.         return Quaternion<T>((T) 0.0, (T) 1.0, (T) 0.0, (T) 0.0);
  532.     }
  533. }
  534. /*! Create a quaternion from a rotation matrix
  535.  */
  536. template<class T> Quaternion<T> Quaternion<T>::matrixToQuaternion(const Matrix3<T>& m)
  537. {
  538.     Quaternion<T> q;
  539.     T trace = m[0][0] + m[1][1] + m[2][2];
  540.     T root;
  541.     T epsilon = std::numeric_limits<T>::epsilon() * (T) 1e3;
  542.     if (trace >= epsilon - 1)
  543.     {
  544.         root = (T) sqrt(trace + 1);
  545.         q.w = (T) 0.5 * root;
  546.         root = (T) 0.5 / root;
  547.         q.x = (m[2][1] - m[1][2]) * root;
  548.         q.y = (m[0][2] - m[2][0]) * root;
  549.         q.z = (m[1][0] - m[0][1]) * root;
  550.     }
  551.     else
  552.     {
  553.         // Set i to the largest element of the diagonal
  554.         int i = 0;
  555.         if (m[1][1] > m[i][i])
  556.             i = 1;
  557.         if (m[2][2] > m[i][i])
  558.             i = 2;
  559.         int j = (i == 2) ? 0 : i + 1;
  560.         int k = (j == 2) ? 0 : j + 1;
  561.         root = (T) sqrt(m[i][i] - m[j][j] - m[k][k] + 1);
  562.         T* xyz[3] = { &q.x, &q.y, &q.z };
  563.         *xyz[i] = (T) 0.5 * root;
  564.         root = (T) 0.5 / root;
  565.         q.w = (m[k][j] - m[j][k]) * root;
  566.         *xyz[j] = (m[j][i] + m[i][j]) * root;
  567.         *xyz[k] = (m[k][i] + m[i][k]) * root;
  568.     }
  569.     return q;
  570. }
  571. /*! Assuming that this is a unit quaternion representing an orientation,
  572.  *  apply a rotation of angle radians about the specfied axis
  573.  */
  574. template<class T> void Quaternion<T>::rotate(Vector3<T> axis, T angle)
  575. {
  576.     Quaternion q;
  577.     q.setAxisAngle(axis, angle);
  578.     *this = q * *this;
  579. }
  580. // Assuming that this is a unit quaternion representing an orientation,
  581. // apply a rotation of angle radians about the x-axis
  582. template<class T> void Quaternion<T>::xrotate(T angle)
  583. {
  584.     T s, c;
  585.     Math<T>::sincos(angle * (T) 0.5, s, c);
  586.     *this = Quaternion<T>(c, s, 0, 0) * *this;
  587. }
  588. // Assuming that this is a unit quaternion representing an orientation,
  589. // apply a rotation of angle radians about the y-axis
  590. template<class T> void Quaternion<T>::yrotate(T angle)
  591. {
  592.     T s, c;
  593.     Math<T>::sincos(angle * (T) 0.5, s, c);
  594.     *this = Quaternion<T>(c, 0, s, 0) * *this;
  595. }
  596. // Assuming that this is a unit quaternion representing an orientation,
  597. // apply a rotation of angle radians about the z-axis
  598. template<class T> void Quaternion<T>::zrotate(T angle)
  599. {
  600.     T s, c;
  601.     Math<T>::sincos(angle * (T) 0.5, s, c);
  602.     *this = Quaternion<T>(c, 0, 0, s) * *this;
  603. }
  604. template<class T> Quaternion<T> Quaternion<T>::xrotation(T angle)
  605. {
  606.     T s, c;
  607.     Math<T>::sincos(angle * (T) 0.5, s, c);
  608.     return Quaternion<T>(c, s, 0, 0);
  609. }
  610. template<class T> Quaternion<T> Quaternion<T>::yrotation(T angle)
  611. {
  612.     T s, c;
  613.     Math<T>::sincos(angle * (T) 0.5, s, c);
  614.     return Quaternion<T>(c, 0, s, 0);
  615. }
  616. template<class T> Quaternion<T> Quaternion<T>::zrotation(T angle)
  617. {
  618.     T s, c;
  619.     Math<T>::sincos(angle * (T) 0.5, s, c);
  620.     return Quaternion<T>(c, 0, 0, s);
  621. }
  622. /*! Determine an orientation that will make the negative z-axis point from
  623.  *  from the observer to the target, with the y-axis pointing in direction
  624.  *  of the component of 'up' that is orthogonal to the z-axis.
  625.  */
  626. template<class T> Quaternion<T> 
  627. Quaternion<T>::lookAt(const Point3<T>& from, const Point3<T>& to, const Vector3<T>& up)
  628. {
  629.     Vector3<T> n = to - from;
  630.     n.normalize();
  631.     Vector3<T> v = n ^ up;
  632.     v.normalize();
  633.     Vector3<T> u = v ^ n;
  634.     return Quaternion<T>::matrixToQuaternion(Matrix3<T>(v, u, -n));
  635. }
  636. #endif // _QUATERNION_H_