llquaternion.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 #include "llquaternion.h"
00035 
00036 #include "llmath.h"     // for F_PI
00037 //#include "vmath.h"
00038 #include "v3math.h"
00039 #include "v3dmath.h"
00040 #include "v4math.h"
00041 #include "m4math.h"
00042 #include "m3math.h"
00043 #include "llquantize.h"
00044 
00045 // WARNING: Don't use this for global const definitions!  using this
00046 // at the top of a *.cpp file might not give you what you think.
00047 const LLQuaternion LLQuaternion::DEFAULT;
00048  
00049 // Constructors
00050 
00051 LLQuaternion::LLQuaternion(const LLMatrix4 &mat)
00052 {
00053         *this = mat.quaternion();
00054         normQuat();
00055 }
00056 
00057 LLQuaternion::LLQuaternion(const LLMatrix3 &mat)
00058 {
00059         *this = mat.quaternion();
00060         normQuat();
00061 }
00062 
00063 LLQuaternion::LLQuaternion(F32 angle, const LLVector4 &vec)
00064 {
00065         LLVector3 v(vec.mV[VX], vec.mV[VY], vec.mV[VZ]);
00066         v.normVec();
00067 
00068         F32 c, s;
00069         c = cosf(angle*0.5f);
00070         s = sinf(angle*0.5f);
00071 
00072         mQ[VX] = v.mV[VX] * s;
00073         mQ[VY] = v.mV[VY] * s;
00074         mQ[VZ] = v.mV[VZ] * s;
00075         mQ[VW] = c;
00076         normQuat();
00077 }
00078 
00079 LLQuaternion::LLQuaternion(F32 angle, const LLVector3 &vec)
00080 {
00081         LLVector3 v(vec);
00082         v.normVec();
00083 
00084         F32 c, s;
00085         c = cosf(angle*0.5f);
00086         s = sinf(angle*0.5f);
00087 
00088         mQ[VX] = v.mV[VX] * s;
00089         mQ[VY] = v.mV[VY] * s;
00090         mQ[VZ] = v.mV[VZ] * s;
00091         mQ[VW] = c;
00092         normQuat();
00093 }
00094 
00095 LLQuaternion::LLQuaternion(const LLVector3 &x_axis,
00096                                                    const LLVector3 &y_axis,
00097                                                    const LLVector3 &z_axis)
00098 {
00099         LLMatrix3 mat;
00100         mat.setRows(x_axis, y_axis, z_axis);
00101         *this = mat.quaternion();
00102         normQuat();
00103 }
00104 
00105 // Quatizations
00106 void    LLQuaternion::quantize16(F32 lower, F32 upper)
00107 {
00108         F32 x = mQ[VX];
00109         F32 y = mQ[VY];
00110         F32 z = mQ[VZ];
00111         F32 s = mQ[VS];
00112 
00113         x = U16_to_F32(F32_to_U16_ROUND(x, lower, upper), lower, upper);
00114         y = U16_to_F32(F32_to_U16_ROUND(y, lower, upper), lower, upper);
00115         z = U16_to_F32(F32_to_U16_ROUND(z, lower, upper), lower, upper);
00116         s = U16_to_F32(F32_to_U16_ROUND(s, lower, upper), lower, upper);
00117 
00118         mQ[VX] = x;
00119         mQ[VY] = y;
00120         mQ[VZ] = z;
00121         mQ[VS] = s;
00122 
00123         normQuat();
00124 }
00125 
00126 void    LLQuaternion::quantize8(F32 lower, F32 upper)
00127 {
00128         mQ[VX] = U8_to_F32(F32_to_U8_ROUND(mQ[VX], lower, upper), lower, upper);
00129         mQ[VY] = U8_to_F32(F32_to_U8_ROUND(mQ[VY], lower, upper), lower, upper);
00130         mQ[VZ] = U8_to_F32(F32_to_U8_ROUND(mQ[VZ], lower, upper), lower, upper);
00131         mQ[VS] = U8_to_F32(F32_to_U8_ROUND(mQ[VS], lower, upper), lower, upper);
00132 
00133         normQuat();
00134 }
00135 
00136 // LLVector3 Magnitude and Normalization Functions
00137 
00138 
00139 // Set LLQuaternion routines
00140 
00141 const LLQuaternion&     LLQuaternion::setQuat(F32 angle, F32 x, F32 y, F32 z)
00142 {
00143         LLVector3 vec(x, y, z);
00144         vec.normVec();
00145 
00146         angle *= 0.5f;
00147         F32 c, s;
00148         c = cosf(angle);
00149         s = sinf(angle);
00150 
00151         mQ[VX] = vec.mV[VX]*s;
00152         mQ[VY] = vec.mV[VY]*s;
00153         mQ[VZ] = vec.mV[VZ]*s;
00154         mQ[VW] = c;
00155 
00156         normQuat();
00157         return (*this);
00158 }
00159 
00160 const LLQuaternion&     LLQuaternion::setQuat(F32 angle, const LLVector3 &vec)
00161 {
00162         LLVector3 v(vec);
00163         v.normVec();
00164 
00165         angle *= 0.5f;
00166         F32 c, s;
00167         c = cosf(angle);
00168         s = sinf(angle);
00169 
00170         mQ[VX] = v.mV[VX]*s;
00171         mQ[VY] = v.mV[VY]*s;
00172         mQ[VZ] = v.mV[VZ]*s;
00173         mQ[VW] = c;
00174 
00175         normQuat();
00176         return (*this);
00177 }
00178 
00179 const LLQuaternion&     LLQuaternion::setQuat(F32 angle, const LLVector4 &vec)
00180 {
00181         LLVector3 v(vec.mV[VX], vec.mV[VY], vec.mV[VZ]);
00182         v.normVec();
00183 
00184         F32 c, s;
00185         c = cosf(angle*0.5f);
00186         s = sinf(angle*0.5f);
00187 
00188         mQ[VX] = v.mV[VX]*s;
00189         mQ[VY] = v.mV[VY]*s;
00190         mQ[VZ] = v.mV[VZ]*s;
00191         mQ[VW] = c;
00192 
00193         normQuat();
00194         return (*this);
00195 }
00196 
00197 const LLQuaternion&     LLQuaternion::setQuat(F32 roll, F32 pitch, F32 yaw)
00198 {
00199         LLMatrix3 rot_mat(roll, pitch, yaw);
00200         rot_mat.orthogonalize();
00201         *this = rot_mat.quaternion();
00202                 
00203         normQuat();
00204         return (*this);
00205 //#if 1
00206 //      // NOTE: LLQuaternion's are actually inverted with respect to
00207 //      // the matrices, so this code also assumes inverted quaternions
00208 //      // (-x, -y, -z, w). The result is that roll,pitch,yaw are applied
00209 //      // in reverse order (yaw,pitch,roll).
00210 //      F64 cosX = cos(roll);
00211 //    F64 cosY = cos(pitch);
00212 //    F64 cosZ = cos(yaw);
00213 //
00214 //    F64 sinX = sin(roll);
00215 //    F64 sinY = sin(pitch);
00216 //    F64 sinZ = sin(yaw);
00217 //
00218 //    mQ[VW] = (F32)sqrt(cosY*cosZ - sinX*sinY*sinZ + cosX*cosZ + cosX*cosY + 1.0)*.5;
00219 //      if (fabs(mQ[VW]) < F_APPROXIMATELY_ZERO)
00220 //      {
00221 //              // null rotation, any axis will do
00222 //              mQ[VX] = 0.0f;
00223 //              mQ[VY] = 1.0f;
00224 //              mQ[VZ] = 0.0f;
00225 //      }
00226 //      else
00227 //      {
00228 //              F32 inv_s = 1.0f / (4.0f * mQ[VW]);
00229 //              mQ[VX] = (F32)-(-sinX*cosY - cosX*sinY*sinZ - sinX*cosZ) * inv_s;
00230 //              mQ[VY] = (F32)-(-cosX*sinY*cosZ + sinX*sinZ - sinY) * inv_s;
00231 //              mQ[VZ] = (F32)-(-cosY*sinZ - sinX*sinY*cosZ - cosX*sinZ) * inv_s;               
00232 //      }
00233 //
00234 //#else // This only works on a certain subset of roll/pitch/yaw
00235 //      
00236 //      F64 cosX = cosf(roll/2.0);
00237 //    F64 cosY = cosf(pitch/2.0);
00238 //    F64 cosZ = cosf(yaw/2.0);
00239 //
00240 //    F64 sinX = sinf(roll/2.0);
00241 //    F64 sinY = sinf(pitch/2.0);
00242 //    F64 sinZ = sinf(yaw/2.0);
00243 //
00244 //    mQ[VW] = (F32)(cosX*cosY*cosZ + sinX*sinY*sinZ);
00245 //    mQ[VX] = (F32)(sinX*cosY*cosZ - cosX*sinY*sinZ);
00246 //    mQ[VY] = (F32)(cosX*sinY*cosZ + sinX*cosY*sinZ);
00247 //    mQ[VZ] = (F32)(cosX*cosY*sinZ - sinX*sinY*cosZ);
00248 //#endif
00249 //
00250 //      normQuat();
00251 //      return (*this);
00252 }
00253 
00254 // SJB: This code is correct for a logicly stored (non-transposed) matrix;
00255 //              Our matrices are stored transposed, OpenGL style, so this generates the
00256 //              INVERSE matrix, or the CORRECT matrix form an INVERSE quaternion.
00257 //              Because we use similar logic in LLMatrix3::quaternion(),
00258 //              we are internally consistant so everything works OK :)
00259 LLMatrix3       LLQuaternion::getMatrix3(void) const
00260 {
00261         LLMatrix3       mat;
00262         F32             xx, xy, xz, xw, yy, yz, yw, zz, zw;
00263 
00264     xx      = mQ[VX] * mQ[VX];
00265     xy      = mQ[VX] * mQ[VY];
00266     xz      = mQ[VX] * mQ[VZ];
00267     xw      = mQ[VX] * mQ[VW];
00268 
00269     yy      = mQ[VY] * mQ[VY];
00270     yz      = mQ[VY] * mQ[VZ];
00271     yw      = mQ[VY] * mQ[VW];
00272 
00273     zz      = mQ[VZ] * mQ[VZ];
00274     zw      = mQ[VZ] * mQ[VW];
00275 
00276     mat.mMatrix[0][0]  = 1.f - 2.f * ( yy + zz );
00277     mat.mMatrix[0][1]  =           2.f * ( xy + zw );
00278     mat.mMatrix[0][2]  =           2.f * ( xz - yw );
00279 
00280     mat.mMatrix[1][0]  =           2.f * ( xy - zw );
00281     mat.mMatrix[1][1]  = 1.f - 2.f * ( xx + zz );
00282     mat.mMatrix[1][2]  =           2.f * ( yz + xw );
00283 
00284     mat.mMatrix[2][0]  =           2.f * ( xz + yw );
00285     mat.mMatrix[2][1]  =           2.f * ( yz - xw );
00286     mat.mMatrix[2][2]  = 1.f - 2.f * ( xx + yy );
00287 
00288         return mat;
00289 }
00290 
00291 LLMatrix4       LLQuaternion::getMatrix4(void) const
00292 {
00293         LLMatrix4       mat;
00294         F32             xx, xy, xz, xw, yy, yz, yw, zz, zw;
00295 
00296     xx      = mQ[VX] * mQ[VX];
00297     xy      = mQ[VX] * mQ[VY];
00298     xz      = mQ[VX] * mQ[VZ];
00299     xw      = mQ[VX] * mQ[VW];
00300 
00301     yy      = mQ[VY] * mQ[VY];
00302     yz      = mQ[VY] * mQ[VZ];
00303     yw      = mQ[VY] * mQ[VW];
00304 
00305     zz      = mQ[VZ] * mQ[VZ];
00306     zw      = mQ[VZ] * mQ[VW];
00307 
00308     mat.mMatrix[0][0]  = 1.f - 2.f * ( yy + zz );
00309     mat.mMatrix[0][1]  =           2.f * ( xy + zw );
00310     mat.mMatrix[0][2]  =           2.f * ( xz - yw );
00311 
00312     mat.mMatrix[1][0]  =           2.f * ( xy - zw );
00313     mat.mMatrix[1][1]  = 1.f - 2.f * ( xx + zz );
00314     mat.mMatrix[1][2]  =           2.f * ( yz + xw );
00315 
00316     mat.mMatrix[2][0]  =           2.f * ( xz + yw );
00317     mat.mMatrix[2][1]  =           2.f * ( yz - xw );
00318     mat.mMatrix[2][2]  = 1.f - 2.f * ( xx + yy );
00319 
00320         // TODO -- should we set the translation portion to zero?
00321 
00322         return mat;
00323 }
00324 
00325 
00326 
00327 
00328 // Other useful methods
00329 
00330 
00331 // calculate the shortest rotation from a to b
00332 void LLQuaternion::shortestArc(const LLVector3 &a, const LLVector3 &b)
00333 {
00334         // Make a local copy of both vectors.
00335         LLVector3 vec_a = a;
00336         LLVector3 vec_b = b;
00337 
00338         // Make sure neither vector is zero length.  Also normalize
00339         // the vectors while we are at it.
00340         F32 vec_a_mag = vec_a.normVec();
00341         F32 vec_b_mag = vec_b.normVec();
00342         if (vec_a_mag < F_APPROXIMATELY_ZERO ||
00343                 vec_b_mag < F_APPROXIMATELY_ZERO)
00344         {
00345                 // Can't calculate a rotation from this.
00346                 // Just return ZERO_ROTATION instead.
00347                 loadIdentity();
00348                 return;
00349         }
00350 
00351         // Create an axis to rotate around, and the cos of the angle to rotate.
00352         LLVector3 axis = vec_a % vec_b;
00353         F32 cos_theta  = vec_a * vec_b;
00354 
00355         // Check the angle between the vectors to see if they are parallel or anti-parallel.
00356         if (cos_theta > 1.0 - F_APPROXIMATELY_ZERO)
00357         {
00358                 // a and b are parallel.  No rotation is necessary.
00359                 loadIdentity();
00360         }
00361         else if (cos_theta < -1.0 + F_APPROXIMATELY_ZERO)
00362         {
00363                 // a and b are anti-parallel.
00364                 // Rotate 180 degrees around some orthogonal axis.
00365                 // Find the projection of the x-axis onto a, and try
00366                 // using the vector between the projection and the x-axis
00367                 // as the orthogonal axis.
00368                 LLVector3 proj = vec_a.mV[VX] / (vec_a * vec_a) * vec_a;
00369                 LLVector3 ortho_axis(1.f, 0.f, 0.f);
00370                 ortho_axis -= proj;
00371                 
00372                 // Turn this into an orthonormal axis.
00373                 F32 ortho_length = ortho_axis.normVec();
00374                 // If the axis' length is 0, then our guess at an orthogonal axis
00375                 // was wrong (a is parallel to the x-axis).
00376                 if (ortho_length < F_APPROXIMATELY_ZERO)
00377                 {
00378                         // Use the z-axis instead.
00379                         ortho_axis.setVec(0.f, 0.f, 1.f);
00380                 }
00381 
00382                 // Construct a quaternion from this orthonormal axis.
00383                 mQ[VX] = ortho_axis.mV[VX];
00384                 mQ[VY] = ortho_axis.mV[VY];
00385                 mQ[VZ] = ortho_axis.mV[VZ];
00386                 mQ[VW] = 0.f;
00387         }
00388         else
00389         {
00390                 // a and b are NOT parallel or anti-parallel.
00391                 // Return the rotation between these vectors.
00392                 F32 theta = (F32)acos(cos_theta);
00393 
00394                 setQuat(theta, axis);
00395         }
00396 }
00397 
00398 // constrains rotation to a cone angle specified in radians
00399 const LLQuaternion &LLQuaternion::constrain(F32 radians)
00400 {
00401         const F32 cos_angle_lim = cosf( radians/2 );    // mQ[VW] limit
00402         const F32 sin_angle_lim = sinf( radians/2 );    // rotation axis length limit
00403 
00404         if (mQ[VW] < 0.f)
00405         {
00406                 mQ[VX] *= -1.f;
00407                 mQ[VY] *= -1.f;
00408                 mQ[VZ] *= -1.f;
00409                 mQ[VW] *= -1.f;
00410         }
00411 
00412         // if rotation angle is greater than limit (cos is less than limit)
00413         if( mQ[VW] < cos_angle_lim )
00414         {
00415                 mQ[VW] = cos_angle_lim;
00416                 F32 axis_len = sqrtf( mQ[VX]*mQ[VX] + mQ[VY]*mQ[VY] + mQ[VZ]*mQ[VZ] ); // sin(theta/2)
00417                 F32 axis_mult_fact = sin_angle_lim / axis_len;
00418                 mQ[VX] *= axis_mult_fact;
00419                 mQ[VY] *= axis_mult_fact;
00420                 mQ[VZ] *= axis_mult_fact;
00421         }
00422 
00423         return *this;
00424 }
00425 
00426 // Operators
00427 
00428 std::ostream& operator<<(std::ostream &s, const LLQuaternion &a)
00429 {
00430         s << "{ " 
00431                 << a.mQ[VX] << ", " << a.mQ[VY] << ", " << a.mQ[VZ] << ", " << a.mQ[VW] 
00432         << " }";
00433         return s;
00434 }
00435 
00436 
00437 // Does NOT renormalize the result
00438 LLQuaternion    operator*(const LLQuaternion &a, const LLQuaternion &b)
00439 {
00440 //      LLQuaternion::mMultCount++;
00441 
00442         LLQuaternion q(
00443                 b.mQ[3] * a.mQ[0] + b.mQ[0] * a.mQ[3] + b.mQ[1] * a.mQ[2] - b.mQ[2] * a.mQ[1],
00444                 b.mQ[3] * a.mQ[1] + b.mQ[1] * a.mQ[3] + b.mQ[2] * a.mQ[0] - b.mQ[0] * a.mQ[2],
00445                 b.mQ[3] * a.mQ[2] + b.mQ[2] * a.mQ[3] + b.mQ[0] * a.mQ[1] - b.mQ[1] * a.mQ[0],
00446                 b.mQ[3] * a.mQ[3] - b.mQ[0] * a.mQ[0] - b.mQ[1] * a.mQ[1] - b.mQ[2] * a.mQ[2]
00447         );
00448         return q;
00449 }
00450 
00451 /*
00452 LLMatrix4       operator*(const LLMatrix4 &m, const LLQuaternion &q)
00453 {
00454         LLMatrix4 qmat(q);
00455         return (m*qmat);
00456 }
00457 */
00458 
00459 
00460 
00461 LLVector4               operator*(const LLVector4 &a, const LLQuaternion &rot)
00462 {
00463     F32 rw = - rot.mQ[VX] * a.mV[VX] - rot.mQ[VY] * a.mV[VY] - rot.mQ[VZ] * a.mV[VZ];
00464     F32 rx =   rot.mQ[VW] * a.mV[VX] + rot.mQ[VY] * a.mV[VZ] - rot.mQ[VZ] * a.mV[VY];
00465     F32 ry =   rot.mQ[VW] * a.mV[VY] + rot.mQ[VZ] * a.mV[VX] - rot.mQ[VX] * a.mV[VZ];
00466     F32 rz =   rot.mQ[VW] * a.mV[VZ] + rot.mQ[VX] * a.mV[VY] - rot.mQ[VY] * a.mV[VX];
00467 
00468     F32 nx = - rw * rot.mQ[VX] +  rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY];
00469     F32 ny = - rw * rot.mQ[VY] +  ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ];
00470     F32 nz = - rw * rot.mQ[VZ] +  rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX];
00471 
00472     return LLVector4(nx, ny, nz, a.mV[VW]);
00473 }
00474 
00475 LLVector3               operator*(const LLVector3 &a, const LLQuaternion &rot)
00476 {
00477     F32 rw = - rot.mQ[VX] * a.mV[VX] - rot.mQ[VY] * a.mV[VY] - rot.mQ[VZ] * a.mV[VZ];
00478     F32 rx =   rot.mQ[VW] * a.mV[VX] + rot.mQ[VY] * a.mV[VZ] - rot.mQ[VZ] * a.mV[VY];
00479     F32 ry =   rot.mQ[VW] * a.mV[VY] + rot.mQ[VZ] * a.mV[VX] - rot.mQ[VX] * a.mV[VZ];
00480     F32 rz =   rot.mQ[VW] * a.mV[VZ] + rot.mQ[VX] * a.mV[VY] - rot.mQ[VY] * a.mV[VX];
00481 
00482     F32 nx = - rw * rot.mQ[VX] +  rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY];
00483     F32 ny = - rw * rot.mQ[VY] +  ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ];
00484     F32 nz = - rw * rot.mQ[VZ] +  rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX];
00485 
00486     return LLVector3(nx, ny, nz);
00487 }
00488 
00489 LLVector3d              operator*(const LLVector3d &a, const LLQuaternion &rot)
00490 {
00491     F64 rw = - rot.mQ[VX] * a.mdV[VX] - rot.mQ[VY] * a.mdV[VY] - rot.mQ[VZ] * a.mdV[VZ];
00492     F64 rx =   rot.mQ[VW] * a.mdV[VX] + rot.mQ[VY] * a.mdV[VZ] - rot.mQ[VZ] * a.mdV[VY];
00493     F64 ry =   rot.mQ[VW] * a.mdV[VY] + rot.mQ[VZ] * a.mdV[VX] - rot.mQ[VX] * a.mdV[VZ];
00494     F64 rz =   rot.mQ[VW] * a.mdV[VZ] + rot.mQ[VX] * a.mdV[VY] - rot.mQ[VY] * a.mdV[VX];
00495 
00496     F64 nx = - rw * rot.mQ[VX] +  rx * rot.mQ[VW] - ry * rot.mQ[VZ] + rz * rot.mQ[VY];
00497     F64 ny = - rw * rot.mQ[VY] +  ry * rot.mQ[VW] - rz * rot.mQ[VX] + rx * rot.mQ[VZ];
00498     F64 nz = - rw * rot.mQ[VZ] +  rz * rot.mQ[VW] - rx * rot.mQ[VY] + ry * rot.mQ[VX];
00499 
00500     return LLVector3d(nx, ny, nz);
00501 }
00502 
00503 F32 dot(const LLQuaternion &a, const LLQuaternion &b)
00504 {
00505         return a.mQ[VX] * b.mQ[VX] + 
00506                    a.mQ[VY] * b.mQ[VY] + 
00507                    a.mQ[VZ] * b.mQ[VZ] + 
00508                    a.mQ[VW] * b.mQ[VW]; 
00509 }
00510 
00511 // DEMO HACK: This lerp is probably inocrrect now due intermediate normalization
00512 // it should look more like the lerp below
00513 #if 0
00514 // linear interpolation
00515 LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q)
00516 {
00517         LLQuaternion r;
00518         r = t * (q - p) + p;
00519         r.normQuat();
00520         return r;
00521 }
00522 #endif
00523 
00524 // lerp from identity to q
00525 LLQuaternion lerp(F32 t, const LLQuaternion &q)
00526 {
00527         LLQuaternion r;
00528         r.mQ[VX] = t * q.mQ[VX];
00529         r.mQ[VY] = t * q.mQ[VY];
00530         r.mQ[VZ] = t * q.mQ[VZ];
00531         r.mQ[VW] = t * (q.mQ[VZ] - 1.f) + 1.f;
00532         r.normQuat();
00533         return r;
00534 }
00535 
00536 LLQuaternion lerp(F32 t, const LLQuaternion &p, const LLQuaternion &q)
00537 {
00538         LLQuaternion r;
00539         F32 inv_t;
00540 
00541         inv_t = 1.f - t;
00542 
00543         r.mQ[VX] = t * q.mQ[VX] + (inv_t * p.mQ[VX]);
00544         r.mQ[VY] = t * q.mQ[VY] + (inv_t * p.mQ[VY]);
00545         r.mQ[VZ] = t * q.mQ[VZ] + (inv_t * p.mQ[VZ]);
00546         r.mQ[VW] = t * q.mQ[VW] + (inv_t * p.mQ[VW]);
00547         r.normQuat();
00548         return r;
00549 }
00550 
00551 
00552 // spherical linear interpolation
00553 LLQuaternion slerp( F32 u, const LLQuaternion &a, const LLQuaternion &b )
00554 {
00555         // cosine theta = dot product of a and b
00556         F32 cos_t = a.mQ[0]*b.mQ[0] + a.mQ[1]*b.mQ[1] + a.mQ[2]*b.mQ[2] + a.mQ[3]*b.mQ[3];
00557         
00558         // if b is on opposite hemisphere from a, use -a instead
00559         int bflip;
00560         if (cos_t < 0.0f)
00561         {
00562                 cos_t = -cos_t;
00563                 bflip = TRUE;
00564         }
00565         else
00566                 bflip = FALSE;
00567 
00568         // if B is (within precision limits) the same as A,
00569         // just linear interpolate between A and B.
00570         F32 alpha;      // interpolant
00571         F32 beta;               // 1 - interpolant
00572         if (1.0f - cos_t < 0.00001f)
00573         {
00574                 beta = 1.0f - u;
00575                 alpha = u;
00576         }
00577         else
00578         {
00579                 F32 theta = acosf(cos_t);
00580                 F32 sin_t = sinf(theta);
00581                 beta = sinf(theta - u*theta) / sin_t;
00582                 alpha = sinf(u*theta) / sin_t;
00583         }
00584 
00585         if (bflip)
00586                 beta = -beta;
00587 
00588         // interpolate
00589         LLQuaternion ret;
00590         ret.mQ[0] = beta*a.mQ[0] + alpha*b.mQ[0];
00591         ret.mQ[1] = beta*a.mQ[1] + alpha*b.mQ[1];
00592         ret.mQ[2] = beta*a.mQ[2] + alpha*b.mQ[2];
00593         ret.mQ[3] = beta*a.mQ[3] + alpha*b.mQ[3];
00594 
00595         return ret;
00596 }
00597 
00598 // lerp whenever possible
00599 LLQuaternion nlerp(F32 t, const LLQuaternion &a, const LLQuaternion &b)
00600 {
00601         if (dot(a, b) < 0.f)
00602         {
00603                 return slerp(t, a, b);
00604         }
00605         else
00606         {
00607                 return lerp(t, a, b);
00608         }
00609 }
00610 
00611 LLQuaternion nlerp(F32 t, const LLQuaternion &q)
00612 {
00613         if (q.mQ[VW] < 0.f)
00614         {
00615                 return slerp(t, q);
00616         }
00617         else
00618         {
00619                 return lerp(t, q);
00620         }
00621 }
00622 
00623 // slerp from identity quaternion to another quaternion
00624 LLQuaternion slerp(F32 t, const LLQuaternion &q)
00625 {
00626         F32 c = q.mQ[VW];
00627         if (1.0f == t  ||  1.0f == c)
00628         {
00629                 // the trivial cases
00630                 return q;
00631         }
00632 
00633         LLQuaternion r;
00634         F32 s, angle, stq, stp;
00635 
00636         s = (F32) sqrt(1.f - c*c);
00637 
00638     if (c < 0.0f)
00639     {
00640         // when c < 0.0 then theta > PI/2 
00641         // since quat and -quat are the same rotation we invert one of  
00642         // p or q to reduce unecessary spins
00643         // A equivalent way to do it is to convert acos(c) as if it had been negative,
00644         // and to negate stp 
00645         angle   = (F32) acos(-c); 
00646         stp     = -(F32) sin(angle * (1.f - t));
00647         stq     = (F32) sin(angle * t);
00648     }   
00649     else
00650     {
00651                 angle   = (F32) acos(c);
00652         stp     = (F32) sin(angle * (1.f - t));
00653         stq     = (F32) sin(angle * t);
00654     }
00655 
00656         r.mQ[VX] = (q.mQ[VX] * stq) / s;
00657         r.mQ[VY] = (q.mQ[VY] * stq) / s;
00658         r.mQ[VZ] = (q.mQ[VZ] * stq) / s;
00659         r.mQ[VW] = (stp + q.mQ[VW] * stq) / s;
00660 
00661         return r;
00662 }
00663 
00664 LLQuaternion mayaQ(F32 xRot, F32 yRot, F32 zRot, LLQuaternion::Order order)
00665 {
00666         LLQuaternion xQ( xRot*DEG_TO_RAD, LLVector3(1.0f, 0.0f, 0.0f) );
00667         LLQuaternion yQ( yRot*DEG_TO_RAD, LLVector3(0.0f, 1.0f, 0.0f) );
00668         LLQuaternion zQ( zRot*DEG_TO_RAD, LLVector3(0.0f, 0.0f, 1.0f) );
00669         LLQuaternion ret;
00670         switch( order )
00671         {
00672         case LLQuaternion::XYZ:
00673                 ret = xQ * yQ * zQ;
00674                 break;
00675         case LLQuaternion::YZX:
00676                 ret = yQ * zQ * xQ;
00677                 break;
00678         case LLQuaternion::ZXY:
00679                 ret = zQ * xQ * yQ;
00680                 break;
00681         case LLQuaternion::XZY:
00682                 ret = xQ * zQ * yQ;
00683                 break;
00684         case LLQuaternion::YXZ:
00685                 ret = yQ * xQ * zQ;
00686                 break;
00687         case LLQuaternion::ZYX:
00688                 ret = zQ * yQ * xQ;
00689                 break;
00690         }
00691         return ret;
00692 }
00693 
00694 const char *OrderToString( const LLQuaternion::Order order )
00695 {
00696         char *p = NULL;
00697         switch( order )
00698         {
00699         default:
00700         case LLQuaternion::XYZ:
00701                 p = "XYZ";
00702                 break;
00703         case LLQuaternion::YZX:
00704                 p = "YZX";
00705                 break;
00706         case LLQuaternion::ZXY:
00707                 p = "ZXY";
00708                 break;
00709         case LLQuaternion::XZY:
00710                 p = "XZY";
00711                 break;
00712         case LLQuaternion::YXZ:
00713                 p = "YXZ";
00714                 break;
00715         case LLQuaternion::ZYX:
00716                 p = "ZYX";
00717                 break;
00718         }
00719         return p;
00720 }
00721 
00722 LLQuaternion::Order StringToOrder( const char *str )
00723 {
00724         if (strncmp(str, "XYZ", 3)==0 || strncmp(str, "xyz", 3)==0)
00725                 return LLQuaternion::XYZ;
00726 
00727         if (strncmp(str, "YZX", 3)==0 || strncmp(str, "yzx", 3)==0)
00728                 return LLQuaternion::YZX;
00729 
00730         if (strncmp(str, "ZXY", 3)==0 || strncmp(str, "zxy", 3)==0)
00731                 return LLQuaternion::ZXY;
00732 
00733         if (strncmp(str, "XZY", 3)==0 || strncmp(str, "xzy", 3)==0)
00734                 return LLQuaternion::XZY;
00735 
00736         if (strncmp(str, "YXZ", 3)==0 || strncmp(str, "yxz", 3)==0)
00737                 return LLQuaternion::YXZ;
00738 
00739         if (strncmp(str, "ZYX", 3)==0 || strncmp(str, "zyx", 3)==0)
00740                 return LLQuaternion::ZYX;
00741 
00742         return LLQuaternion::XYZ;
00743 }
00744 
00745 const LLQuaternion&     LLQuaternion::setQuat(const LLMatrix3 &mat)
00746 {
00747         *this = mat.quaternion();
00748         normQuat();
00749         return (*this);
00750 }
00751 
00752 const LLQuaternion&     LLQuaternion::setQuat(const LLMatrix4 &mat)
00753 {
00754         *this = mat.quaternion();
00755         normQuat();
00756         return (*this);
00757 }
00758 
00759 void LLQuaternion::getAngleAxis(F32* angle, LLVector3 &vec) const
00760 {
00761         F32 cos_a = mQ[VW];
00762         if (cos_a > 1.0f) cos_a = 1.0f;
00763         if (cos_a < -1.0f) cos_a = -1.0f;
00764 
00765     F32 sin_a = (F32) sqrt( 1.0f - cos_a * cos_a );
00766 
00767     if ( fabs( sin_a ) < 0.0005f )
00768                 sin_a = 1.0f;
00769         else
00770                 sin_a = 1.f/sin_a;
00771 
00772     *angle = 2.0f * (F32) acos( cos_a );
00773     vec.mV[VX] = mQ[VX] * sin_a;
00774     vec.mV[VY] = mQ[VY] * sin_a;
00775     vec.mV[VZ] = mQ[VZ] * sin_a;
00776 }
00777 
00778 
00779 // quaternion does not need to be normalized
00780 void LLQuaternion::getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) const
00781 {
00782         LLMatrix3 rot_mat(*this);
00783         rot_mat.orthogonalize();
00784         rot_mat.getEulerAngles(roll, pitch, yaw);
00785 
00786 //      // NOTE: LLQuaternion's are actually inverted with respect to
00787 //      // the matrices, so this code also assumes inverted quaternions
00788 //      // (-x, -y, -z, w). The result is that roll,pitch,yaw are applied
00789 //      // in reverse order (yaw,pitch,roll).
00790 //      F32 x = -mQ[VX], y = -mQ[VY], z = -mQ[VZ], w = mQ[VW];
00791 //      F64 m20 = 2.0*(x*z-y*w);
00792 //      if (1.0f - fabsf(m20) < F_APPROXIMATELY_ZERO)
00793 //      {
00794 //              *roll = 0.0f;
00795 //              *pitch = (F32)asin(m20);
00796 //              *yaw = (F32)atan2(2.0*(x*y-z*w), 1.0 - 2.0*(x*x+z*z));
00797 //      }
00798 //      else
00799 //      {
00800 //              *roll  = (F32)atan2(-2.0*(y*z+x*w), 1.0-2.0*(x*x+y*y));
00801 //              *pitch = (F32)asin(m20);
00802 //              *yaw   = (F32)atan2(-2.0*(x*y+z*w), 1.0-2.0*(y*y+z*z));
00803 //      }
00804 }
00805 
00806 // Saves space by using the fact that our quaternions are normalized
00807 LLVector3 LLQuaternion::packToVector3() const
00808 {
00809         if( mQ[VW] >= 0 )
00810         {
00811                 return LLVector3( mQ[VX], mQ[VY], mQ[VZ] );
00812         }
00813         else
00814         {
00815                 return LLVector3( -mQ[VX], -mQ[VY], -mQ[VZ] );
00816         }
00817 }
00818 
00819 // Saves space by using the fact that our quaternions are normalized
00820 void LLQuaternion::unpackFromVector3( const LLVector3& vec )
00821 {
00822         mQ[VX] = vec.mV[VX];
00823         mQ[VY] = vec.mV[VY];
00824         mQ[VZ] = vec.mV[VZ];
00825         F32 t = 1.f - vec.magVecSquared();
00826         if( t > 0 )
00827         {
00828                 mQ[VW] = sqrt( t );
00829         }
00830         else
00831         {
00832                 // Need this to avoid trying to find the square root of a negative number due
00833                 // to floating point error.
00834                 mQ[VW] = 0;
00835         }
00836 }
00837 
00838 BOOL LLQuaternion::parseQuat(const char* buf, LLQuaternion* value)
00839 {
00840         if( buf == NULL || buf[0] == '\0' || value == NULL)
00841         {
00842                 return FALSE;
00843         }
00844 
00845         LLQuaternion quat;
00846         S32 count = sscanf( buf, "%f %f %f %f", quat.mQ + 0, quat.mQ + 1, quat.mQ + 2, quat.mQ + 3 );
00847         if( 4 == count )
00848         {
00849                 value->setQuat( quat );
00850                 return TRUE;
00851         }
00852 
00853         return FALSE;
00854 }
00855 
00856 
00857 // End

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