m3math.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 //#include "vmath.h"
00035 #include "v3math.h"
00036 #include "v3dmath.h"
00037 #include "v4math.h"
00038 #include "m4math.h"
00039 #include "m3math.h"
00040 #include "llquaternion.h"
00041 
00042 // LLMatrix3
00043 
00044 //              ji  
00045 // LLMatrix3 = |00 01 02 |
00046 //             |10 11 12 |
00047 //             |20 21 22 |
00048 
00049 // LLMatrix3 = |fx fy fz |  forward-axis
00050 //             |lx ly lz |  left-axis
00051 //             |ux uy uz |  up-axis
00052 
00053 
00054 // Constructors
00055 
00056 
00057 LLMatrix3::LLMatrix3(const LLQuaternion &q)
00058 {
00059         setRot(q);
00060 }
00061 
00062 
00063 LLMatrix3::LLMatrix3(const F32 angle, const LLVector3 &vec)
00064 {
00065         LLQuaternion    quat(angle, vec);
00066         setRot(quat);
00067 }
00068 
00069 LLMatrix3::LLMatrix3(const F32 angle, const LLVector3d &vec)
00070 {
00071         LLVector3 vec_f;
00072         vec_f.setVec(vec);
00073         LLQuaternion    quat(angle, vec_f);
00074         setRot(quat);
00075 }
00076 
00077 LLMatrix3::LLMatrix3(const F32 angle, const LLVector4 &vec)
00078 {
00079         LLQuaternion    quat(angle, vec);
00080         setRot(quat);
00081 }
00082 
00083 LLMatrix3::LLMatrix3(const F32 angle, const F32 x, const F32 y, const F32 z)
00084 {
00085         LLVector3 vec(x, y, z);
00086         LLQuaternion    quat(angle, vec);
00087         setRot(quat);
00088 }
00089 
00090 LLMatrix3::LLMatrix3(const F32 roll, const F32 pitch, const F32 yaw)
00091 {
00092         setRot(roll,pitch,yaw);
00093 }
00094 
00095 // From Matrix and Quaternion FAQ
00096 void LLMatrix3::getEulerAngles(F32 *roll, F32 *pitch, F32 *yaw) const
00097 {
00098         F64 angle_x, angle_y, angle_z;
00099         F64 cx, cy, cz;                                 // cosine of angle_x, angle_y, angle_z
00100         F64 sx,     sz;                                 // sine of angle_x, angle_y, angle_z
00101 
00102         angle_y = asin(llclamp(mMatrix[2][0], -1.f, 1.f));
00103         cy = cos(angle_y);
00104 
00105         if (fabs(cy) > 0.005)           // non-zero
00106         {
00107                 // no gimbal lock
00108                 cx = mMatrix[2][2] / cy;
00109                 sx = - mMatrix[2][1] / cy;
00110 
00111                 angle_x = (F32) atan2(sx, cx);
00112 
00113                 cz = mMatrix[0][0] / cy;
00114                 sz = - mMatrix[1][0] / cy;
00115 
00116                 angle_z = (F32) atan2(sz, cz);
00117         }
00118         else
00119         {
00120                 // yup, gimbal lock
00121                 angle_x = 0;
00122 
00123                 // some tricky math thereby avoided, see article
00124 
00125                 cz = mMatrix[1][1];
00126                 sz = mMatrix[0][1];
00127 
00128                 angle_z = atan2(sz, cz);
00129         }
00130 
00131         *roll = (F32)angle_x;
00132         *pitch = (F32)angle_y;
00133         *yaw = (F32)angle_z;
00134 }
00135         
00136 
00137 // Clear and Assignment Functions
00138 
00139 const LLMatrix3&        LLMatrix3::identity()
00140 {
00141         mMatrix[0][0] = 1.f;
00142         mMatrix[0][1] = 0.f;
00143         mMatrix[0][2] = 0.f;
00144 
00145         mMatrix[1][0] = 0.f;
00146         mMatrix[1][1] = 1.f;
00147         mMatrix[1][2] = 0.f;
00148 
00149         mMatrix[2][0] = 0.f;
00150         mMatrix[2][1] = 0.f;
00151         mMatrix[2][2] = 1.f;
00152         return (*this);
00153 }
00154 
00155 const LLMatrix3&        LLMatrix3::zero()
00156 {
00157         mMatrix[0][0] = 0.f;
00158         mMatrix[0][1] = 0.f;
00159         mMatrix[0][2] = 0.f;
00160 
00161         mMatrix[1][0] = 0.f;
00162         mMatrix[1][1] = 0.f;
00163         mMatrix[1][2] = 0.f;
00164 
00165         mMatrix[2][0] = 0.f;
00166         mMatrix[2][1] = 0.f;
00167         mMatrix[2][2] = 0.f;
00168         return (*this);
00169 }
00170 
00171 // various useful mMatrix functions
00172 
00173 const LLMatrix3&        LLMatrix3::transpose() 
00174 {
00175         // transpose the matrix
00176         F32 temp;
00177         temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp;
00178         temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp;
00179         temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp;
00180         return *this;
00181 }
00182 
00183 
00184 F32             LLMatrix3::determinant() const
00185 {
00186         // Is this a useful method when we assume the matrices are valid rotation
00187         // matrices throughout this implementation?
00188         return  mMatrix[0][0] * (mMatrix[1][1] * mMatrix[2][2] - mMatrix[1][2] * mMatrix[2][1]) +
00189                         mMatrix[0][1] * (mMatrix[1][2] * mMatrix[2][0] - mMatrix[1][0] * mMatrix[2][2]) +
00190                         mMatrix[0][2] * (mMatrix[1][0] * mMatrix[2][1] - mMatrix[1][1] * mMatrix[2][0]); 
00191 }
00192 
00193 // This is identical to the transMat3() method because we assume a rotation matrix
00194 const LLMatrix3&        LLMatrix3::invert()
00195 {
00196         // transpose the matrix
00197         F32 temp;
00198         temp = mMatrix[VX][VY]; mMatrix[VX][VY] = mMatrix[VY][VX]; mMatrix[VY][VX] = temp;
00199         temp = mMatrix[VX][VZ]; mMatrix[VX][VZ] = mMatrix[VZ][VX]; mMatrix[VZ][VX] = temp;
00200         temp = mMatrix[VY][VZ]; mMatrix[VY][VZ] = mMatrix[VZ][VY]; mMatrix[VZ][VY] = temp;
00201         return *this;
00202 }
00203 
00204 // does not assume a rotation matrix, and does not divide by determinant, assuming results will be renormalized
00205 const LLMatrix3&        LLMatrix3::adjointTranspose()
00206 {
00207         LLMatrix3 adjoint_transpose;
00208         adjoint_transpose.mMatrix[VX][VX] = mMatrix[VY][VY] * mMatrix[VZ][VZ] - mMatrix[VY][VZ] * mMatrix[VZ][VY] ;
00209         adjoint_transpose.mMatrix[VY][VX] = mMatrix[VY][VZ] * mMatrix[VZ][VX] - mMatrix[VY][VX] * mMatrix[VZ][VZ] ;
00210         adjoint_transpose.mMatrix[VZ][VX] = mMatrix[VY][VX] * mMatrix[VZ][VY] - mMatrix[VY][VY] * mMatrix[VZ][VX] ;
00211         adjoint_transpose.mMatrix[VX][VY] = mMatrix[VZ][VY] * mMatrix[VX][VZ] - mMatrix[VZ][VZ] * mMatrix[VX][VY] ;
00212         adjoint_transpose.mMatrix[VY][VY] = mMatrix[VZ][VZ] * mMatrix[VX][VX] - mMatrix[VZ][VX] * mMatrix[VX][VZ] ;
00213         adjoint_transpose.mMatrix[VZ][VY] = mMatrix[VZ][VX] * mMatrix[VX][VY] - mMatrix[VZ][VY] * mMatrix[VX][VX] ;
00214         adjoint_transpose.mMatrix[VX][VZ] = mMatrix[VX][VY] * mMatrix[VY][VZ] - mMatrix[VX][VZ] * mMatrix[VY][VY] ;
00215         adjoint_transpose.mMatrix[VY][VZ] = mMatrix[VX][VZ] * mMatrix[VY][VX] - mMatrix[VX][VX] * mMatrix[VY][VZ] ;
00216         adjoint_transpose.mMatrix[VZ][VZ] = mMatrix[VX][VX] * mMatrix[VY][VY] - mMatrix[VX][VY] * mMatrix[VY][VX] ;
00217 
00218         *this = adjoint_transpose;
00219         return *this;
00220 }
00221 
00222 // SJB: This code is correct for a logicly stored (non-transposed) matrix;
00223 //              Our matrices are stored transposed, OpenGL style, so this generates the
00224 //              INVERSE quaternion (-x, -y, -z, w)!
00225 //              Because we use similar logic in LLQuaternion::getMatrix3,
00226 //              we are internally consistant so everything works OK :)
00227 LLQuaternion    LLMatrix3::quaternion() const
00228 {
00229         LLQuaternion    quat;
00230         F32             tr, s, q[4];
00231         U32             i, j, k;
00232         U32             nxt[3] = {1, 2, 0};
00233 
00234         tr = mMatrix[0][0] + mMatrix[1][1] + mMatrix[2][2];
00235 
00236         // check the diagonal
00237         if (tr > 0.f) 
00238         {
00239                 s = (F32)sqrt (tr + 1.f);
00240                 quat.mQ[VS] = s / 2.f;
00241                 s = 0.5f / s;
00242                 quat.mQ[VX] = (mMatrix[1][2] - mMatrix[2][1]) * s;
00243                 quat.mQ[VY] = (mMatrix[2][0] - mMatrix[0][2]) * s;
00244                 quat.mQ[VZ] = (mMatrix[0][1] - mMatrix[1][0]) * s;
00245         } 
00246         else
00247         {               
00248                 // diagonal is negative
00249                 i = 0;
00250                 if (mMatrix[1][1] > mMatrix[0][0]) 
00251                         i = 1;
00252                 if (mMatrix[2][2] > mMatrix[i][i]) 
00253                         i = 2;
00254 
00255                 j = nxt[i];
00256                 k = nxt[j];
00257 
00258 
00259                 s = (F32)sqrt ((mMatrix[i][i] - (mMatrix[j][j] + mMatrix[k][k])) + 1.f);
00260 
00261                 q[i] = s * 0.5f;
00262 
00263                 if (s != 0.f) 
00264                         s = 0.5f / s;
00265 
00266                 q[3] = (mMatrix[j][k] - mMatrix[k][j]) * s;
00267                 q[j] = (mMatrix[i][j] + mMatrix[j][i]) * s;
00268                 q[k] = (mMatrix[i][k] + mMatrix[k][i]) * s;
00269 
00270                 quat.setQuat(q);
00271         }
00272         return quat;
00273 }
00274 
00275 
00276 // These functions take Rotation arguments
00277 const LLMatrix3&        LLMatrix3::setRot(const F32 angle, const F32 x, const F32 y, const F32 z)
00278 {
00279         setRot(LLQuaternion(angle,x,y,z));
00280         return *this;
00281 }
00282 
00283 const LLMatrix3&        LLMatrix3::setRot(const F32 angle, const LLVector3 &vec)
00284 {
00285         setRot(LLQuaternion(angle, vec));
00286         return *this;
00287 }
00288 
00289 const LLMatrix3&        LLMatrix3::setRot(const F32 roll, const F32 pitch, const F32 yaw)
00290 {
00291         // Rotates RH about x-axis by 'roll'  then
00292         // rotates RH about the old y-axis by 'pitch' then
00293         // rotates RH about the original z-axis by 'yaw'.
00294         //                .
00295         //               /|\ yaw axis
00296         //                |     __.
00297         //   ._        ___|      /| pitch axis
00298         //  _||\       \\ |-.   /
00299         //  \|| \_______\_|__\_/_______
00300         //   | _ _   o o o_o_o_o o   /_\_  ________\ roll axis
00301         //   //  /_______/    /__________>         /   
00302         //  /_,-'       //   /
00303         //             /__,-'
00304 
00305         F32             cx, sx, cy, sy, cz, sz;
00306         F32             cxsy, sxsy;
00307 
00308     cx = (F32)cos(roll); //A
00309     sx = (F32)sin(roll); //B
00310     cy = (F32)cos(pitch); //C
00311     sy = (F32)sin(pitch); //D
00312     cz = (F32)cos(yaw); //E
00313     sz = (F32)sin(yaw); //F
00314 
00315     cxsy = cx * sy; //AD
00316     sxsy = sx * sy; //BD 
00317 
00318     mMatrix[0][0] =  cy * cz;
00319     mMatrix[1][0] = -cy * sz;
00320     mMatrix[2][0] = sy;
00321     mMatrix[0][1] = sxsy * cz + cx * sz;
00322     mMatrix[1][1] = -sxsy * sz + cx * cz;
00323     mMatrix[2][1] = -sx * cy;
00324     mMatrix[0][2] =  -cxsy * cz + sx * sz;
00325     mMatrix[1][2] =  cxsy * sz + sx * cz;
00326     mMatrix[2][2] =  cx * cy;
00327         return *this;
00328 }
00329 
00330 
00331 const LLMatrix3&        LLMatrix3::setRot(const LLQuaternion &q)
00332 {
00333         *this = q.getMatrix3();
00334         return *this;
00335 }
00336 
00337 const LLMatrix3&        LLMatrix3::setRows(const LLVector3 &fwd, const LLVector3 &left, const LLVector3 &up)
00338 {
00339         mMatrix[0][0] = fwd.mV[0];
00340         mMatrix[0][1] = fwd.mV[1];
00341         mMatrix[0][2] = fwd.mV[2];
00342 
00343         mMatrix[1][0] = left.mV[0];
00344         mMatrix[1][1] = left.mV[1];
00345         mMatrix[1][2] = left.mV[2];
00346 
00347         mMatrix[2][0] = up.mV[0];
00348         mMatrix[2][1] = up.mV[1];
00349         mMatrix[2][2] = up.mV[2];
00350 
00351         return *this;
00352 }
00353 
00354                 
00355 // Rotate exisitng mMatrix
00356 const LLMatrix3&        LLMatrix3::rotate(const F32 angle, const F32 x, const F32 y, const F32 z)
00357 {
00358         LLMatrix3       mat(angle, x, y, z);
00359         *this *= mat;
00360         return *this;
00361 }
00362 
00363 
00364 const LLMatrix3&        LLMatrix3::rotate(const F32 angle, const LLVector3 &vec)
00365 {
00366         LLMatrix3       mat(angle, vec);
00367         *this *= mat;
00368         return *this;
00369 }
00370 
00371 
00372 const LLMatrix3&        LLMatrix3::rotate(const F32 roll, const F32 pitch, const F32 yaw)
00373 {
00374         LLMatrix3       mat(roll, pitch, yaw); 
00375         *this *= mat;
00376         return *this;
00377 }
00378 
00379 
00380 const LLMatrix3&        LLMatrix3::rotate(const LLQuaternion &q)
00381 {
00382         LLMatrix3       mat(q);
00383         *this *= mat;
00384         return *this;
00385 }
00386 
00387 
00388 LLVector3       LLMatrix3::getFwdRow() const
00389 {
00390         return LLVector3(mMatrix[VX]);
00391 }
00392 
00393 LLVector3       LLMatrix3::getLeftRow() const
00394 {
00395         return LLVector3(mMatrix[VY]);
00396 }
00397 
00398 LLVector3       LLMatrix3::getUpRow() const
00399 {
00400         return LLVector3(mMatrix[VZ]);
00401 }
00402 
00403 
00404 
00405 const LLMatrix3&        LLMatrix3::orthogonalize()
00406 {
00407         LLVector3 x_axis(mMatrix[VX]);
00408         LLVector3 y_axis(mMatrix[VY]);
00409         LLVector3 z_axis(mMatrix[VZ]);
00410 
00411         x_axis.normVec();
00412         y_axis -= x_axis * (x_axis * y_axis);
00413         y_axis.normVec();
00414         z_axis = x_axis % y_axis;
00415         setRows(x_axis, y_axis, z_axis);
00416         return (*this);
00417 }
00418 
00419 
00420 // LLMatrix3 Operators
00421 
00422 LLMatrix3 operator*(const LLMatrix3 &a, const LLMatrix3 &b)
00423 {
00424         U32             i, j;
00425         LLMatrix3       mat;
00426         for (i = 0; i < NUM_VALUES_IN_MAT3; i++)
00427         {
00428                 for (j = 0; j < NUM_VALUES_IN_MAT3; j++)
00429                 {
00430                         mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] + 
00431                                                             a.mMatrix[j][1] * b.mMatrix[1][i] + 
00432                                                             a.mMatrix[j][2] * b.mMatrix[2][i];
00433                 }
00434         }
00435         return mat;
00436 }
00437 
00438 /* Not implemented to help enforce code consistency with the syntax of 
00439    row-major notation.  This is a Good Thing.
00440 LLVector3 operator*(const LLMatrix3 &a, const LLVector3 &b)
00441 {
00442         LLVector3       vec;
00443         // matrix operates "from the left" on column vector
00444         vec.mV[VX] = a.mMatrix[VX][VX] * b.mV[VX] + 
00445                                  a.mMatrix[VX][VY] * b.mV[VY] + 
00446                                  a.mMatrix[VX][VZ] * b.mV[VZ];
00447         
00448         vec.mV[VY] = a.mMatrix[VY][VX] * b.mV[VX] + 
00449                                  a.mMatrix[VY][VY] * b.mV[VY] + 
00450                                  a.mMatrix[VY][VZ] * b.mV[VZ];
00451         
00452         vec.mV[VZ] = a.mMatrix[VZ][VX] * b.mV[VX] + 
00453                                  a.mMatrix[VZ][VY] * b.mV[VY] + 
00454                                  a.mMatrix[VZ][VZ] * b.mV[VZ];
00455         return vec;
00456 }
00457 */
00458 
00459 
00460 LLVector3 operator*(const LLVector3 &a, const LLMatrix3 &b)
00461 {
00462         // matrix operates "from the right" on row vector
00463         return LLVector3(
00464                                 a.mV[VX] * b.mMatrix[VX][VX] + 
00465                                 a.mV[VY] * b.mMatrix[VY][VX] + 
00466                                 a.mV[VZ] * b.mMatrix[VZ][VX],
00467         
00468                                 a.mV[VX] * b.mMatrix[VX][VY] + 
00469                                 a.mV[VY] * b.mMatrix[VY][VY] + 
00470                                 a.mV[VZ] * b.mMatrix[VZ][VY],
00471         
00472                                 a.mV[VX] * b.mMatrix[VX][VZ] + 
00473                                 a.mV[VY] * b.mMatrix[VY][VZ] + 
00474                                 a.mV[VZ] * b.mMatrix[VZ][VZ] );
00475 }
00476 
00477 LLVector3d operator*(const LLVector3d &a, const LLMatrix3 &b)
00478 {
00479         // matrix operates "from the right" on row vector
00480         return LLVector3d(
00481                                 a.mdV[VX] * b.mMatrix[VX][VX] + 
00482                                 a.mdV[VY] * b.mMatrix[VY][VX] + 
00483                                 a.mdV[VZ] * b.mMatrix[VZ][VX],
00484         
00485                                 a.mdV[VX] * b.mMatrix[VX][VY] + 
00486                                 a.mdV[VY] * b.mMatrix[VY][VY] + 
00487                                 a.mdV[VZ] * b.mMatrix[VZ][VY],
00488         
00489                                 a.mdV[VX] * b.mMatrix[VX][VZ] + 
00490                                 a.mdV[VY] * b.mMatrix[VY][VZ] + 
00491                                 a.mdV[VZ] * b.mMatrix[VZ][VZ] );
00492 }
00493 
00494 bool operator==(const LLMatrix3 &a, const LLMatrix3 &b)
00495 {
00496         U32             i, j;
00497         for (i = 0; i < NUM_VALUES_IN_MAT3; i++)
00498         {
00499                 for (j = 0; j < NUM_VALUES_IN_MAT3; j++)
00500                 {
00501                         if (a.mMatrix[j][i] != b.mMatrix[j][i])
00502                                 return FALSE;
00503                 }
00504         }
00505         return TRUE;
00506 }
00507 
00508 bool operator!=(const LLMatrix3 &a, const LLMatrix3 &b)
00509 {
00510         U32             i, j;
00511         for (i = 0; i < NUM_VALUES_IN_MAT3; i++)
00512         {
00513                 for (j = 0; j < NUM_VALUES_IN_MAT3; j++)
00514                 {
00515                         if (a.mMatrix[j][i] != b.mMatrix[j][i])
00516                                 return TRUE;
00517                 }
00518         }
00519         return FALSE;
00520 }
00521 
00522 const LLMatrix3& operator*=(LLMatrix3 &a, const LLMatrix3 &b)
00523 {
00524         U32             i, j;
00525         LLMatrix3       mat;
00526         for (i = 0; i < NUM_VALUES_IN_MAT3; i++)
00527         {
00528                 for (j = 0; j < NUM_VALUES_IN_MAT3; j++)
00529                 {
00530                         mat.mMatrix[j][i] = a.mMatrix[j][0] * b.mMatrix[0][i] + 
00531                                                             a.mMatrix[j][1] * b.mMatrix[1][i] + 
00532                                                             a.mMatrix[j][2] * b.mMatrix[2][i];
00533                 }
00534         }
00535         a = mat;
00536         return a;
00537 }
00538 
00539 std::ostream& operator<<(std::ostream& s, const LLMatrix3 &a) 
00540 {
00541         s << "{ " 
00542                 << a.mMatrix[VX][VX] << ", " << a.mMatrix[VX][VY] << ", " << a.mMatrix[VX][VZ] << "; "
00543                 << a.mMatrix[VY][VX] << ", " << a.mMatrix[VY][VY] << ", " << a.mMatrix[VY][VZ] << "; "
00544                 << a.mMatrix[VZ][VX] << ", " << a.mMatrix[VZ][VY] << ", " << a.mMatrix[VZ][VZ] 
00545           << " }";
00546         return s;
00547 }
00548 

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