Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

quaternion.h

Go to the documentation of this file.
00001 // quaternion.h
00002 // 
00003 // Copyright (C) 2000, Chris Laurel <claurel@shatters.net>
00004 //
00005 // Template-ized quaternion math library.
00006 //
00007 // This program is free software; you can redistribute it and/or
00008 // modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2
00010 // of the License, or (at your option) any later version.
00011 
00012 #ifndef _QUATERNION_H_
00013 #define _QUATERNION_H_
00014 
00015 #include <celmath/mathlib.h>
00016 #include <celmath/vecmath.h>
00017 
00018 
00019 #if 0
00020 // Forward declarations needed to make friend templates work . . .
00021 // Disabled until I can get this to work on every compiler.
00022 template<class T> class Quaternion;
00023 
00024 template<class T> Quaternion<T> operator+(Quaternion<T>, Quaternion<T>);
00025 template<class T> Quaternion<T> operator-(Quaternion<T>, Quaternion<T>);
00026 template<class T> Quaternion<T> operator*(Quaternion<T>, Quaternion<T>);
00027 template<class T> Quaternion<T> operator*(T, Quaternion<T>);
00028 template<class T> Quaternion<T> operator*(Vector3<T>, Quaternion<T>);
00029 template<class T> bool operator==(Quaternion<T>, Quaternion<T>);
00030 template<class T> bool operator!=(Quaternion<T>, Quaternion<T>);
00031 template<class T> T real(Quaternion<T>);
00032 template<class T> Vector3<T> imag(Quaternion<T>);
00033 #endif
00034 
00035 template<class T> class Quaternion
00036 {
00037 public:
00038     inline Quaternion();
00039     inline Quaternion(const Quaternion<T>&);
00040     inline Quaternion(T);
00041     inline Quaternion(const Vector3<T>&);
00042     inline Quaternion(T, const Vector3<T>&);
00043     inline Quaternion(T, T, T, T);
00044 
00045     Quaternion(const Matrix3<T>&);
00046 
00047     inline Quaternion& operator+=(Quaternion);
00048     inline Quaternion& operator-=(Quaternion);
00049     inline Quaternion& operator*=(T);
00050     Quaternion& operator*=(Quaternion);
00051 
00052     inline Quaternion operator~() const;    // conjugate
00053     inline Quaternion operator-() const;
00054     inline Quaternion operator+() const;
00055 
00056     void setAxisAngle(Vector3<T> axis, T angle);
00057 
00058     void getAxisAngle(Vector3<T>& axis, T& angle) const;
00059     Matrix4<T> toMatrix4() const;
00060     Matrix3<T> toMatrix3() const;
00061 
00062     static Quaternion<T> slerp(Quaternion<T>, Quaternion<T>, T);
00063 
00064     void rotate(Vector3<T> axis, T angle);
00065     void xrotate(T angle);
00066     void yrotate(T angle);
00067     void zrotate(T angle);
00068 
00069     bool isPure() const;
00070     bool isReal() const;
00071     T normalize();
00072 
00073     static Quaternion<T> xrotation(T);
00074     static Quaternion<T> yrotation(T);
00075     static Quaternion<T> zrotation(T);
00076 #if 0
00077     // This code is disabled until I can 
00078 #ifndef BROKEN_FRIEND_TEMPLATES
00079     // This just rocks . . .  MSVC 6.0 doesn't parse this correctly,
00080     // so template friend functions need to be declared in the standard
00081     // conforming way for GNU C and a non-conforming way for MSVC.
00082     friend Quaternion<T> operator+ <>(Quaternion<T>, Quaternion<T>);
00083     friend Quaternion<T> operator- <>(Quaternion<T>, Quaternion<T>);
00084     friend Quaternion<T> operator* <>(Quaternion<T>, Quaternion<T>);
00085     friend Quaternion<T> operator* <>(T, Quaternion<T>);
00086     friend Quaternion<T> operator* <>(Vector3<T>, Quaternion<T>);
00087 
00088     friend bool operator== <>(Quaternion<T>, Quaternion<T>);
00089     friend bool operator!= <>(Quaternion<T>, Quaternion<T>);
00090 
00091     friend T real<>(Quaternion<T>);
00092     friend Vector3<T> imag<>(Quaternion<T>);
00093 #else
00094     friend Quaternion<T> operator+(Quaternion<T>, Quaternion<T>);
00095     friend Quaternion<T> operator-(Quaternion<T>, Quaternion<T>);
00096     friend Quaternion<T> operator*(Quaternion<T>, Quaternion<T>);
00097     friend Quaternion<T> operator*(T, Quaternion<T>);
00098     friend Quaternion<T> operator*(Vector3<T>, Quaternion<T>);
00099 
00100     friend bool operator==(Quaternion<T>, Quaternion<T>);
00101     friend bool operator!=(Quaternion<T>, Quaternion<T>);
00102 
00103     friend T real(Quaternion<T>);
00104     friend Vector3<T> imag(Quaternion<T>);
00105 #endif // BROKEN_FRIEND_TEMPLATES
00106 
00107 #endif
00108 
00109     // Until friend templates are working . . .
00110     // private:
00111     T w, x, y, z;
00112 };
00113 
00114 
00115 typedef Quaternion<float> Quatf;
00116 typedef Quaternion<double> Quatd;
00117 
00118 
00119 template<class T> Quaternion<T>::Quaternion() : w(0), x(0), y(0), z(0)
00120 {
00121 }
00122 
00123 template<class T> Quaternion<T>::Quaternion(const Quaternion<T>& q) :
00124     w(q.w), x(q.x), y(q.y), z(q.z)
00125 {
00126 }
00127 
00128 template<class T> Quaternion<T>::Quaternion(T re) :
00129     w(re), x(0), y(0), z(0)
00130 {
00131 }
00132 
00133 // Create a 'pure' quaternion
00134 template<class T> Quaternion<T>::Quaternion(const Vector3<T>& im) :
00135      w(0), x(im.x), y(im.y), z(im.z)
00136 {
00137 }
00138 
00139 template<class T> Quaternion<T>::Quaternion(T re, const Vector3<T>& im) :
00140      w(re), x(im.x), y(im.y), z(im.z)
00141 {
00142 }
00143 
00144 template<class T> Quaternion<T>::Quaternion(T _w, T _x, T _y, T _z) :
00145     w(_w), x(_x), y(_y), z(_z)
00146 {
00147 }
00148 
00149 // Create a quaternion from a rotation matrix
00150 template<class T> Quaternion<T>::Quaternion(const Matrix3<T>& m)
00151 {
00152     T trace = m[0][0] + m[1][1] + m[2][2];
00153     T root;
00154 
00155     if (trace > 0)
00156     {
00157         root = (T) sqrt(trace + 1);
00158         w = (T) 0.5 * root;
00159         root = (T) 0.5 / root;
00160         x = (m[2][1] - m[1][2]) * root;
00161         y = (m[0][2] - m[2][0]) * root;
00162         z = (m[1][0] - m[0][1]) * root;
00163     }
00164     else
00165     {
00166         int i = 0;
00167         if (m[1][1] > m[i][i])
00168             i = 1;
00169         if (m[2][2] > m[i][i])
00170             i = 2;
00171         int j = (i == 2) ? 0 : i + 1;
00172         int k = (j == 2) ? 0 : j + 1;
00173 
00174         root = (T) sqrt(m[i][i] - m[j][j] - m[k][k] + 1);
00175         T* xyz[3] = { &x, &y, &z };
00176         *xyz[i] = (T) 0.5 * root;
00177         root = (T) 0.5 / root;
00178         w = (m[k][j] - m[j][k]) * root;
00179         *xyz[j] = (m[j][i] + m[i][j]) * root;
00180         *xyz[k] = (m[k][i] + m[i][k]) * root;
00181     }
00182 }
00183 
00184 
00185 template<class T> Quaternion<T>& Quaternion<T>::operator+=(Quaternion<T> a)
00186 {
00187     x += a.x; y += a.y; z += a.z; w += a.w;
00188     return *this;
00189 }
00190 
00191 template<class T> Quaternion<T>& Quaternion<T>::operator-=(Quaternion<T> a)
00192 {
00193     x -= a.x; y -= a.y; z -= a.z; w -= a.w;
00194     return *this;
00195 }
00196 
00197 template<class T> Quaternion<T>& Quaternion<T>::operator*=(Quaternion<T> q)
00198 {
00199     *this = Quaternion<T>(w * q.w - x * q.x - y * q.y - z * q.z,
00200                           w * q.x + x * q.w + y * q.z - z * q.y,
00201                           w * q.y + y * q.w + z * q.x - x * q.z,
00202                           w * q.z + z * q.w + x * q.y - y * q.x);
00203                           
00204     return *this;
00205 }
00206 
00207 template<class T> Quaternion<T>& Quaternion<T>::operator*=(T s)
00208 {
00209     x *= s; y *= s; z *= s; w *= s;
00210     return *this;
00211 }
00212 
00213 // conjugate operator
00214 template<class T> Quaternion<T> Quaternion<T>::operator~() const
00215 {
00216     return Quaternion<T>(w, -x, -y, -z);
00217 }
00218 
00219 template<class T> Quaternion<T> Quaternion<T>::operator-() const
00220 {
00221     return Quaternion<T>(-w, -x, -y, -z);
00222 }
00223 
00224 template<class T> Quaternion<T> Quaternion<T>::operator+() const
00225 {
00226     return *this;
00227 }
00228 
00229 
00230 template<class T> Quaternion<T> operator+(Quaternion<T> a, Quaternion<T> b)
00231 {
00232     return Quaternion<T>(a.w + b.w, a.x + b.x, a.y + b.y, a.z + b.z);
00233 }
00234 
00235 template<class T> Quaternion<T> operator-(Quaternion<T> a, Quaternion<T> b)
00236 {
00237     return Quaternion<T>(a.w - b.w, a.x - b.x, a.y - b.y, a.z - b.z);
00238 }
00239 
00240 template<class T> Quaternion<T> operator*(Quaternion<T> a, Quaternion<T> b)
00241 {
00242     return Quaternion<T>(a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
00243                          a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
00244                          a.w * b.y + a.y * b.w + a.z * b.x - a.x * b.z,
00245                          a.w * b.z + a.z * b.w + a.x * b.y - a.y * b.x);
00246 }
00247 
00248 template<class T> Quaternion<T> operator*(T s, Quaternion<T> q)
00249 {
00250     return Quaternion<T>(s * q.w, s * q.x, s * q.y, s * q.z);
00251 }
00252 
00253 template<class T> Quaternion<T> operator*(Quaternion<T> q, T s)
00254 {
00255     return Quaternion<T>(s * q.w, s * q.x, s * q.y, s * q.z);
00256 }
00257 
00258 // equivalent to multiplying by the quaternion (0, v)
00259 template<class T> Quaternion<T> operator*(Vector3<T> v, Quaternion<T> q)
00260 {
00261     return Quaternion<T>(-v.x * q.x - v.y * q.y - v.z * q.z,
00262                          v.x * q.w + v.y * q.z - v.z * q.y,
00263                          v.y * q.w + v.z * q.x - v.x * q.z,
00264                          v.z * q.w + v.x * q.y - v.y * q.x);
00265 }
00266 
00267 template<class T> Quaternion<T> operator/(Quaternion<T> q, T s)
00268 {
00269     return q * (1 / s);
00270 }
00271 
00272 template<class T> Quaternion<T> operator/(Quaternion<T> a, Quaternion<T> b)
00273 {
00274     return a * (~b / abs(b));
00275 }
00276 
00277 
00278 template<class T> bool operator==(Quaternion<T> a, Quaternion<T> b)
00279 {
00280     return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w;
00281 }
00282 
00283 template<class T> bool operator!=(Quaternion<T> a, Quaternion<T> b)
00284 {
00285     return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w;
00286 }
00287 
00288 
00289 // elementary functions
00290 template<class T> Quaternion<T> conjugate(Quaternion<T> q)
00291 {
00292     return Quaternion<T>(q.w, -q.x, -q.y, -q.z);
00293 }
00294 
00295 template<class T> T norm(Quaternion<T> q)
00296 {
00297     return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
00298 }
00299 
00300 template<class T> T abs(Quaternion<T> q)
00301 {
00302     return (T) sqrt(norm(q));
00303 }
00304 
00305 template<class T> Quaternion<T> exp(Quaternion<T> q)
00306 {
00307     if (q.isReal())
00308     {
00309         return Quaternion<T>((T) exp(q.w));
00310     }
00311     else
00312     {
00313         T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
00314         T s = (T) sin(l);
00315         T c = (T) cos(l);
00316         T e = (T) exp(q.w);
00317         T t = e * s / l;
00318         return Quaternion<T>(e * c, t * q.x, t * q.y, t * q.z);
00319     }
00320 }
00321 
00322 template<class T> Quaternion<T> log(Quaternion<T> q)
00323 {
00324     if (q.isReal())
00325     {
00326         if (q.w > 0)
00327         {
00328             return Quaternion<T>((T) log(q.w));
00329         }
00330         else if (q.w < 0)
00331         {
00332             // The log of a negative purely real quaternion has
00333             // infinitely many values, all of the form (ln(-w), PI * I),
00334             // where I is any unit vector.  We arbitrarily choose an I
00335             // of (1, 0, 0) here and whereever else a similar choice is
00336             // necessary.  Geometrically, the set of roots is a sphere
00337             // of radius PI centered at ln(-w) on the real axis.
00338             return Quaternion<T>((T) log(-q.w), (T) PI, 0, 0);
00339         }
00340         else
00341         {
00342             // error . . . ln(0) not defined
00343             return Quaternion<T>(0);
00344         }
00345     }
00346     else
00347     {
00348         T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
00349         T r = (T) sqrt(l * l + q.w * q.w);
00350         T theta = (T) atan2(l, q.w);
00351         T t = theta / l;
00352         return Quaternion<T>((T) log(r), t * q.x, t * q.y, t * q.z);
00353     }
00354 }
00355 
00356 
00357 template<class T> Quaternion<T> pow(Quaternion<T> q, T s)
00358 {
00359     return exp(s * log(q));
00360 }
00361 
00362 
00363 template<class T> Quaternion<T> pow(Quaternion<T> q, Quaternion<T> p)
00364 {
00365     return exp(p * log(q));
00366 }
00367 
00368 
00369 template<class T> Quaternion<T> sin(Quaternion<T> q)
00370 {
00371     if (q.isReal())
00372     {
00373         return Quaternion<T>((T) sin(q.w));
00374     }
00375     else
00376     {
00377         T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
00378         T m = q.w;
00379         T s = (T) sin(m);
00380         T c = (T) cos(m);
00381         T il = 1 / l;
00382         T e0 = (T) exp(-l);
00383         T e1 = (T) exp(l);
00384 
00385         T c0 = (T) -0.5 * e0 * il * c;
00386         T c1 = (T)  0.5 * e1 * il * c;
00387 
00388         return Quaternion<T>((T) 0.5 * e0 * s, c0 * q.x, c0 * q.y, c0 * q.z) +
00389             Quaternion<T>((T) 0.5 * e1 * s, c1 * q.x, c1 * q.y, c1 * q.z);
00390     }
00391 }
00392 
00393 template<class T> Quaternion<T> cos(Quaternion<T> q)
00394 {
00395     if (q.isReal())
00396     {
00397         return Quaternion<T>((T) cos(q.w));
00398     }
00399     else
00400     {
00401         T l = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
00402         T m = q.w;
00403         T s = (T) sin(m);
00404         T c = (T) cos(m);
00405         T il = 1 / l;
00406         T e0 = (T) exp(-l);
00407         T e1 = (T) exp(l);
00408 
00409         T c0 = (T)  0.5 * e0 * il * s;
00410         T c1 = (T) -0.5 * e1 * il * s;
00411 
00412         return Quaternion<T>((T) 0.5 * e0 * c, c0 * q.x, c0 * q.y, c0 * q.z) +
00413             Quaternion<T>((T) 0.5 * e1 * c, c1 * q.x, c1 * q.y, c1 * q.z);
00414     }
00415 }
00416 
00417 template<class T> Quaternion<T> sqrt(Quaternion<T> q)
00418 {
00419     // In general, the square root of a quaternion has two values, one
00420     // of which is the negative of the other.  However, any negative purely
00421     // real quaternion has an infinite number of square roots.
00422     // This function returns the positive root for positive reals and
00423     // the root on the positive i axis for negative reals.
00424     if (q.isReal())
00425     {
00426         if (q.w >= 0)
00427             return Quaternion<T>((T) sqrt(q.w), 0, 0, 0);
00428         else
00429             return Quaternion<T>(0, (T) sqrt(-q.w), 0, 0);
00430     }
00431     else
00432     {
00433         T b = (T) sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
00434         T r = (T) sqrt(q.w * q.w + b * b);
00435         if (q.w >= 0)
00436         {
00437             T m = (T) sqrt((T) 0.5 * (r + q.w));
00438             T l = b / (2 * m);
00439             T t = l / b;
00440             return Quaternion<T>(m, q.x * t, q.y * t, q.z * t);
00441         }
00442         else
00443         {
00444             T l = (T) sqrt((T) 0.5 * (r - q.w));
00445             T m = b / (2 * l);
00446             T t = l / b;
00447             return Quaternion<T>(m, q.x * t, q.y * t, q.z * t);
00448         }
00449     }
00450 }
00451 
00452 template<class T> T real(Quaternion<T> q)
00453 {
00454     return q.w;
00455 }
00456 
00457 template<class T> Vector3<T> imag(Quaternion<T> q)
00458 {
00459     return Vector3<T>(q.x, q.y, q.z);
00460 }
00461 
00462 
00463 // Quaternion methods
00464 
00465 template<class T> bool Quaternion<T>::isReal() const
00466 {
00467     return (x == 0 && y == 0 && z == 0);
00468 }
00469 
00470 template<class T> bool Quaternion<T>::isPure() const
00471 {
00472     return w == 0;
00473 }
00474 
00475 template<class T> T Quaternion<T>::normalize()
00476 {
00477     T s = (T) sqrt(w * w + x * x + y * y + z * z);
00478     T invs = (T) 1 / (T) s;
00479     x *= invs;
00480     y *= invs;
00481     z *= invs;
00482     w *= invs;
00483 
00484     return s;
00485 }
00486 
00487 // Set to the unit quaternion representing an axis angle rotation.  Assume
00488 // that axis is a unit vector
00489 template<class T> void Quaternion<T>::setAxisAngle(Vector3<T> axis, T angle)
00490 {
00491     T s, c;
00492     
00493     Math<T>::sincos(angle * (T) 0.5, s, c);
00494     x = s * axis.x;
00495     y = s * axis.y;
00496     z = s * axis.z;
00497     w = c;
00498 }
00499 
00500 
00501 // Assuming that this a unit quaternion, return the in axis/angle form the
00502 // orientation which it represents.
00503 template<class T> void Quaternion<T>::getAxisAngle(Vector3<T>& axis,
00504                                                    T& angle) const
00505 {
00506     // The quaternion has the form:
00507     // w = cos(angle/2), (x y z) = sin(angle/2)*axis
00508 
00509     T magSquared = x * x + y * y + z * z;
00510     if (magSquared > (T) 1e-10)
00511     {
00512         T s =  (T) 1 / (T) sqrt(magSquared);
00513         axis.x = x * s;
00514         axis.y = y * s;
00515         axis.z = z * s;
00516         if (w <= -1 || w >= 1)
00517             angle = 0;
00518         else
00519             angle = (T) acos(w) * 2;
00520     }
00521     else
00522     {
00523         // The angle is zero, so we pick an arbitrary unit axis
00524         axis.x = 1;
00525         axis.y = 0;
00526         axis.z = 0;
00527         angle = 0;
00528     }
00529 }
00530 
00531 
00532 // Convert this (assumed to be normalized) quaternion to a rotation matrix
00533 template<class T> Matrix4<T> Quaternion<T>::toMatrix4() const
00534 {
00535     T wx = w * x * 2;
00536     T wy = w * y * 2;
00537     T wz = w * z * 2;
00538     T xx = x * x * 2;
00539     T xy = x * y * 2;
00540     T xz = x * z * 2;
00541     T yy = y * y * 2;
00542     T yz = y * z * 2;
00543     T zz = z * z * 2;
00544 
00545     return Matrix4<T>(Vector4<T>(1 - yy - zz, xy - wz, xz + wy, 0),
00546                       Vector4<T>(xy + wz, 1 - xx - zz, yz - wx, 0),
00547                       Vector4<T>(xz - wy, yz + wx, 1 - xx - yy, 0),
00548                       Vector4<T>(0, 0, 0, 1));
00549 }
00550 
00551 
00552 // Convert this (assumed to be normalized) quaternion to a rotation matrix
00553 template<class T> Matrix3<T> Quaternion<T>::toMatrix3() const
00554 {
00555     T wx = w * x * 2;
00556     T wy = w * y * 2;
00557     T wz = w * z * 2;
00558     T xx = x * x * 2;
00559     T xy = x * y * 2;
00560     T xz = x * z * 2;
00561     T yy = y * y * 2;
00562     T yz = y * z * 2;
00563     T zz = z * z * 2;
00564 
00565     return Matrix3<T>(Vector3<T>(1 - yy - zz, xy - wz, xz + wy),
00566                       Vector3<T>(xy + wz, 1 - xx - zz, yz - wx),
00567                       Vector3<T>(xz - wy, yz + wx, 1 - xx - yy));
00568 }
00569 
00570 
00571 template<class T> T dot(Quaternion<T> a, Quaternion<T> b)
00572 {
00573     return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
00574 }
00575 
00576 
00577 template<class T> Quaternion<T> Quaternion<T>::slerp(Quaternion<T> q0,
00578                                                      Quaternion<T> q1,
00579                                                      T t)
00580 {
00581     T c = dot(q0, q1);
00582 
00583     // Because of potential rounding errors, we must clamp c to the domain of acos.
00584     if (c > (T) 1.0)
00585         c = (T) 1.0;
00586     else if (c < (T) -1.0)
00587         c = (T) -1.0;
00588 
00589     T angle = (T) acos(c);
00590 
00591     if (abs(angle) < (T) 1.0e-5)
00592         return q0;
00593 
00594     T s = (T) sin(angle);
00595     T is = (T) 1.0 / s;
00596 
00597     return q0 * ((T) sin((1 - t) * angle) * is) +
00598            q1 * ((T) sin(t * angle) * is);
00599 }
00600 
00601 
00602 // Assuming that this is a unit quaternion representing an orientation,
00603 // apply a rotation of angle radians about the specfied axis
00604 template<class T> void Quaternion<T>::rotate(Vector3<T> axis, T angle)
00605 {
00606     Quaternion q;
00607     q.setAxisAngle(axis, angle);
00608     *this = q * *this;
00609 }
00610 
00611 
00612 // Assuming that this is a unit quaternion representing an orientation,
00613 // apply a rotation of angle radians about the x-axis
00614 template<class T> void Quaternion<T>::xrotate(T angle)
00615 {
00616     T s, c;
00617 
00618     Math<T>::sincos(angle * (T) 0.5, s, c);
00619     *this = Quaternion<T>(c, s, 0, 0) * *this;
00620 }
00621 
00622 // Assuming that this is a unit quaternion representing an orientation,
00623 // apply a rotation of angle radians about the y-axis
00624 template<class T> void Quaternion<T>::yrotate(T angle)
00625 {
00626     T s, c;
00627 
00628     Math<T>::sincos(angle * (T) 0.5, s, c);
00629     *this = Quaternion<T>(c, 0, s, 0) * *this;
00630 }
00631 
00632 // Assuming that this is a unit quaternion representing an orientation,
00633 // apply a rotation of angle radians about the z-axis
00634 template<class T> void Quaternion<T>::zrotate(T angle)
00635 {
00636     T s, c;
00637 
00638     Math<T>::sincos(angle * (T) 0.5, s, c);
00639     *this = Quaternion<T>(c, 0, 0, s) * *this;
00640 }
00641 
00642 
00643 template<class T> Quaternion<T> Quaternion<T>::xrotation(T angle)
00644 {
00645     T s, c;
00646     Math<T>::sincos(angle * (T) 0.5, s, c);
00647     return Quaternion<T>(c, s, 0, 0);
00648 }
00649 
00650 template<class T> Quaternion<T> Quaternion<T>::yrotation(T angle)
00651 {
00652     T s, c;
00653     Math<T>::sincos(angle * (T) 0.5, s, c);
00654     return Quaternion<T>(c, 0, s, 0);
00655 }
00656 
00657 template<class T> Quaternion<T> Quaternion<T>::zrotation(T angle)
00658 {
00659     T s, c;
00660     Math<T>::sincos(angle * (T) 0.5, s, c);
00661     return Quaternion<T>(c, 0, 0, s);
00662 }
00663 
00664 #endif // _QUATERNION_H_

Generated on Sat Jan 14 22:30:32 2006 for Celestia by  doxygen 1.4.1