Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

Matrix4.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2008 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: Matrix4.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.47 $       $Date: 2008/04/28 22:48:13 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *
00019  * 4 x 4 Matrix, used for a transformation matrix.
00020  *
00021  ***************************************************************************/
00022 
00023 #include <math.h>
00024 #include <string.h>
00025 #include <stdio.h>
00026 #include "Matrix4.h"
00027 #include "utilities.h"
00028 
00029 // constructor, for the case when an array of floating-point numbers is given
00030 Matrix4::Matrix4(const float *m) {
00031   memcpy((void *)mat, (const void *)m, 16*sizeof(float));
00032 }
00033 
00034 // multiplies a 3D point (first arg) by the Matrix, returns in second arg
00035 void Matrix4::multpoint3d(const float opoint[3], float npoint[3]) const {
00036 #if 0
00037     // should try re-testing this formulation to see if it outperforms
00038     // the old one, without introducing floating point imprecision
00039     float tmp[3];
00040     float itmp3 = 1.0f / (opoint[0]*mat[3] + opoint[1]*mat[7] + 
00041                           opoint[2]*mat[11] + mat[15]);
00042     npoint[0]=itmp3 * (opoint[0]*mat[0] + opoint[1]*mat[4] + opoint[2]*mat[ 8] + mat[12]);
00043     npoint[1]=itmp3 * (opoint[0]*mat[1] + opoint[1]*mat[5] + opoint[2]*mat[ 9] + mat[13]);
00044     npoint[2]=itmp3 * (opoint[0]*mat[2] + opoint[1]*mat[6] + opoint[2]*mat[10] + mat[14]);
00045 #else
00046     float tmp[3];
00047     float itmp3 = 1.0f / (opoint[0]*mat[3] + opoint[1]*mat[7] +
00048                           opoint[2]*mat[11] + mat[15]);
00049     tmp[0] = itmp3*opoint[0];
00050     tmp[1] = itmp3*opoint[1];
00051     tmp[2] = itmp3*opoint[2];
00052     npoint[0]=tmp[0]*mat[0] + tmp[1]*mat[4] + tmp[2]*mat[ 8] + itmp3*mat[12];
00053     npoint[1]=tmp[0]*mat[1] + tmp[1]*mat[5] + tmp[2]*mat[ 9] + itmp3*mat[13];
00054     npoint[2]=tmp[0]*mat[2] + tmp[1]*mat[6] + tmp[2]*mat[10] + itmp3*mat[14];
00055 #endif
00056 }
00057 
00058 
00059 // multiplies a 3D norm (first arg) by the Matrix, returns in second arg
00060 // This differs from point multiplication in that the translatation operations
00061 // are ignored.
00062 void Matrix4::multnorm3d(const float onorm[3], float nnorm[3]) const {
00063   float tmp[4];
00064 
00065   tmp[0]=onorm[0]*mat[0] + onorm[1]*mat[4] + onorm[2]*mat[8];
00066   tmp[1]=onorm[0]*mat[1] + onorm[1]*mat[5] + onorm[2]*mat[9];
00067   tmp[2]=onorm[0]*mat[2] + onorm[1]*mat[6] + onorm[2]*mat[10];
00068   tmp[3]=onorm[0]*mat[3] + onorm[1]*mat[7] + onorm[2]*mat[11];
00069   float itmp = 1.0f / sqrtf(tmp[0]*tmp[0] + tmp[1]*tmp[1] + tmp[2]*tmp[2]);
00070   nnorm[0]=tmp[0]*itmp;
00071   nnorm[1]=tmp[1]*itmp;
00072   nnorm[2]=tmp[2]*itmp;
00073 }
00074 
00075 
00076 // multiplies a 4D point (first arg) by the Matrix, returns in second arg
00077 void Matrix4::multpoint4d(const float opoint[4], float npoint[4]) const {
00078   npoint[0]=opoint[0]*mat[0]+opoint[1]*mat[4]+opoint[2]*mat[8]+opoint[3]*mat[12];
00079   npoint[1]=opoint[0]*mat[1]+opoint[1]*mat[5]+opoint[2]*mat[9]+opoint[3]*mat[13];
00080   npoint[2]=opoint[0]*mat[2]+opoint[1]*mat[6]+opoint[2]*mat[10]+opoint[3]*mat[14];
00081   npoint[3]=opoint[0]*mat[3]+opoint[1]*mat[7]+opoint[2]*mat[11]+opoint[3]*mat[15];
00082 }
00083 
00084 
00085 // clears the matrix (resets it to identity)
00086 void Matrix4::identity(void) {
00087   memset((void *)mat, 0, 16*sizeof(float));
00088   mat[0]=1.0f;
00089   mat[5]=1.0f;
00090   mat[10]=1.0f;
00091   mat[15]=1.0f;
00092 }
00093 
00094 
00095 // sets the matrix so all items are the given constant value
00096 void Matrix4::constant(float f) {
00097   for (int i=0; i<16; mat[i++] = f); 
00098 }
00099 
00100 // return the inverse of this matrix, that is, 
00101 // the inverse of the rotation, the inverse of the scaling, and 
00102 // the opposite of the translation vector.
00103 #define MATSWAP(a,b) {temp=(a);(a)=(b);(b)=temp;}
00104 int Matrix4::inverse(void) {
00105 
00106   float matr[4][4], ident[4][4];
00107   int i, j, k, l, ll;
00108   int icol=0, irow=0;
00109   int indxc[4], indxr[4], ipiv[4];
00110   float big, dum, pivinv, temp;
00111  
00112   for (i=0; i<4; i++) {
00113     for (j=0; j<4; j++) {
00114       matr[i][j] = mat[4*i+j];
00115       ident[i][j] = 0.0f;
00116     }
00117     ident[i][i]=1.0f;
00118   } 
00119   // Gauss-jordan elimination with full pivoting.  Yes, folks, a 
00120   // GL Matrix4 is inverted like any other, since the identity is 
00121   // still the identity.
00122   
00123   // from numerical recipies in C second edition, pg 39
00124 
00125   for(j=0;j<=3;j++) ipiv[j] = 0;
00126   for(i=0;i<=3;i++) {
00127     big=0.0;
00128     for (j=0;j<=3;j++) {
00129       if(ipiv[j] != 1) {
00130         for (k=0;k<=3;k++) {
00131           if(ipiv[k] == 0) {
00132             if(fabs(matr[j][k]) >= big) {
00133               big = (float) fabs(matr[j][k]);
00134               irow=j;
00135               icol=k;
00136             }
00137           } else if (ipiv[k] > 1) return 1;
00138         } 
00139       }
00140     }
00141     ++(ipiv[icol]);
00142     if (irow != icol) {
00143       for (l=0;l<=3;l++) MATSWAP(matr[irow][l],matr[icol][l]);
00144       for (l=0;l<=3;l++) MATSWAP(ident[irow][l],ident[icol][l]);
00145     }
00146     indxr[i]=irow;
00147     indxc[i]=icol;
00148     if(matr[icol][icol] == 0.0f) return 1; 
00149     pivinv = 1.0f / matr[icol][icol];
00150     matr[icol][icol]=1.0f;
00151     for (l=0;l<=3;l++) matr[icol][l] *= pivinv;
00152     for (l=0;l<=3;l++) ident[icol][l] *= pivinv;
00153     for (ll=0;ll<=3;ll++) {
00154       if (ll != icol) {
00155         dum=matr[ll][icol];
00156         matr[ll][icol]=0.0f;
00157         for (l=0;l<=3;l++) matr[ll][l] -= matr[icol][l]*dum;
00158         for (l=0;l<=3;l++) ident[ll][l] -= ident[icol][l]*dum;
00159       }
00160     }
00161   }
00162   for (l=3;l>=0;l--) {
00163     if (indxr[l] != indxc[l]) {
00164       for (k=0;k<=3;k++) {
00165         MATSWAP(matr[k][indxr[l]],matr[k][indxc[l]]);
00166       }
00167     }
00168   }
00169   for (i=0; i<4; i++) 
00170     for (j=0; j<4; j++)
00171       mat[4*i+j] = matr[i][j];
00172   return 0;
00173 }
00174       
00175 void Matrix4::transpose() {
00176   float tmp[16];
00177   int i,j;
00178   for(i=0;i<4;i++) {
00179     for(j=0;j<4;j++) {
00180       tmp[4*i+j] = mat[i+4*j];
00181     }
00182   }
00183   for(i=0;i<16;i++)
00184     mat[i] = tmp[i];
00185 }
00186 
00187 // replaces this matrix with the given one
00188 void Matrix4::loadmatrix(const Matrix4& m) {
00189   memcpy((void *)mat, (const void *)m.mat, 16*sizeof(float));
00190 }
00191 
00192 // premultiply the matrix by the given matrix
00193 void Matrix4::multmatrix(const Matrix4& m) {
00194   float tmp[4];
00195   for (int j=0; j<4; j++) {
00196     tmp[0] = mat[j];
00197     tmp[1] = mat[4+j];
00198     tmp[2] = mat[8+j]; 
00199     tmp[3] = mat[12+j];
00200     for (int i=0; i<4; i++) {
00201       mat[4*i+j] = m.mat[4*i]*tmp[0] + m.mat[4*i+1]*tmp[1] +
00202         m.mat[4*i+2]*tmp[2] + m.mat[4*i+3]*tmp[3]; 
00203     }
00204   } 
00205 }
00206 
00207 // performs a rotation around an axis (char == 'x', 'y', or 'z')
00208 // angle is in degrees
00209 void Matrix4::rot(float a, char axis) {
00210   Matrix4 m;                    // create identity matrix
00211   double angle;
00212 
00213   angle = (double)DEGTORAD(a);
00214 
00215   if (axis == 'x') {
00216     m.mat[0]=1.0;
00217     m.mat[5]=(float)cos(angle);
00218     m.mat[10]=m.mat[5];
00219     m.mat[6] = (float)sin(angle);
00220     m.mat[9] = -m.mat[6];
00221   } else if (axis == 'y') {
00222     m.mat[0] = (float)cos(angle);
00223     m.mat[5] = 1.0;
00224     m.mat[10] = m.mat[0];
00225     m.mat[2] = (float) -sin(angle);
00226     m.mat[8] = -m.mat[2];
00227   } else if (axis == 'z') {
00228     m.mat[0] = (float)cos(angle);
00229     m.mat[5] = m.mat[0];
00230     m.mat[10] = 1.0;
00231     m.mat[1] = (float)sin(angle);
00232     m.mat[4] = -m.mat[1];
00233   }
00234   // If there was an error, m is identity so we can multiply anyway.
00235   multmatrix(m);
00236 }
00237 
00238 // performs rotation around a given vector
00239 void Matrix4::rotate_axis(const float axis[3], float angle) {
00240   transvec(axis[0], axis[1], axis[2]);
00241   rot((float) (RADTODEG(angle)), 'x');
00242   transvecinv(axis[0], axis[1], axis[2]);
00243 }
00244 
00245 // applies the transformation needed to bring the x axis along the given vector. 
00246 void Matrix4::transvec(float x, float y, float z) {
00247   double theta = atan2(y,x);
00248   double length = sqrt(y*y + x*x);
00249   double phi = atan2((double) z, length);
00250   rot((float) RADTODEG(theta), 'z');
00251   rot((float) RADTODEG(-phi), 'y');
00252 }
00253 
00254 // applies the transformation needed to bring the given vector to the x axis.
00255 void Matrix4::transvecinv(float x, float y, float z) {
00256   double theta = atan2(y,x);
00257   double length = sqrt(y*y + x*x);
00258   double phi = atan2((double) z, length);
00259   rot((float) RADTODEG(phi), 'y');
00260   rot((float) RADTODEG(-theta), 'z');
00261 }
00262 
00263 // performs a translation
00264 void Matrix4::translate(float x, float y, float z) {
00265   Matrix4 m;            // create identity matrix
00266   m.mat[12] = x;
00267   m.mat[13] = y;
00268   m.mat[14] = z;
00269   multmatrix(m);
00270 }
00271 
00272 // performs scaling
00273 void Matrix4::scale(float x, float y, float z) {
00274   Matrix4 m;            // create identity matrix
00275   m.mat[0] = x;
00276   m.mat[5] = y;
00277   m.mat[10] = z;
00278   multmatrix(m);
00279 }
00280 
00281 // sets this matrix to represent a window perspective
00282 void Matrix4::window(float left, float right, float bottom, 
00283                          float top, float nearval, float farval) {
00284 
00285   constant(0.0);                // initialize this matrix to 0
00286   mat[0] = (2.0f*nearval) / (right-left);
00287   mat[5] = (2.0f*nearval) / (top-bottom);
00288   mat[8] = (right+left) / (right-left);
00289   mat[9] = (top+bottom) / (top-bottom);
00290   mat[10] = -(farval+nearval) / (farval-nearval);
00291   mat[11] = -1.0f;
00292   mat[14] = -(2.0f*farval*nearval) / (farval-nearval);
00293 }
00294 
00295 
00296 // sets this matrix to a 3D orthographic matrix
00297 void Matrix4::ortho(float left, float right, float bottom,
00298                         float top, float nearval, float farval) {
00299 
00300   constant(0.0);                // initialize this matrix to 0
00301   mat[0] =  2.0f / (right-left);
00302   mat[5] =  2.0f / (top-bottom);
00303   mat[10] = -2.0f / (farval-nearval);
00304   mat[12] = -(right+left) / (right-left);
00305   mat[13] = -(top+bottom) / (top-bottom);
00306   mat[14] = -(farval+nearval) / (farval-nearval);
00307   mat[15] = 1.0;
00308 }
00309 
00310 
00311 // sets this matrix to a 2D orthographic matrix
00312 void Matrix4::ortho2(float left, float right, float bottom, float top) {
00313 
00314   constant(0.0);                // initialize this matrix to 0
00315   mat[0] =  2.0f / (right-left);
00316   mat[5] =  2.0f / (top-bottom);
00317   mat[10] = -1.0f;
00318   mat[12] = -(right+left) / (right-left);
00319   mat[13] = -(top+bottom) / (top-bottom);
00320   mat[15] =  1.0f;
00321 }
00322 
00323 /* This subroutine defines a viewing transformation with the eye at the point
00324  * (vx,vy,vz) looking at the point (px,py,pz).  Twist is the right-hand
00325  * rotation about this line.  The resultant matrix is multiplied with
00326  * the top of the transformation stack and then replaces it.  Precisely,
00327  * lookat does:
00328  * lookat = trans(-vx,-vy,-vz)*rotate(theta,y)*rotate(phi,x)*rotate(-twist,z)
00329  */
00330  void Matrix4::lookat(float vx, float vy, float vz, float px, float py,
00331                          float pz, short twist) {
00332   Matrix4 m(0.0);
00333   float tmp;
00334 
00335   /* pre multiply stack by rotate(-twist,z) */
00336   rot(-twist / 10.0f,'z');
00337 
00338   tmp = sqrtf((px-vx)*(px-vx) + (py-vy)*(py-vy) + (pz-vz)*(pz-vz));
00339   m.mat[0] = 1.0;
00340   m.mat[5] = sqrtf((px-vx)*(px-vx) + (pz-vz)*(pz-vz)) / tmp;
00341   m.mat[6] = (vy-py) / tmp;
00342   m.mat[9] = -m.mat[6];
00343   m.mat[10] = m.mat[5];
00344   m.mat[15] = 1.0;
00345   multmatrix(m);
00346 
00347   /* premultiply by rotate(theta,y) */
00348   m.constant(0.0);
00349   tmp = sqrtf((px-vx)*(px-vx) + (pz-vz)*(pz-vz));
00350   m.mat[0] = (vz-pz) / tmp;
00351   m.mat[5] = 1.0;
00352   m.mat[10] = m.mat[0];
00353   m.mat[15] = 1.0;
00354   m.mat[2] = -(px-vx) / tmp;
00355   m.mat[8] = -m.mat[2];
00356   multmatrix(m);
00357 
00358   /* premultiply by trans(-vx,-vy,-vz) */
00359   translate(-vx,-vy,-vz);
00360 }
00361 
00362  // Transform 3x3 into 4x4 matrix:
00363  void trans_from_rotate(const float mat3[9], Matrix4 *mat4) {
00364   int i;
00365   for (i=0; i<3; i++) {
00366     mat4->mat[0+i] = mat3[3*i];
00367     mat4->mat[4+i] = mat3[3*i+1];
00368     mat4->mat[8+i] = mat3[3*i+2];
00369   }
00370 }
00371 
00372 // Print a matrix for debugging purpose
00373 void print_Matrix4(const Matrix4 *mat4) {
00374   int i, j;
00375   for (i=0; i<4; i++) {
00376     for (j=0; j<4; j++) {
00377       printf("%f ", mat4->mat[4*j+i]);
00378     }
00379     printf("\n");
00380   }
00381   printf("\n");
00382 }
00383 

Generated on Sat Sep 6 01:26:54 2008 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002