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

math/matrix4.cpp

Go to the documentation of this file.
00001 #include "matrix4.h"
00002 
00007 #include <cmath>
00008 #include <cassert>
00009 #include <string>
00010 #include <iostream>
00011 #include <iomanip>
00012 using namespace std;
00013 
00014 #include <glt/gl.h>
00015 
00016 #include <misc/string.h>
00017 #include <math/umatrix.h>
00018 
00019 double Matrix::_identity[16] = 
00020 {
00021    1.0, 0.0, 0.0, 0.0,
00022    0.0, 1.0, 0.0, 0.0,
00023    0.0, 0.0, 1.0, 0.0,
00024    0.0, 0.0, 0.0, 1.0
00025 };
00026 
00027 Matrix::Matrix()
00028 {
00029     reset();
00030 }
00031 
00032 Matrix::Matrix(const Matrix &matrix)
00033 {
00034     (*this) = matrix;
00035 }
00036 
00037 Matrix::Matrix(const float *matrix)
00038 {
00039           real  *i = _matrix;
00040     const float *j =  matrix;
00041     for (int k=0; k<16; i++,j++,k++)
00042         *i = *j;
00043 }
00044 
00045 Matrix::Matrix(const double *matrix)
00046 {
00047           real   *i = _matrix;
00048     const double *j =  matrix;
00049     for (int k=0; k<16; i++,j++,k++)
00050         *i = *j;
00051 }
00052 
00053 Matrix::Matrix(const unsigned int glMatrix)
00054 {
00055     switch (glMatrix)
00056     {
00057     case GL_MODELVIEW_MATRIX:
00058         glGetDoublev(GL_MODELVIEW_MATRIX,_matrix);
00059         break;
00060     case GL_PROJECTION_MATRIX:
00061         glGetDoublev(GL_PROJECTION_MATRIX,_matrix);
00062         break;
00063     default:
00064         break;
00065     }
00066 }
00067 
00068 Matrix::Matrix(const string &str)
00069 {
00070     #ifndef NDEBUG
00071     const int n = 
00072     #endif
00073         atoc(str,atof,"+-eE.0123456789",_matrix+0,_matrix+16);
00074         
00075     assert(n==16);
00076 }
00077 
00078 Matrix &
00079 Matrix::operator=(const Matrix &m)
00080 {
00081     memcpy(_matrix,m._matrix,sizeof(_matrix));
00082 
00083     return *this;
00084 }
00085 
00086 Matrix 
00087 Matrix::operator *(const Matrix &m) const
00088 {
00089     Matrix prod;
00090 
00091     for (int c=0;c<4;c++)
00092         for (int r=0;r<4;r++)
00093             prod.set(c,r,
00094                 get(c,0)*m.get(0,r) +
00095                 get(c,1)*m.get(1,r) +
00096                 get(c,2)*m.get(2,r) +
00097                 get(c,3)*m.get(3,r));
00098 
00099     return prod;
00100 }
00101 
00102 Matrix &
00103 Matrix::operator*=(const Matrix &m)
00104 {
00105     // Potential optimisation here to
00106     // skip a temporary copy
00107 
00108     return (*this) = (*this)*m;
00109 }
00110 
00111 Vector    
00112 Matrix::operator*(const Vector &v) const
00113 {
00114     double prod[4] = { 0,0,0,0 };
00115 
00116     for (int r=0;r<4;r++)
00117     {
00118         for (int c=0;c<3;c++)
00119             prod[r] += v[c]*get(c,r);
00120 
00121         prod[r] += get(3,r);
00122     }
00123 
00124     double div = 1.0 / prod[3];
00125 
00126     return Vector(prod[0]*div,prod[1]*div,prod[2]*div);
00127 }
00128 
00129 void 
00130 Matrix::reset()
00131 {
00132     memcpy(_matrix,_identity,16*sizeof(double));
00133 }
00134 
00135 void 
00136 Matrix::identity()
00137 {
00138     reset();
00139 }
00140 
00141 bool 
00142 Matrix::isIdentity() const
00143 {
00144     return !memcmp(_matrix,_identity,sizeof(_matrix));
00145 }
00146 
00147 const double & 
00148 Matrix::operator[](const int i) const
00149 {
00150     assert(i>=0 && i<16);
00151     return _matrix[i];
00152 }
00153 
00154 double & 
00155 Matrix::operator[](const int i)
00156 {
00157     assert(i>=0 && i<16);
00158     return _matrix[i];
00159 }
00160 
00161 bool 
00162 Matrix::operator==(const Matrix &m) const
00163 {
00164     return !memcmp(_matrix,m._matrix,sizeof(_matrix));
00165 }
00166 
00167 bool 
00168 Matrix::operator!=(const Matrix &m) const
00169 {
00170     return memcmp(_matrix,m._matrix,sizeof(_matrix))!=0;
00171 }
00172 
00173 Matrix::operator double *()
00174 {
00175     return _matrix;
00176 }
00177 
00178 Matrix::operator const double *() const
00179 {
00180     return _matrix;
00181 }
00182 
00183 void
00184 Matrix::glMultMatrix() const
00185 {
00186     glMultMatrixd(_matrix);
00187 }
00188 
00189 void 
00190 Matrix::glLoadMatrix() const
00191 {
00192     glLoadMatrixd(_matrix);
00193 }
00194 
00195 
00196 #if 0
00197 double const *
00198 Matrix::row(const unsigned int row) const
00199 {
00200     static double r[4];
00201 
00202     for (int c=0;c<4;c++)
00203         r[c] = _matrix[c*4+row];
00204     
00205     return r;
00206 }
00207 
00208 double const *
00209 Matrix::column(const unsigned int column) const
00210 {
00211     return _matrix+column*4;
00212 }
00213 
00214 #endif
00215 
00216 ostream &
00217 Matrix::writePov(ostream &os) const
00218 {
00219     UnMatrix um = unmatrix();
00220 
00221     os << "scale < ";
00222       os << um[U_SCALEX] << ',';
00223       os << um[U_SCALEY] << ',';
00224       os << um[U_SCALEZ] << " > ";
00225 
00226     os << "rotate < ";
00227       os << um[U_ROTATEX]/M_PI_DEG << ',';
00228       os << um[U_ROTATEY]/M_PI_DEG << ',';
00229       os << um[U_ROTATEZ]/M_PI_DEG << " > ";
00230 
00231     os << "translate < ";
00232       os << um[U_TRANSX] << ',';
00233       os << um[U_TRANSY] << ',';
00234       os << um[U_TRANSZ] << " > ";
00235 
00236     return os;
00237 }
00238 
00244 Matrix matrixScale(const double sf)
00245 {
00246     Matrix scale;
00247 
00248     scale.set(0,0,sf);
00249     scale.set(1,1,sf);
00250     scale.set(2,2,sf);
00251     
00252     return scale;
00253 }
00254 
00260 Matrix matrixScale(const Vector sf)
00261 {
00262     Matrix scale;
00263 
00264     scale.set(0,0,sf[0]);
00265     scale.set(1,1,sf[1]);
00266     scale.set(2,2,sf[2]);
00267     
00268     return scale;
00269 }
00270 
00276 Matrix matrixTranslate(const Vector trans)
00277 {
00278     Matrix translate;
00279 
00280     translate.set(3,0,trans[0]);
00281     translate.set(3,1,trans[1]);
00282     translate.set(3,2,trans[2]);
00283 
00284     return translate;
00285 }
00286 
00292 Matrix matrixTranslate(const real x,const real y,const real z)
00293 {
00294     Matrix translate;
00295 
00296     translate.set(3,0,x);
00297     translate.set(3,1,y);
00298     translate.set(3,2,z);
00299 
00300     return translate;
00301 }
00302 
00310 Matrix matrixRotate(const Vector axis, const double angle)
00311 {
00312     Matrix rotate;
00313 
00314     // Page 466, Graphics Gems
00315 
00316     double s = sin(angle*M_PI_DEG);
00317     double c = cos(angle*M_PI_DEG);
00318     double t = 1 - c;
00319 
00320     Vector ax = axis/sqrt(axis.norm());
00321 
00322     double x = ax[0];
00323     double y = ax[1];
00324     double z = ax[2];
00325 
00326     rotate.set(0,0,t*x*x+c);
00327     rotate.set(1,0,t*y*x+s*z);
00328     rotate.set(2,0,t*z*x-s*y);
00329 
00330     rotate.set(0,1,t*x*y-s*z);
00331     rotate.set(1,1,t*y*y+c);
00332     rotate.set(2,1,t*z*y+s*x);
00333 
00334     rotate.set(0,2,t*x*z+s*y);
00335     rotate.set(1,2,t*y*z-s*x);
00336     rotate.set(2,2,t*z*z+c);
00337 
00338     return rotate;
00339 }
00340 
00348 Matrix matrixRotate(const double azimuth, const double elevation)
00349 {
00350     Matrix rotate;
00351 
00352     double ca = cos(azimuth*M_PI_DEG);
00353     double sa = sin(azimuth*M_PI_DEG);
00354     double cb = cos(elevation*M_PI_DEG);
00355     double sb = sin(elevation*M_PI_DEG);
00356 
00357     rotate.set(0,0,cb);
00358     rotate.set(1,0,0);
00359     rotate.set(2,0,-sb);
00360 
00361     rotate.set(0,1,-sa*sb);
00362     rotate.set(1,1,ca);
00363     rotate.set(2,1,-sa*cb);
00364 
00365     rotate.set(0,2,ca*sb);
00366     rotate.set(1,2,sa);
00367     rotate.set(2,2,ca*cb);
00368 
00369     return rotate;
00370 }
00371 
00380 Matrix matrixOrient(const Vector &x,const Vector &y,const Vector &z)
00381 {
00382     Matrix orient;
00383 
00384     orient.set(0,0,x.x());
00385     orient.set(0,1,x.y());
00386     orient.set(0,2,x.z());
00387 
00388     orient.set(1,0,y.x());
00389     orient.set(1,1,y.y());
00390     orient.set(1,2,y.z());
00391 
00392     orient.set(2,0,z.x());
00393     orient.set(2,1,z.y());
00394     orient.set(2,2,z.z());
00395 
00396     return orient;
00397 }
00398 
00406 Matrix matrixOrient(const Vector &direction,const Vector &up)
00407 {
00408     assert(direction.norm()>0.0);
00409     assert(up.norm()>0.0);
00410 
00411     Vector d(direction);
00412     d.normalize();
00413 
00414     Vector u(up);
00415     u.normalize();
00416 
00417     return matrixOrient(xProduct(u,d),u,d);
00418 }
00419 
00425 std::ostream &
00426 operator<<(std::ostream &os,const Matrix &m)
00427 {
00428     for (int r=0;r<4;r++)
00429         for (int c=0;c<4;c++)
00430             os << setw(10) << setfill(' ') << m.get(c,r) << ( c==3 ? '\n' : '\t');
00431 
00432     return os;
00433 }
00434 
00440 std::istream &
00441 operator>>(std::istream &is,Matrix &m)
00442 {
00443     for (int r=0;r<4;r++)
00444         for (int c=0;c<4;c++)
00445         {
00446             double tmp;
00447             is >> tmp;
00448             m.set(c,r,tmp);
00449         }
00450 
00451     return is;
00452 }
00453 
00454 Matrix 
00455 Matrix::inverse() const
00456 {
00457     Matrix inv;
00458     invertMatrix(_matrix,inv._matrix);
00459     return inv;
00460 }
00461 
00462 Matrix 
00463 Matrix::transpose() const
00464 {
00465     Matrix tmp;
00466     
00467     for (int i=0;i<4;i++)
00468         for (int j=0;j<4;j++)
00469             tmp.set(j,i,get(i,j));
00470     
00471     return tmp;
00472 }
00473 
00474 //
00475 // From Mesa-2.2\src\glu\project.c
00476 //
00477 
00478 //
00479 // Compute the inverse of a 4x4 matrix.  Contributed by scotter@lafn.org
00480 //
00481 
00482 void 
00483 Matrix::invertMatrixGeneral( const double *m, double *out )
00484 {
00485 
00486 /* NB. OpenGL Matrices are COLUMN major. */
00487 #define MAT(m,r,c) (m)[(c)*4+(r)]
00488 
00489 /* Here's some shorthand converting standard (row,column) to index. */
00490 #define m11 MAT(m,0,0)
00491 #define m12 MAT(m,0,1)
00492 #define m13 MAT(m,0,2)
00493 #define m14 MAT(m,0,3)
00494 #define m21 MAT(m,1,0)
00495 #define m22 MAT(m,1,1)
00496 #define m23 MAT(m,1,2)
00497 #define m24 MAT(m,1,3)
00498 #define m31 MAT(m,2,0)
00499 #define m32 MAT(m,2,1)
00500 #define m33 MAT(m,2,2)
00501 #define m34 MAT(m,2,3)
00502 #define m41 MAT(m,3,0)
00503 #define m42 MAT(m,3,1)
00504 #define m43 MAT(m,3,2)
00505 #define m44 MAT(m,3,3)
00506 
00507    double det;
00508    double d12, d13, d23, d24, d34, d41;
00509    double tmp[16]; /* Allow out == in. */
00510 
00511    /* Inverse = adjoint / det. (See linear algebra texts.)*/
00512 
00513    /* pre-compute 2x2 dets for last two rows when computing */
00514    /* cofactors of first two rows. */
00515    d12 = (m31*m42-m41*m32);
00516    d13 = (m31*m43-m41*m33);
00517    d23 = (m32*m43-m42*m33);
00518    d24 = (m32*m44-m42*m34);
00519    d34 = (m33*m44-m43*m34);
00520    d41 = (m34*m41-m44*m31);
00521 
00522    tmp[0] =  (m22 * d34 - m23 * d24 + m24 * d23);
00523    tmp[1] = -(m21 * d34 + m23 * d41 + m24 * d13);
00524    tmp[2] =  (m21 * d24 + m22 * d41 + m24 * d12);
00525    tmp[3] = -(m21 * d23 - m22 * d13 + m23 * d12);
00526 
00527    /* Compute determinant as early as possible using these cofactors. */
00528    det = m11 * tmp[0] + m12 * tmp[1] + m13 * tmp[2] + m14 * tmp[3];
00529 
00530    /* Run singularity test. */
00531    if (det == 0.0) {
00532       /* printf("invert_matrix: Warning: Singular matrix.\n"); */
00533       memcpy(out,_identity,16*sizeof(double));
00534    }
00535    else {
00536       double invDet = 1.0 / det;
00537       /* Compute rest of inverse. */
00538       tmp[0] *= invDet;
00539       tmp[1] *= invDet;
00540       tmp[2] *= invDet;
00541       tmp[3] *= invDet;
00542 
00543       tmp[4] = -(m12 * d34 - m13 * d24 + m14 * d23) * invDet;
00544       tmp[5] =  (m11 * d34 + m13 * d41 + m14 * d13) * invDet;
00545       tmp[6] = -(m11 * d24 + m12 * d41 + m14 * d12) * invDet;
00546       tmp[7] =  (m11 * d23 - m12 * d13 + m13 * d12) * invDet;
00547 
00548       /* Pre-compute 2x2 dets for first two rows when computing */
00549       /* cofactors of last two rows. */
00550       d12 = m11*m22-m21*m12;
00551       d13 = m11*m23-m21*m13;
00552       d23 = m12*m23-m22*m13;
00553       d24 = m12*m24-m22*m14;
00554       d34 = m13*m24-m23*m14;
00555       d41 = m14*m21-m24*m11;
00556 
00557       tmp[8] =  (m42 * d34 - m43 * d24 + m44 * d23) * invDet;
00558       tmp[9] = -(m41 * d34 + m43 * d41 + m44 * d13) * invDet;
00559       tmp[10] =  (m41 * d24 + m42 * d41 + m44 * d12) * invDet;
00560       tmp[11] = -(m41 * d23 - m42 * d13 + m43 * d12) * invDet;
00561       tmp[12] = -(m32 * d34 - m33 * d24 + m34 * d23) * invDet;
00562       tmp[13] =  (m31 * d34 + m33 * d41 + m34 * d13) * invDet;
00563       tmp[14] = -(m31 * d24 + m32 * d41 + m34 * d12) * invDet;
00564       tmp[15] =  (m31 * d23 - m32 * d13 + m33 * d12) * invDet;
00565 
00566       memcpy(out, tmp, 16*sizeof(double));
00567    }
00568 
00569 #undef m11
00570 #undef m12
00571 #undef m13
00572 #undef m14
00573 #undef m21
00574 #undef m22
00575 #undef m23
00576 #undef m24
00577 #undef m31
00578 #undef m32
00579 #undef m33
00580 #undef m34
00581 #undef m41
00582 #undef m42
00583 #undef m43
00584 #undef m44
00585 #undef MAT
00586 }
00587 
00588 
00589 //
00590 // Invert matrix m.  This algorithm contributed by Stephane Rehel
00591 // <rehel@worldnet.fr>
00592 //
00593 
00594 void 
00595 Matrix::invertMatrix( const double *m, double *out )
00596 {
00597 /* NB. OpenGL Matrices are COLUMN major. */
00598 #define MAT(m,r,c) (m)[(c)*4+(r)]
00599 
00600 /* Here's some shorthand converting standard (row,column) to index. */
00601 #define m11 MAT(m,0,0)
00602 #define m12 MAT(m,0,1)
00603 #define m13 MAT(m,0,2)
00604 #define m14 MAT(m,0,3)
00605 #define m21 MAT(m,1,0)
00606 #define m22 MAT(m,1,1)
00607 #define m23 MAT(m,1,2)
00608 #define m24 MAT(m,1,3)
00609 #define m31 MAT(m,2,0)
00610 #define m32 MAT(m,2,1)
00611 #define m33 MAT(m,2,2)
00612 #define m34 MAT(m,2,3)
00613 #define m41 MAT(m,3,0)
00614 #define m42 MAT(m,3,1)
00615 #define m43 MAT(m,3,2)
00616 #define m44 MAT(m,3,3)
00617 
00618    register double det;
00619    double tmp[16]; /* Allow out == in. */
00620 
00621    if( m41 != 0. || m42 != 0. || m43 != 0. || m44 != 1. ) {
00622       invertMatrixGeneral(m, out);
00623       return;
00624    }
00625 
00626    /* Inverse = adjoint / det. (See linear algebra texts.)*/
00627 
00628    tmp[0]= m22 * m33 - m23 * m32;
00629    tmp[1]= m23 * m31 - m21 * m33;
00630    tmp[2]= m21 * m32 - m22 * m31;
00631 
00632    /* Compute determinant as early as possible using these cofactors. */
00633    det= m11 * tmp[0] + m12 * tmp[1] + m13 * tmp[2];
00634 
00635    /* Run singularity test. */
00636    if (det == 0.0) {
00637       /* printf("invert_matrix: Warning: Singular matrix.\n"); */
00638       memcpy( out, _identity, 16*sizeof(double) );
00639    }
00640    else {
00641       double d12, d13, d23, d24, d34, d41;
00642       register double im11, im12, im13, im14;
00643 
00644       det= 1. / det;
00645 
00646       /* Compute rest of inverse. */
00647       tmp[0] *= det;
00648       tmp[1] *= det;
00649       tmp[2] *= det;
00650       tmp[3]  = 0.;
00651 
00652       im11= m11 * det;
00653       im12= m12 * det;
00654       im13= m13 * det;
00655       im14= m14 * det;
00656       tmp[4] = im13 * m32 - im12 * m33;
00657       tmp[5] = im11 * m33 - im13 * m31;
00658       tmp[6] = im12 * m31 - im11 * m32;
00659       tmp[7] = 0.;
00660 
00661       /* Pre-compute 2x2 dets for first two rows when computing */
00662       /* cofactors of last two rows. */
00663       d12 = im11*m22 - m21*im12;
00664       d13 = im11*m23 - m21*im13;
00665       d23 = im12*m23 - m22*im13;
00666       d24 = im12*m24 - m22*im14;
00667       d34 = im13*m24 - m23*im14;
00668       d41 = im14*m21 - m24*im11;
00669 
00670       tmp[8] =  d23;
00671       tmp[9] = -d13;
00672       tmp[10] = d12;
00673       tmp[11] = 0.;
00674 
00675       tmp[12] = -(m32 * d34 - m33 * d24 + m34 * d23);
00676       tmp[13] =  (m31 * d34 + m33 * d41 + m34 * d13);
00677       tmp[14] = -(m31 * d24 + m32 * d41 + m34 * d12);
00678       tmp[15] =  1.;
00679 
00680       memcpy(out, tmp, 16*sizeof(double));
00681   }
00682 
00683 #undef m11
00684 #undef m12
00685 #undef m13
00686 #undef m14
00687 #undef m21
00688 #undef m22
00689 #undef m23
00690 #undef m24
00691 #undef m31
00692 #undef m32
00693 #undef m33
00694 #undef m34
00695 #undef m41
00696 #undef m42
00697 #undef m43
00698 #undef m44
00699 #undef MAT
00700 }

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