Main Page   Modules   Class Hierarchy   Compound List   File List   Compound Members   File Members   Related Pages   Examples  

math/umatrix.cpp

Go to the documentation of this file.
00001 #include "umatrix.h"
00002 
00007 #include <iostream>
00008 using namespace std;
00009 
00010 #include <glt/gl.h>
00011 
00012 #include <math/matrix4.h>
00013 
00014 //
00015 // From Graphics Gems II - Decomposing a matrix into simple transformations. Pg. 320
00016 //
00017 
00018 // unmatrix.c - given a 4x4 matrix, decompose it into standard operations.
00019 //
00020 // Author:  Spencer W. Thomas
00021 //          University of Michigan
00022 //
00023 
00024 // unmatrix - Decompose a non-degenerate 4x4 transformation matrix into
00025 // the sequence of transformations that produced it.
00026 // [Sx][Sy][Sz][Shearx/y][Sx/z][Sz/y][Rx][Ry][Rz][Tx][Ty][Tz][P(x,y,z,w)]
00027 //
00028 // The coefficient of each transformation is returned in the corresponding
00029 // element of the vector tran.
00030 //
00031 // Returns true upon success, false if the matrix is singular.
00032 //
00033 
00034 UnMatrix::UnMatrix()
00035 {
00036     memset(_tran,0,sizeof(_tran));
00037 }
00038 
00039 UnMatrix::UnMatrix(const UnMatrix &umatrix)
00040 {
00041     memcpy(_tran,umatrix._tran,sizeof(_tran));
00042 }
00043 
00044 UnMatrix::UnMatrix(const Matrix &matrix)
00045 {
00046     UnMatrix umatrix = matrix.unmatrix();
00047     memcpy(_tran,umatrix._tran,sizeof(_tran));
00048 }
00049 
00050 UnMatrix::~UnMatrix()
00051 {
00052 }
00053 
00054 static char *UnMatrixFieldDescription[] =
00055 {
00056     "U_SCALEX",
00057     "U_SCALEY",
00058     "U_SCALEZ",
00059     "U_SHEARXY",
00060     "U_SHEARXZ",
00061     "U_SHEARYZ",
00062     "U_ROTATEX",
00063     "U_ROTATEY",
00064     "U_ROTATEZ",
00065     "U_TRANSX",
00066     "U_TRANSY",
00067     "U_TRANSZ",
00068     "U_PERSPX",
00069     "U_PERSPY",
00070     "U_PERSPZ",
00071     "U_PERSPW"
00072 };
00073 
00079 UnMatrix 
00080 operator-(const UnMatrix &b,const UnMatrix &a)
00081 {
00082     UnMatrix um;
00083 
00084     um[U_SCALEX]  = b._tran[U_SCALEX] - a._tran[U_SCALEX];
00085     um[U_SCALEY]  = b._tran[U_SCALEY] - a._tran[U_SCALEY];
00086     um[U_SCALEZ]  = b._tran[U_SCALEZ] - a._tran[U_SCALEZ];
00087 
00088     um[U_ROTATEX] = b._tran[U_ROTATEX] - a._tran[U_ROTATEX];
00089     um[U_ROTATEY] = b._tran[U_ROTATEY] - a._tran[U_ROTATEY];
00090     um[U_ROTATEZ] = b._tran[U_ROTATEZ] - a._tran[U_ROTATEZ];
00091 
00092     um[U_TRANSX]  = b._tran[U_TRANSX] - a._tran[U_TRANSX];
00093     um[U_TRANSY]  = b._tran[U_TRANSY] - a._tran[U_TRANSY];
00094     um[U_TRANSZ]  = b._tran[U_TRANSZ] - a._tran[U_TRANSZ];
00095 
00096     return um;
00097 }
00098 
00104 UnMatrix 
00105 operator*(const UnMatrix &a,const double scaleFactor)
00106 {
00107     UnMatrix um = a;
00108 
00109     um[U_SCALEX]  *= scaleFactor;
00110     um[U_SCALEY]  *= scaleFactor;
00111     um[U_SCALEZ]  *= scaleFactor;
00112 
00113     um[U_ROTATEX] *= scaleFactor;
00114     um[U_ROTATEY] *= scaleFactor;
00115     um[U_ROTATEZ] *= scaleFactor;
00116 
00117     um[U_TRANSX]  *= scaleFactor;
00118     um[U_TRANSY]  *= scaleFactor;
00119     um[U_TRANSZ]  *= scaleFactor;
00120 
00121     return um;
00122 }
00123 
00129 UnMatrix 
00130 operator+(const UnMatrix &a,const UnMatrix &b)
00131 {
00132     UnMatrix um;
00133 
00134     um[U_SCALEX]  = b._tran[U_SCALEX] + a._tran[U_SCALEX];
00135     um[U_SCALEY]  = b._tran[U_SCALEY] + a._tran[U_SCALEY];
00136     um[U_SCALEZ]  = b._tran[U_SCALEZ] + a._tran[U_SCALEZ];
00137 
00138     um[U_ROTATEX] = b._tran[U_ROTATEX] + a._tran[U_ROTATEX];
00139     um[U_ROTATEY] = b._tran[U_ROTATEY] + a._tran[U_ROTATEY];
00140     um[U_ROTATEZ] = b._tran[U_ROTATEZ] + a._tran[U_ROTATEZ];
00141 
00142     um[U_TRANSX]  = b._tran[U_TRANSX] + a._tran[U_TRANSX];
00143     um[U_TRANSY]  = b._tran[U_TRANSY] + a._tran[U_TRANSY];
00144     um[U_TRANSZ]  = b._tran[U_TRANSZ] + a._tran[U_TRANSZ];
00145 
00146     return um;
00147 }
00148 
00149 
00155 std::ostream &
00156 operator<<(std::ostream &os,const UnMatrixField &field)
00157 {
00158     if (field>=U_SCALEX && field<=U_PERSPW)
00159         os << UnMatrixFieldDescription[field];
00160     else
00161         os << "Unknown";
00162 
00163     return os;
00164 }
00165 
00171 istream &
00172 operator>>(istream &is,UnMatrixField &field)
00173 {
00174     char buffer[128];
00175 
00176     is >> buffer;
00177 
00178     for (int f=0;f<16;f++)
00179         if (!strcmp(buffer,UnMatrixFieldDescription[f]))
00180         {
00181             field = (UnMatrixField) f;
00182             break;
00183         }
00184 
00185     return is;
00186 }
00187 
00193 std::ostream &
00194 operator<<(std::ostream &os,const UnMatrix &unMatrix)
00195 {
00196     for (int f=0;f<16;f++)
00197         os << (UnMatrixField) f << ' ' << unMatrix._tran[f] << endl;
00198 
00199     return os;
00200 }
00201 
00207 istream &
00208 operator>>(istream &is,UnMatrix &unMatrix)
00209 {
00210     for (int f=0;f<16;f++)
00211     {
00212         UnMatrixField field;
00213         double value;
00214 
00215         is >> field;
00216         is >> value;
00217 
00218         if (!is.eof()) unMatrix[field] = value;
00219     }
00220 
00221     return is;
00222 }
00223 
00224 typedef struct {
00225     double x,y,z,w;
00226 } Vector4;
00227 
00228 UnMatrix
00229 Matrix::unmatrix() const
00230 {
00231     UnMatrix tran;
00232 
00233     Matrix locmat = (*this);
00234 
00235     if (locmat.element(3,3)==0.0)
00236         return tran;
00237 
00238     register int i, j;
00239 
00240     for ( i=0; i<4;i++ )
00241         for ( j=0; j<4; j++ )
00242             locmat.element(i,j) /= locmat.element(3,3);
00243 
00244     /* pmat is used to solve for perspective, but it also provides
00245      * an easy way to test for singularity of the upper 3x3 component.
00246      */
00247 
00248     Matrix pmat = locmat;
00249 
00250     for ( i=0; i<3; i++ )
00251         pmat.set(i,3,0.0);
00252 
00253     pmat.set(3,3,1.0);
00254 
00255     if ( pmat.det() == 0.0 )
00256         return tran;
00257 
00258     /* First, isolate perspective.  This is the messiest. */
00259 
00260     if 
00261     ( 
00262         locmat.element(0,3) != 0.0 || 
00263         locmat.element(1,3) != 0.0 ||
00264         locmat.element(2,3) != 0.0 
00265     ) 
00266     {
00267         Vector4 prhs, psol;
00268 
00269         /* prhs is the right hand side of the equation. */
00270  
00271         prhs.x = locmat.element(0,3);
00272         prhs.y = locmat.element(1,3);
00273         prhs.z = locmat.element(2,3);
00274         prhs.w = locmat.element(3,3);
00275 
00276         /* Solve the equation by inverting pmat and multiplying
00277          * prhs by the inverse.  (This is the easiest way, not
00278          * necessarily the best.)
00279          * inverse function (and det4x4, above) from the Matrix
00280          * Inversion gem in the first volume.
00281          */
00282 
00283 //      Matrix invpmat = pmat.inverse();
00284 //      Matrix tinvpmat = invpmat.transpose();
00285 //      V4MulPointByMatrix(&prhs, &tinvpmat, &psol);    // REVISIT
00286  
00287         psol.x = 0.0;
00288         psol.y = 0.0;
00289         psol.z = 0.0;
00290         psol.w = 0.0;
00291 
00292         /* Stuff the answer away. */
00293         tran[U_PERSPX] = psol.x;
00294         tran[U_PERSPY] = psol.y;
00295         tran[U_PERSPZ] = psol.z;
00296         tran[U_PERSPW] = psol.w;
00297 
00298         /* Clear the perspective partition. */
00299         locmat.element(0,3) = locmat.element(1,3) = locmat.element(2,3) = 0.0;
00300         locmat.element(3,3) = 1.0;
00301 
00302     } else      /* No perspective. */
00303         tran[U_PERSPX] = tran[U_PERSPY] = tran[U_PERSPZ] = tran[U_PERSPW] = 0;
00304 
00305     /* Next take care of translation (easy). */
00306     for ( i=0; i<3; i++ ) 
00307     {
00308         tran[(UnMatrixField) (U_TRANSX + i)] = locmat.element(3,i);
00309         locmat.set(3,i,0.0);
00310     }
00311 
00312     Vector  row[3];
00313 
00314     /* Now get scale and shear. */
00315     for ( i=0; i<3; i++ ) 
00316     {
00317         row[i][0] = locmat.get(i,0);
00318         row[i][1] = locmat.get(i,1);
00319         row[i][2] = locmat.get(i,2);
00320     }
00321 
00322     /* Compute X scale factor and normalize first row. */
00323 
00324     tran[U_SCALEX] = sqrt(row[0].norm());
00325     row[0].normalize();
00326 
00327     /* Compute XY shear factor and make 2nd row orthogonal to 1st. */
00328     tran[U_SHEARXY] = row[0] * row[1];
00329     row[1] = row[1] - row[0] * tran[U_SHEARXY];
00330 
00331     /* Now, compute Y scale and normalize 2nd row. */
00332     tran[U_SCALEY] = sqrt(row[1].norm());
00333     row[1].normalize();
00334     tran[U_SHEARXY] /= tran[U_SCALEY];
00335 
00336     /* Compute XZ and YZ shears, orthogonalize 3rd row. */
00337     tran[U_SHEARXZ] = row[0] * row[2];
00338     row[2] = row[2] - row[0] * tran[U_SHEARXZ];
00339 
00340     tran[U_SHEARYZ] = row[1] * row[2];
00341     row[2] = row[2] - row[1] * tran[U_SHEARYZ];
00342 
00343     /* Next, get Z scale and normalize 3rd row. */
00344     tran[U_SCALEZ] = sqrt(row[2].norm());
00345     row[2].normalize();
00346 
00347     tran[U_SHEARXZ] /= tran[U_SCALEZ];
00348     tran[U_SHEARYZ] /= tran[U_SCALEZ];
00349  
00350     /* At this point, the matrix (in rows[]) is orthonormal.
00351      * Check for a coordinate system flip.  If the determinant
00352      * is -1, then negate the matrix and the scaling factors.
00353      */
00354     if ( row[0] * xProduct(row[1],row[2]) < 0.0 )
00355         for ( i = 0; i < 3; i++ ) 
00356         {
00357             tran[(UnMatrixField) (U_SCALEX+i)] *= -1;
00358             row[i] = row[i] * -1.0;
00359         }
00360  
00361     /* Now, get the rotations out, as described in the gem. */
00362     tran[U_ROTATEY] = asin(-row[0][2]);
00363 
00364     if ( cos(tran[U_ROTATEY]) != 0 ) 
00365     {
00366         tran[U_ROTATEX] = atan2(row[1][2], row[2][2]);
00367         tran[U_ROTATEZ] = atan2(row[0][1], row[0][0]);
00368     } 
00369     else 
00370     {
00371         tran[U_ROTATEX] = atan2(row[1][0], row[1][1]);
00372         tran[U_ROTATEZ] = 0;
00373     }
00374 
00375     return tran;
00376 }
00377 
00378 //
00379 // From Graphics Gems GEMSI\MATINV.C
00380 //
00381 
00382 //
00383 // Calculate the determinant of a 4x4 matrix.
00384 //
00385 
00386 double
00387 Matrix::det() const
00388 {
00389     double ans;
00390     double a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4;
00391 
00392     /* assign to individual variable names to aid selecting */
00393     /*  correct elements */
00394 
00395     a1 = get(0,0); b1 = get(0,1); 
00396     c1 = get(0,2); d1 = get(0,3);
00397 
00398     a2 = get(1,0); b2 = get(1,1); 
00399     c2 = get(1,2); d2 = get(1,3);
00400 
00401     a3 = get(2,0); b3 = get(2,1); 
00402     c3 = get(2,2); d3 = get(2,3);
00403 
00404     a4 = get(3,0); b4 = get(3,1); 
00405     c4 = get(3,2); d4 = get(3,3);
00406 
00407     ans = a1 * det3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4)
00408         - b1 * det3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4)
00409         + c1 * det3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4)
00410         - d1 * det3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4);
00411     return ans;
00412 }
00413 
00414 // 
00415 // Calculate the determinant of a 3x3 matrix
00416 // in the form
00417 //
00418 //     | a1,  b1,  c1 |
00419 //     | a2,  b2,  c2 |
00420 //     | a3,  b3,  c3 |
00421 //
00422 
00423 double 
00424 Matrix::det3x3
00425 ( 
00426     const double a1, 
00427     const double a2, 
00428     const double a3, 
00429     const double b1, 
00430     const double b2, 
00431     const double b3, 
00432     const double c1, 
00433     const double c2, 
00434     const double c3 
00435 ) const
00436 {
00437     return 
00438         a1 * det2x2( b2, b3, c2, c3 )
00439         - b1 * det2x2( a2, a3, c2, c3 )
00440         + c1 * det2x2( a2, a3, b2, b3 );
00441 }
00442 
00443 // Calculate the determinant of a 2x2 matrix.
00444 
00445 double
00446 Matrix::det2x2
00447 ( 
00448     const double a, 
00449     const double b, 
00450     const double c, 
00451     const double d
00452 ) const
00453 {
00454     return a * d - b * c;
00455 }
00456 
00457 
00458 bool 
00459 UnMatrix::uniformScale(const double tol) const
00460 {
00461     if (fabs(_tran[U_SCALEX]-_tran[U_SCALEY])>tol) return false;
00462     if (fabs(_tran[U_SCALEX]-_tran[U_SCALEZ])>tol) return false;
00463     if (fabs(_tran[U_SCALEY]-_tran[U_SCALEZ])>tol) return false;
00464     return true;
00465 }
00466 
00467 bool 
00468 UnMatrix::noRotation(const double tol) const
00469 {
00470     if (fabs(_tran[U_ROTATEX])>tol) return false;
00471     if (fabs(_tran[U_ROTATEY])>tol) return false;
00472     if (fabs(_tran[U_ROTATEZ])>tol) return false;
00473     return true;
00474 }
00475 
00476 bool 
00477 UnMatrix::noShear(const double tol) const
00478 {
00479     if (fabs(_tran[U_SHEARXY])>tol) return false;
00480     if (fabs(_tran[U_SHEARXZ])>tol) return false;
00481     if (fabs(_tran[U_SHEARYZ])>tol) return false;
00482     return true;
00483 }
00484 
00485 bool 
00486 UnMatrix::noPerspective(const double tol) const
00487 {
00488     if (fabs(_tran[U_PERSPX])>tol) return false;
00489     if (fabs(_tran[U_PERSPY])>tol) return false;
00490     if (fabs(_tran[U_PERSPZ])>tol) return false;
00491     if (fabs(_tran[U_PERSPW])>tol) return false;
00492     return true;
00493 }
00494 

Generated on Tue Nov 5 11:11:04 2002 for GLT by doxygen1.2.18