llquaternion.h

Go to the documentation of this file.
00001 
00032 #ifndef LLQUATERNION_H
00033 #define LLQUATERNION_H
00034 
00035 #include "llmath.h"
00036 
00037 class LLVector4;
00038 class LLVector3;
00039 class LLVector3d;
00040 class LLMatrix4;
00041 class LLMatrix3;
00042 
00043 //      NOTA BENE: Quaternion code is written assuming Unit Quaternions!!!!
00044 //                         Moreover, it is written assuming that all vectors and matricies
00045 //                         passed as arguments are normalized and unitary respectively.
00046 //                         VERY VERY VERY VERY BAD THINGS will happen if these assumptions fail.
00047 
00048 static const U32 LENGTHOFQUAT = 4;
00049 
00050 class LLQuaternion
00051 {
00052 public:
00053         F32 mQ[LENGTHOFQUAT];
00054 
00055         static const LLQuaternion DEFAULT;
00056 
00057         LLQuaternion();                                                                 // Initializes Quaternion to (0,0,0,1)
00058         explicit LLQuaternion(const LLMatrix4 &mat);                            // Initializes Quaternion from Matrix4
00059         explicit LLQuaternion(const LLMatrix3 &mat);                            // Initializes Quaternion from Matrix3
00060         LLQuaternion(F32 x, F32 y, F32 z, F32 w);               // Initializes Quaternion to normQuat(x, y, z, w)
00061         LLQuaternion(F32 angle, const LLVector4 &vec);  // Initializes Quaternion to axis_angle2quat(angle, vec)
00062         LLQuaternion(F32 angle, const LLVector3 &vec);  // Initializes Quaternion to axis_angle2quat(angle, vec)
00063         LLQuaternion(const F32 *q);                                             // Initializes Quaternion to normQuat(x, y, z, w)
00064         LLQuaternion(const LLVector3 &x_axis,
00065                                  const LLVector3 &y_axis,
00066                                  const LLVector3 &z_axis);                      // Initializes Quaternion from Matrix3 = [x_axis ; y_axis ; z_axis]
00067 
00068         BOOL isIdentity() const;
00069         BOOL isNotIdentity() const;
00070         BOOL isFinite() const;                                                                  // checks to see if all values of LLQuaternion are finite
00071         void quantize16(F32 lower, F32 upper);                                  // changes the vector to reflect quatization
00072         void quantize8(F32 lower, F32 upper);                                                   // changes the vector to reflect quatization
00073         void loadIdentity();                                                                                    // Loads the quaternion that represents the identity rotation
00074         const LLQuaternion&     setQuatInit(F32 x, F32 y, F32 z, F32 w);        // Sets Quaternion to normQuat(x, y, z, w)
00075         const LLQuaternion&     setQuat(const LLQuaternion &quat);                      // Copies Quaternion
00076         const LLQuaternion&     setQuat(const F32 *q);                                          // Sets Quaternion to normQuat(quat[VX], quat[VY], quat[VZ], quat[VW])
00077         const LLQuaternion&     setQuat(const LLMatrix3 &mat);                          // Sets Quaternion to mat2quat(mat)
00078         const LLQuaternion&     setQuat(const LLMatrix4 &mat);                          // Sets Quaternion to mat2quat(mat)
00079         const LLQuaternion&     setQuat(F32 angle, F32 x, F32 y, F32 z);        // Sets Quaternion to axis_angle2quat(angle, x, y, z)
00080         const LLQuaternion&     setQuat(F32 angle, const LLVector3 &vec);       // Sets Quaternion to axis_angle2quat(angle, vec)
00081         const LLQuaternion&     setQuat(F32 angle, const LLVector4 &vec);       // Sets Quaternion to axis_angle2quat(angle, vec)
00082         const LLQuaternion&     setQuat(F32 roll, F32 pitch, F32 yaw);          // Sets Quaternion to euler2quat(pitch, yaw, roll)
00083 
00084         LLMatrix4       getMatrix4(void) const;                                                 // Returns the Matrix4 equivalent of Quaternion
00085         LLMatrix3       getMatrix3(void) const;                                                 // Returns the Matrix3 equivalent of Quaternion
00086         void            getAngleAxis(F32* angle, F32* x, F32* y, F32* z) const; // returns rotation in radians about axis x,y,z
00087         void            getAngleAxis(F32* angle, LLVector3 &vec) const;
00088         void            getEulerAngles(F32 *roll, F32* pitch, F32 *yaw) const;
00089 
00090         F32                             normQuat();                                     // Normalizes Quaternion and returns magnitude
00091         const LLQuaternion&     conjQuat(void);                         // Conjugates Quaternion and returns result
00092 
00093         // Other useful methods
00094         const LLQuaternion&     transQuat();                                                                                    // Transpose
00095         void                    shortestArc(const LLVector3 &a, const LLVector3 &b);    // shortest rotation from a to b
00096         const LLQuaternion& constrain(F32 radians);                                             // constrains rotation to a cone angle specified in radians
00097 
00098         // Standard operators
00099         friend std::ostream& operator<<(std::ostream &s, const LLQuaternion &a);                                        // Prints a
00100         friend LLQuaternion operator+(const LLQuaternion &a, const LLQuaternion &b);    // Addition
00101         friend LLQuaternion operator-(const LLQuaternion &a, const LLQuaternion &b);    // Subtraction
00102         friend LLQuaternion operator-(const LLQuaternion &a);                                                   // Negation
00103         friend LLQuaternion operator*(F32 a, const LLQuaternion &q);                                    // Scale
00104         friend LLQuaternion operator*(const LLQuaternion &q, F32 b);                                    // Scale
00105         friend LLQuaternion operator*(const LLQuaternion &a, const LLQuaternion &b);    // Returns a * b
00106         friend LLQuaternion operator~(const LLQuaternion &a);                                                   // Returns a* (Conjugate of a)
00107         bool operator==(const LLQuaternion &b) const;                   // Returns a == b
00108         bool operator!=(const LLQuaternion &b) const;                   // Returns a != b
00109 
00110         friend const LLQuaternion& operator*=(LLQuaternion &a, const LLQuaternion &b);  // Returns a * b
00111 
00112         friend LLVector4 operator*(const LLVector4 &a, const LLQuaternion &rot);                // Rotates a by rot
00113         friend LLVector3 operator*(const LLVector3 &a, const LLQuaternion &rot);                // Rotates a by rot
00114         friend LLVector3d operator*(const LLVector3d &a, const LLQuaternion &rot);              // Rotates a by rot
00115 
00116         // Non-standard operators
00117         friend F32 dot(const LLQuaternion &a, const LLQuaternion &b);
00118         friend LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q);          // linear interpolation (t = 0 to 1) from p to q
00119         friend LLQuaternion lerp(F32 t, const LLQuaternion &q);                                                         // linear interpolation (t = 0 to 1) from identity to q
00120         friend LLQuaternion slerp(F32 t, const LLQuaternion &p, const LLQuaternion &q);         // spherical linear interpolation from p to q
00121         friend LLQuaternion slerp(F32 t, const LLQuaternion &q);                                                        // spherical linear interpolation from identity to q
00122         friend LLQuaternion nlerp(F32 t, const LLQuaternion &p, const LLQuaternion &q);         // normalized linear interpolation from p to q
00123         friend LLQuaternion nlerp(F32 t, const LLQuaternion &q);                                                        // normalized linear interpolation from p to q
00124 
00125         LLVector3       packToVector3() const;                                          // Saves space by using the fact that our quaternions are normalized
00126         void            unpackFromVector3(const LLVector3& vec);        // Saves space by using the fact that our quaternions are normalized
00127 
00128         enum Order {
00129                 XYZ = 0,
00130                 YZX = 1,
00131                 ZXY = 2,
00132                 XZY = 3,
00133                 YXZ = 4,
00134                 ZYX = 5
00135         };
00136         // Creates a quaternions from maya's rotation representation,
00137         // which is 3 rotations (in DEGREES) in the specified order
00138         friend LLQuaternion mayaQ(F32 x, F32 y, F32 z, Order order);
00139 
00140         // Conversions between Order and strings like "xyz" or "ZYX"
00141         friend const char *OrderToString( const Order order );
00142         friend Order StringToOrder( const char *str );
00143 
00144         static BOOL parseQuat(const char* buf, LLQuaternion* value);
00145 
00146         // For debugging, only
00147         //static U32 mMultCount;
00148 };
00149 
00150 // checker
00151 inline BOOL     LLQuaternion::isFinite() const
00152 {
00153         return (llfinite(mQ[VX]) && llfinite(mQ[VY]) && llfinite(mQ[VZ]) && llfinite(mQ[VS]));
00154 }
00155 
00156 inline BOOL LLQuaternion::isIdentity() const
00157 {
00158         return 
00159                 ( mQ[VX] == 0.f ) &&
00160                 ( mQ[VY] == 0.f ) &&
00161                 ( mQ[VZ] == 0.f ) &&
00162                 ( mQ[VS] == 1.f );
00163 }
00164 
00165 inline BOOL LLQuaternion::isNotIdentity() const
00166 {
00167         return 
00168                 ( mQ[VX] != 0.f ) ||
00169                 ( mQ[VY] != 0.f ) ||
00170                 ( mQ[VZ] != 0.f ) ||
00171                 ( mQ[VS] != 1.f );
00172 }
00173 
00174 
00175 
00176 inline LLQuaternion::LLQuaternion(void)
00177 {
00178         mQ[VX] = 0.f;
00179         mQ[VY] = 0.f;
00180         mQ[VZ] = 0.f;
00181         mQ[VS] = 1.f;
00182 }
00183 
00184 inline LLQuaternion::LLQuaternion(F32 x, F32 y, F32 z, F32 w)
00185 {
00186         mQ[VX] = x;
00187         mQ[VY] = y;
00188         mQ[VZ] = z;
00189         mQ[VS] = w;
00190 
00191         //RN: don't normalize this case as its used mainly for temporaries during calculations
00192         //normQuat();
00193         /*
00194         F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);
00195         mag -= 1.f;
00196         mag = fabs(mag);
00197         llassert(mag < 10.f*FP_MAG_THRESHOLD);
00198         */
00199 }
00200 
00201 inline LLQuaternion::LLQuaternion(const F32 *q)
00202 {
00203         mQ[VX] = q[VX];
00204         mQ[VY] = q[VY];
00205         mQ[VZ] = q[VZ];
00206         mQ[VS] = q[VW];
00207 
00208         normQuat();
00209         /*
00210         F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);
00211         mag -= 1.f;
00212         mag = fabs(mag);
00213         llassert(mag < FP_MAG_THRESHOLD);
00214         */
00215 }
00216 
00217 
00218 inline void LLQuaternion::loadIdentity()
00219 {
00220         mQ[VX] = 0.0f;
00221         mQ[VY] = 0.0f;
00222         mQ[VZ] = 0.0f;
00223         mQ[VW] = 1.0f;
00224 }
00225 
00226 
00227 inline const LLQuaternion&      LLQuaternion::setQuatInit(F32 x, F32 y, F32 z, F32 w)
00228 {
00229         mQ[VX] = x;
00230         mQ[VY] = y;
00231         mQ[VZ] = z;
00232         mQ[VS] = w;
00233         normQuat();
00234         return (*this);
00235 }
00236 
00237 inline const LLQuaternion&      LLQuaternion::setQuat(const LLQuaternion &quat)
00238 {
00239         mQ[VX] = quat.mQ[VX];
00240         mQ[VY] = quat.mQ[VY];
00241         mQ[VZ] = quat.mQ[VZ];
00242         mQ[VW] = quat.mQ[VW];
00243         normQuat();
00244         return (*this);
00245 }
00246 
00247 inline const LLQuaternion&      LLQuaternion::setQuat(const F32 *q)
00248 {
00249         mQ[VX] = q[VX];
00250         mQ[VY] = q[VY];
00251         mQ[VZ] = q[VZ];
00252         mQ[VS] = q[VW];
00253         normQuat();
00254         return (*this);
00255 }
00256 
00257 // There may be a cheaper way that avoids the sqrt.
00258 // Does sin_a = VX*VX + VY*VY + VZ*VZ?
00259 // Copied from Matrix and Quaternion FAQ 1.12
00260 inline void LLQuaternion::getAngleAxis(F32* angle, F32* x, F32* y, F32* z) const
00261 {
00262         F32 cos_a = mQ[VW];
00263         if (cos_a > 1.0f) cos_a = 1.0f;
00264         if (cos_a < -1.0f) cos_a = -1.0f;
00265 
00266     F32 sin_a = (F32) sqrt( 1.0f - cos_a * cos_a );
00267 
00268     if ( fabs( sin_a ) < 0.0005f )
00269                 sin_a = 1.0f;
00270         else
00271                 sin_a = 1.f/sin_a;
00272 
00273     *angle = 2.0f * (F32) acos( cos_a );
00274     *x = mQ[VX] * sin_a;
00275     *y = mQ[VY] * sin_a;
00276     *z = mQ[VZ] * sin_a;
00277 }
00278 
00279 inline const LLQuaternion& LLQuaternion::conjQuat()
00280 {
00281         mQ[VX] *= -1.f;
00282         mQ[VY] *= -1.f;
00283         mQ[VZ] *= -1.f;
00284         return (*this);
00285 }
00286 
00287 // Transpose
00288 inline const LLQuaternion& LLQuaternion::transQuat()
00289 {
00290         mQ[VX] = -mQ[VX];
00291         mQ[VY] = -mQ[VY];
00292         mQ[VZ] = -mQ[VZ];
00293         return *this;
00294 }
00295 
00296 
00297 inline LLQuaternion     operator+(const LLQuaternion &a, const LLQuaternion &b)
00298 {
00299         return LLQuaternion( 
00300                 a.mQ[VX] + b.mQ[VX],
00301                 a.mQ[VY] + b.mQ[VY],
00302                 a.mQ[VZ] + b.mQ[VZ],
00303                 a.mQ[VW] + b.mQ[VW] );
00304 }
00305 
00306 
00307 inline LLQuaternion     operator-(const LLQuaternion &a, const LLQuaternion &b)
00308 {
00309         return LLQuaternion( 
00310                 a.mQ[VX] - b.mQ[VX],
00311                 a.mQ[VY] - b.mQ[VY],
00312                 a.mQ[VZ] - b.mQ[VZ],
00313                 a.mQ[VW] - b.mQ[VW] );
00314 }
00315 
00316 
00317 inline LLQuaternion     operator-(const LLQuaternion &a)
00318 {
00319         return LLQuaternion(
00320                 -a.mQ[VX],
00321                 -a.mQ[VY],
00322                 -a.mQ[VZ],
00323                 -a.mQ[VW] );
00324 }
00325 
00326 
00327 inline LLQuaternion     operator*(F32 a, const LLQuaternion &q)
00328 {
00329         return LLQuaternion(
00330                 a * q.mQ[VX],
00331                 a * q.mQ[VY],
00332                 a * q.mQ[VZ],
00333                 a * q.mQ[VW] );
00334 }
00335 
00336 
00337 inline LLQuaternion     operator*(const LLQuaternion &q, F32 a)
00338 {
00339         return LLQuaternion(
00340                 a * q.mQ[VX],
00341                 a * q.mQ[VY],
00342                 a * q.mQ[VZ],
00343                 a * q.mQ[VW] );
00344 }
00345 
00346 inline LLQuaternion     operator~(const LLQuaternion &a)
00347 {
00348         LLQuaternion q(a);
00349         q.conjQuat();
00350         return q;
00351 }
00352 
00353 inline bool     LLQuaternion::operator==(const LLQuaternion &b) const
00354 {
00355         return (  (mQ[VX] == b.mQ[VX])
00356                         &&(mQ[VY] == b.mQ[VY])
00357                         &&(mQ[VZ] == b.mQ[VZ])
00358                         &&(mQ[VS] == b.mQ[VS]));
00359 }
00360 
00361 inline bool     LLQuaternion::operator!=(const LLQuaternion &b) const
00362 {
00363         return (  (mQ[VX] != b.mQ[VX])
00364                         ||(mQ[VY] != b.mQ[VY])
00365                         ||(mQ[VZ] != b.mQ[VZ])
00366                         ||(mQ[VS] != b.mQ[VS]));
00367 }
00368 
00369 inline const LLQuaternion&      operator*=(LLQuaternion &a, const LLQuaternion &b)
00370 {
00371 #if 1
00372         LLQuaternion q(
00373                 b.mQ[3] * a.mQ[0] + b.mQ[0] * a.mQ[3] + b.mQ[1] * a.mQ[2] - b.mQ[2] * a.mQ[1],
00374                 b.mQ[3] * a.mQ[1] + b.mQ[1] * a.mQ[3] + b.mQ[2] * a.mQ[0] - b.mQ[0] * a.mQ[2],
00375                 b.mQ[3] * a.mQ[2] + b.mQ[2] * a.mQ[3] + b.mQ[0] * a.mQ[1] - b.mQ[1] * a.mQ[0],
00376                 b.mQ[3] * a.mQ[3] - b.mQ[0] * a.mQ[0] - b.mQ[1] * a.mQ[1] - b.mQ[2] * a.mQ[2]
00377         );
00378         a = q;
00379 #else
00380         a = a * b;
00381 #endif
00382         return a;
00383 }
00384 
00385 inline F32      LLQuaternion::normQuat()
00386 {
00387         F32 mag = sqrtf(mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] + mQ[VS]*mQ[VS]);
00388 
00389         if (mag > FP_MAG_THRESHOLD)
00390         {
00391                 F32 oomag = 1.f/mag;
00392                 mQ[VX] *= oomag;
00393                 mQ[VY] *= oomag;
00394                 mQ[VZ] *= oomag;
00395                 mQ[VS] *= oomag;
00396         }
00397         else
00398         {
00399                 mQ[VX] = 0.f;
00400                 mQ[VY] = 0.f;
00401                 mQ[VZ] = 0.f;
00402                 mQ[VS] = 1.f;
00403         }
00404 
00405         return mag;
00406 }
00407 
00408 LLQuaternion::Order StringToOrder( const char *str );
00409 
00410 // Some notes about Quaternions
00411 
00412 // What is a Quaternion?
00413 // ---------------------
00414 // A quaternion is a point in 4-dimensional complex space.
00415 // Q = { Qx, Qy, Qz, Qw }
00416 // 
00417 //
00418 // Why Quaternions?
00419 // ----------------
00420 // The set of quaternions that make up the the 4-D unit sphere 
00421 // can be mapped to the set of all rotations in 3-D space.  Sometimes
00422 // it is easier to describe/manipulate rotations in quaternion space
00423 // than rotation-matrix space.
00424 //
00425 //
00426 // How Quaternions?
00427 // ----------------
00428 // In order to take advantage of quaternions we need to know how to
00429 // go from rotation-matricies to quaternions and back.  We also have
00430 // to agree what variety of rotations we're generating.
00431 // 
00432 // Consider the equation...   v' = v * R 
00433 //
00434 // There are two ways to think about rotations of vectors.
00435 // 1) v' is the same vector in a different reference frame
00436 // 2) v' is a new vector in the same reference frame
00437 //
00438 // bookmark -- which way are we using?
00439 // 
00440 // 
00441 // Quaternion from Angle-Axis:
00442 // ---------------------------
00443 // Suppose we wanted to represent a rotation of some angle (theta) 
00444 // about some axis ({Ax, Ay, Az})...
00445 //
00446 // axis of rotation = {Ax, Ay, Az} 
00447 // angle_of_rotation = theta
00448 //
00449 // s = sin(0.5 * theta)
00450 // c = cos(0.5 * theta)
00451 // Q = { s * Ax, s * Ay, s * Az, c }
00452 //
00453 //
00454 // 3x3 Matrix from Quaternion
00455 // --------------------------
00456 //
00457 //     |                                                                    |
00458 //     | 1 - 2 * (y^2 + z^2)   2 * (x * y + z * w)     2 * (y * w - x * z)  |
00459 //     |                                                                    |
00460 // M = | 2 * (x * y - z * w)   1 - 2 * (x^2 + z^2)     2 * (y * z + x * w)  |
00461 //     |                                                                    |
00462 //     | 2 * (x * z + y * w)   2 * (y * z - x * w)     1 - 2 * (x^2 + y^2)  |
00463 //     |                                                                    |
00464 
00465 #endif

Generated on Thu Jul 1 06:09:04 2010 for Second Life Viewer by  doxygen 1.4.7