// MatrixC Code Definition #define VNAME C #define VTYPE unsigned char // Constructors/Destructors inline MatrixC::MatrixC (void) {data = NULL; Resize (0,0);} inline MatrixC::~MatrixC (void) {if (data!=NULL) delete[] data;} inline MatrixC::MatrixC (int r, int c) {data = NULL; Resize (c,r);} // Member Functions inline VTYPE &MatrixC::operator () (int c, int r) { #ifdef DEBUG_MATRIX if (data==NULL) Error.Print ( ErrorLev::Matrix, ErrorDef::MatrixIsNull, true ); if (r<0 || r>=rows) Error.Print ( ErrorLev::Matrix, ErrorDef::RowOutOfBounds, true ); if (c<0 || c>=cols) Error.Print ( ErrorLev::Matrix, ErrorDef::ColOutOfBounds, true ); #endif return *(data + (r*cols+c)); } inline MatrixC &MatrixC::operator= (unsigned char op) {VTYPE *n = data, *nlen = data + len; for (;n255) { *n = (VTYPE) 255; } else if (*b<=0) { *n = (VTYPE) 0; } else { *n = (VTYPE) *b; } } return *this; } inline MatrixC &MatrixC::operator+= (unsigned char op) {VTYPE *n = data, *nlen = data + len; for (;n= bce) { // If last col in B.. bs = op.data; // Go back to first column in B as += cols; // Goto next row in A } n++; // Goto next element in C } delete[] data; // Destroy old A matrix data = newdata; rows = newr; cols = newc; len = newlen; // Replace with new A matrix } return *this; } inline MatrixC &MatrixC::Resize (int x, int y) { if (data!=NULL) { if (rows!=y || cols!=x) { delete[] data; len = (rows = y) * (cols = x); data = new VTYPE[len]; } } else { len = (rows = y) * (cols = x); data = new VTYPE[len]; } #ifdef DEBUG_MATRIX if (data==NULL) Debug.Print (DEBUG_MATRIX, "MatrixC::Resize: Out of memory for construction.\n"); #endif #ifdef MATRIX_INITIALIZE memset (data, 0, sizeof(VTYPE)*len); #endif return *this; } inline MatrixC &MatrixC::ResizeSafe (int x, int y) { VTYPE *newdata; int newlen; VTYPE *n, *ne; VTYPE *b, *be; int bskip; if (data!=NULL) { newlen = x*y; newdata = new VTYPE[newlen]; #ifdef DEBUG_MATRIX if (newdata==NULL) Debug.Print (DEBUG_MATRIX, "MatrixC::SizeSafe: Out of memory for construction.\n"); #endif if (y>=rows && x>=cols) { // New size is larger (in both r and c) memset (newdata, 0, newlen*sizeof(VTYPE)); // Clear new matrix ne = data + len; // Calculate end of current matrix b = newdata; // Start of new matrix be = newdata + cols; // Last filled column+1 in new matrix bskip = x-cols; for (n = data; n0) { n = data; // Copy columns to left of c ne = data + len; nskip = (cols-c); b = newdata; be = newdata + c; bskip = (cols-c)+1; for (; n Ainv // b -> solution x // #ifdef DEBUG_MATRIX Debug.Print (DEBUG_MATRIX, "MatrixC::GaussJordan: Not implemented for char matrix\n"); #endif return *this; } inline int MatrixC::GetX() {return cols;} inline int MatrixC::GetY() {return rows;} inline int MatrixC::GetRows(void) {return rows;} inline int MatrixC::GetCols(void) {return cols;} inline int MatrixC::GetLength(void) {return len;} inline VTYPE *MatrixC::GetData(void) {return data;} inline double MatrixC::GetF (int r, int c) {return (double) (*(data + r*cols + c));} #undef VTYPE #undef VNAME // MatrixI Code Definition #define VNAME I #define VTYPE int // Constructors/Destructors inline MatrixI::MatrixI (void) {data = NULL; Resize (0,0);} inline MatrixI::~MatrixI (void) {if (data!=NULL) delete[] data;} inline MatrixI::MatrixI (int r, int c) {data = NULL; Resize (c,r);} // Member Functions inline VTYPE &MatrixI::operator () (int c, int r) { #ifdef DEBUG_MATRIX if (data==NULL) Debug.Print (DEBUG_MATRIX, "MatrixI::op(): Matrix data is null\n"); if (r<0 || r>=rows) Debug.Print (DEBUG_MATRIX, "MatrixI:op(): Row is out of bounds\n"); if (c<0 || c>=cols) Debug.Print (DEBUG_MATRIX, "MatrixI:op(): Col is out of bounds\n"); #endif return *(data + (r*cols+c)); } inline MatrixI &MatrixI::operator= (unsigned char op) {VTYPE *n = data, *nlen = data + len; for (;n= bce) { // If last col in B.. bs = op.data; // Go back to first column in B as += cols; // Goto next row in A } n++; // Goto next element in C } delete[] data; // Destroy old A matrix data = newdata; rows = newr; cols = newc; len = newlen; // Replace with new A matrix } return *this; } inline MatrixI &MatrixI::Resize (int x, int y) { if (data!=NULL) { if (rows!=y || cols!=x) {delete[] data; len = (rows = y) * (cols = x); data = new VTYPE[len];} } else { len = (rows = y) * (cols = x); data = new VTYPE[len]; } #ifdef DEBUG_MATRIX if (data==NULL) Debug.Print (DEBUG_MATRIX, "MatrixC::Size: Out of memory for construction.\n"); #endif #ifdef MATRIX_INITIALIZE memset (data, 0, sizeof(VTYPE)*len); #endif return *this; } inline MatrixI &MatrixI::ResizeSafe (int x, int y) { VTYPE *newdata; int newlen; VTYPE *n, *ne; VTYPE *b, *be; int bskip; if (data!=NULL) { newlen = x*y; newdata = new VTYPE[newlen]; #ifdef DEBUG_MATRIX if (newdata==NULL) Debug.Print (DEBUG_MATRIX, "MatrixC::SizeSafe: Out of memory for construction.\n"); #endif if (y>=rows && x>=cols) { // New size is larger (in both r and c) memset (newdata, 0, newlen*sizeof(VTYPE)); // Clear new matrix ne = data + len; // Calculate end of current matrix b = newdata; // Start of new matrix be = newdata + cols; // Last filled column+1 in new matrix bskip = x-cols; for (n = data; n0) { n = data; // Copy columns to left of c ne = data + len; nskip = (cols-c); b = newdata; be = newdata + c; bskip = (cols-c)+1; for (; n Ainv // b -> solution x // #ifdef DEBUG_MATRIX Debug.Print (DEBUG_MATRIX, "MatrixI::GaussJordan: Not implemented for int matrix\n"); #endif return *this; } inline int MatrixI::GetX() {return cols;} inline int MatrixI::GetY() {return rows;} inline int MatrixI::GetRows(void) {return rows;} inline int MatrixI::GetCols(void) {return cols;} inline int MatrixI::GetLength(void) {return len;} inline VTYPE *MatrixI::GetData(void) {return data;} inline double MatrixI::GetF (int r, int c) {return (double) (*(data + r*cols + c));} #undef VTYPE #undef VNAME // MatrixF Code Definition #define VNAME F #define VTYPE double // Constructors/Destructors inline MatrixF::MatrixF (void) {data = NULL; Resize (0,0);} inline MatrixF::~MatrixF (void) { if (data!=NULL) delete [] data; } inline MatrixF::MatrixF (const int r, const int c) {data = NULL; Resize (r,c);} // Member Functions inline VTYPE MatrixF::GetVal ( int c, int r ) { #ifdef DEBUG_MATRIX if (data==NULL) Error.Print ( ErrorLev::Matrix, ErrorDef::MatrixIsNull, true ); if (r<0 || r>=rows) Error.Print ( ErrorLev::Matrix, ErrorDef::RowOutOfBounds, true ); if (c<0 || c>=cols) Error.Print ( ErrorLev::Matrix, ErrorDef::ColOutOfBounds, true ); #endif return *(data + (r*cols+c)); } inline VTYPE &MatrixF::operator () (const int c, const int r) { #ifdef DEBUG_MATRIX if (data==NULL) Error.Print ( ErrorLev::Matrix, ErrorDef::MatrixIsNull, true ); if (r<0 || r>=rows) Error.Print ( ErrorLev::Matrix, ErrorDef::RowOutOfBounds, true ); if (c<0 || c>=cols) Error.Print ( ErrorLev::Matrix, ErrorDef::ColOutOfBounds, true ); #endif return *(data + (r*cols+c)); } inline MatrixF &MatrixF::operator= (const unsigned char op) {VTYPE *n = data, *nlen = data + len; for (;n= bce) { // If last col in B.. bs = op.data; // Go back to first column in B as += cols; // Goto next row in A } n++; // Goto next element in C } delete[] data; // Destroy old A matrix data = newdata; rows = newr; cols = newc; len = newlen; // Replace with new A matrix } return *this; } inline MatrixF &MatrixF::Multiply4x4 (const MatrixF &op) { #ifdef DEBUG_MATRIX if (data==NULL) Debug.Print (DEBUG_MATRIX, "MatrixF::Multiply4x4 m*=op: Matrix data is null\n"); if (op.data==NULL) Debug.Print (DEBUG_MATRIX, "MatrixF::Multiply4x4 m*=op: Operand matrix (op) data is null\n"); if (rows!=4 || cols!=4) Debug.Print (DEBUG_MATRIX, "MatrixF::Multiply4x4 m*=op: Matrix m is not 4x4"); if (op.rows!=4 || op.cols!=4) Debug.Print (DEBUG_MATRIX, "MatrixF::Multiply4x4 m*=op: Matrix op is not 4x4"); #endif register double c1, c2, c3, c4; // Temporary storage VTYPE *n, *a, *b1, *b2, *b3, *b4; a = data; n = data; b1 = op.data; b2 = op.data + 4; b3 = op.data + 8; b4 = op.data + 12; c1 = *a++; c2 = *a++; c3 = *a++; c4 = *a++; // Calculate First Row *n++ = c1*(*b1++) + c2*(*b2++) + c3*(*b3++) + c4*(*b4++); *n++ = c1*(*b1++) + c2*(*b2++) + c3*(*b3++) + c4*(*b4++); *n++ = c1*(*b1++) + c2*(*b2++) + c3*(*b3++) + c4*(*b4++); *n++ = c1*(*b1) + c2*(*b2) + c3*(*b3) + c4*(*b4); b1 -= 3 ; b2 -= 3; b3 -= 3; b4 -= 3; c1 = *a++; c2 = *a++; c3 = *a++; c4 = *a++; // Calculate Second Row *n++ = c1*(*b1++) + c2*(*b2++) + c3*(*b3++) + c4*(*b4++); *n++ = c1*(*b1++) + c2*(*b2++) + c3*(*b3++) + c4*(*b4++); *n++ = c1*(*b1++) + c2*(*b2++) + c3*(*b3++) + c4*(*b4++); *n++ = c1*(*b1) + c2*(*b2) + c3*(*b3) + c4*(*b4); b1 -= 3 ; b2 -= 3; b3 -= 3; b4 -= 3; c1 = *a++; c2 = *a++; c3 = *a++; c4 = *a++; // Calculate Third Row *n++ = c1*(*b1++) + c2*(*b2++) + c3*(*b3++) + c4*(*b4++); *n++ = c1*(*b1++) + c2*(*b2++) + c3*(*b3++) + c4*(*b4++); *n++ = c1*(*b1++) + c2*(*b2++) + c3*(*b3++) + c4*(*b4++); *n++ = c1*(*b1) + c2*(*b2) + c3*(*b3) + c4*(*b4); b1 -= 3 ; b2 -= 3; b3 -= 3; b4 -= 3; c1 = *a++; c2 = *a++; c3 = *a++; c4 = *a; // Calculate Four Row *n++ = c1*(*b1++) + c2*(*b2++) + c3*(*b3++) + c4*(*b4++); *n++ = c1*(*b1++) + c2*(*b2++) + c3*(*b3++) + c4*(*b4++); *n++ = c1*(*b1++) + c2*(*b2++) + c3*(*b3++) + c4*(*b4++); *n = c1*(*b1) + c2*(*b2) + c3*(*b3) + c4*(*b4); return *this; } inline MatrixF &MatrixF::Resize (const int x, const int y) { if (data!=NULL) { if (rows==y && cols==x) return *this; delete[] data; } rows = y; cols = x; if (y>0 && x>0) { len = rows * cols; if (len!=0) { data = new VTYPE[len]; #ifdef DEBUG_MATRIX if (data==NULL) Debug.Print (DEBUG_MATRIX, "MatrixF::Size: Out of memory for construction.\n"); #endif } } #ifdef MATRIX_INITIALIZE if (data!=NULL) memset (data, 0, sizeof(VTYPE)*len); #endif return *this; } inline MatrixF &MatrixF::ResizeSafe (const int x, const int y) { VTYPE *newdata; int newlen; VTYPE *n, *ne; VTYPE *b, *be; int bskip; if (data!=NULL) { newlen = x*y; newdata = new VTYPE[newlen]; #ifdef DEBUG_MATRIX if (newdata==NULL) Debug.Print (DEBUG_MATRIX, "MatrixF::SizeSafe: Out of memory for construction.\n"); #endif if (y>=rows && x>=cols) { // New size is larger (in both r and c) memset (newdata, 0, newlen*sizeof(VTYPE)); // Clear new matrix ne = data + len; // Calculate end of current matrix b = newdata; // Start of new matrix be = newdata + cols; // Last filled column+1 in new matrix bskip = x-cols; for (n = data; n0) { n = data; // Copy columns to left of c ne = data + len; nskip = (cols-c); b = newdata; be = newdata + c; bskip = (cols-c)+1; for (; n>counter-clockwise<< when looking down the X+ axis toward the origin inline MatrixF &MatrixF::RotateX (const double ang) { Resize (4,4); VTYPE *n = data; double c,s; c = cos(ang * 3.141592/180); s = sin(ang * 3.141592/180); *n = 1; n += 5; *n++ = (VTYPE) c; *n = (VTYPE) s; n+=3; *n++ = (VTYPE) -s; *n = (VTYPE) c; n+=5; *n = 1; return *this; } // rotates points >>counter-clockwise<< when looking down the Y+ axis toward the origin inline MatrixF &MatrixF::RotateY (const double ang) { Resize (4,4); VTYPE *n = data; double c,s; c = cos(ang * 3.141592/180); s = sin(ang * 3.141592/180); *n = (VTYPE) c; n+=2; *n = (VTYPE) -s; n+=3; *n = 1; n+=3; *n = (VTYPE) s; n+=2; *n = (VTYPE) c; n+=5; *n = 1; return *this; } // rotates points >>counter-clockwise<< when looking down the Z+ axis toward the origin inline MatrixF &MatrixF::RotateZ (const double ang) { Resize (4,4); VTYPE *n = data; double c,s; c = cos(ang * 3.141592/180); s = sin(ang * 3.141592/180); *n++ = (VTYPE) c; *n = (VTYPE) s; n+=3; *n++ = (VTYPE) -s; *n = (VTYPE) c; n+=5; *n = 1; n+=5; *n = 1; return *this; } inline MatrixF &MatrixF::Ortho (double sx, double sy, double vn, double vf) { // simplified version of OpenGL's glOrtho function VTYPE *n = data; *n++ = (VTYPE) (1.0/sx); *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) (1.0/sy); *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) (-2.0/(vf-vn)); *n++ = (VTYPE) (-(vf+vn)/(vf-vn)); *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0; *n++ = (VTYPE) 1.0; } inline MatrixF &MatrixF::Translate (double tx, double ty, double tz) { Resize (4,4); VTYPE *n = data; *n++ = (VTYPE) 1.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 1.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) 1.0; *n++ = (VTYPE) 0.0; *n++ = (VTYPE) tx; *n++ = (VTYPE) ty; *n++ = (VTYPE) tz; *n++ = (VTYPE) 1.0; return *this; } inline MatrixF &MatrixF::Basis (const Vector3DF &c1, const Vector3DF &c2, const Vector3DF &c3) { Resize (4,4); VTYPE *n = data; *n++ = (VTYPE) c1.X(); *n++ = (VTYPE) c2.X(); *n++ = (VTYPE) c3.X(); *n++ = (VTYPE) 0; *n++ = (VTYPE) c1.Y(); *n++ = (VTYPE) c2.Y(); *n++ = (VTYPE) c3.Y(); *n++ = (VTYPE) 0; *n++ = (VTYPE) c1.Z(); *n++ = (VTYPE) c2.Z(); *n++ = (VTYPE) c3.Z(); *n++ = (VTYPE) 0; *n++ = (VTYPE) 0; *n++ = (VTYPE) 0; *n++ = (VTYPE) 0; *n++ = (VTYPE) 0; return *this; } #define SWAP(a, b) {temp=(a); (a)=(b); (b)=temp;} inline MatrixF &MatrixF::GaussJordan (MatrixF &b) { // Gauss-Jordan solves the matrix equation Ax = b // Given the problem: // A*x = b (where A is 'this' matrix and b is provided) // The solution is: // Ainv*b = x // This function returns Ainv in A and x in b... that is: // A (this) -> Ainv // b -> solution x // MatrixI index_col, index_row; MatrixI piv_flag; int r, c, c2, rs, cs; double piv_val; int piv_row, piv_col; double pivinv, dummy, temp; #ifdef DEBUG_MATRIX if (rows!=cols) Debug.Print (DEBUG_MATRIX, "MatrixF::GaussJordan: Number of rows and cols of A must be equal.\n"); if (rows!=b.rows) Debug.Print (DEBUG_MATRIX, "MatrixF::GaussJordan: Number of rows of A and rows of b must be equal.\n"); if (b.cols!=1) Debug.Print ( DEBUG_MATRIX, "MatrixF::GaussJordan: Number of cols of b must be 1.\n"); #endif index_col.Resize (cols, 1); index_row.Resize (cols, 1); piv_flag.Resize (cols, 1); piv_flag = 0; for (c = 0; c < cols; c++) { piv_val = 0.0; for (rs = 0; rs < rows; rs++) { if (piv_flag(rs, 0) != 1 ) for (cs = 0; cs < cols; cs++) { if (piv_flag(cs, 0) == 0) { if (fabs((*this) (cs, rs)) >= piv_val) { piv_val = fabs((*this) (cs, rs)); piv_row = rs; piv_col = cs; } } else if (piv_flag(cs, 0)>1) { #ifdef DEBUG_MATRIX Debug.Print (DEBUG_MATRIX, "MatrixF::GaussJordan: Singular matrix (dbl pivs).\n"); //Print (); #endif } } } piv_flag(piv_col, 0)++; if (piv_row != piv_col) { for (c2 = 0; c2 < cols; c2++) SWAP ((*this) (c2, piv_row), (*this) (c2, piv_col)); for (c2 = 0; c2 < b.cols; c2++) SWAP (b(c2, piv_row), b(c2, piv_col)); } index_row (c, 0) = piv_row; index_col (c, 0) = piv_col; if ((*this) (piv_col, piv_col) == 0.0) { #ifdef DEBUG_MATRIX Debug.Print (DEBUG_MATRIX, "MatrixF::GaussJordan: Singular matrix (0 piv).\n"); //Print (); #endif } pivinv = 1.0 / ((*this) (piv_col, piv_col)); (*this) (piv_col, piv_col) = 1.0; for (c2 = 0; c2 < cols; c2++) (*this) (c2, piv_col) *= pivinv; for (c2 = 0; c2 < b.cols; c2++) b(c2, piv_col) *= pivinv; for (r = 0; r < rows; r++) { if (r != piv_col) { dummy = (*this) (piv_col, r); (*this) (piv_col, r) = 0.0; for (c2 = 0; c2 < cols; c2++) (*this) (c2, r) -= (*this) (c2, piv_col)*dummy; for (c2 = 0; c2 < b.cols; c2++) b(c2, r) -= b(c2, piv_col)*dummy; } } } for (c = cols-1; c >= 0; c--) { if (index_row(c, 0) != index_col(c, 0)) for (r = 0; r < rows; r++) SWAP ((*this) (index_row(c,0), r), (*this) (index_col(c,0), r) ); } return *this; } inline MatrixF &MatrixF::Submatrix ( MatrixF& b, int mx, int my) { VTYPE* pEnd = data + rows*cols; // end of matrix VTYPE* pVal = data; VTYPE* pNewVal = b.data; VTYPE* pNewEnd = pNewVal + mx; int pNewSkip = cols - mx; for (pVal = data; pVal < pEnd;) { for (; pNewVal < pNewEnd;) *pVal++ = *pNewVal++; pNewVal += pNewSkip; pNewEnd += mx; } return *this; } // N-Vector Dot Product // Elements may be in rows or columns, but: // - If in rows, number of columns must be one and number of rows must match. // - If in cols, number of rows must be one and number of cols must match. inline double MatrixF::Dot ( MatrixF& b ) { double d = 0.0; VTYPE* pA = data; VTYPE* pB = b.data; if ( rows==1 && b.rows==1 && cols == b.cols ) { VTYPE* pAEnd = data + cols; d = 0.0; for (; pA < pAEnd;) d += (*pA++) * (*pB++); } else if ( cols==1 && b.cols==1 && rows == b.rows) { VTYPE* pAEnd = data + rows; d = 0.0; for (; pA < pAEnd;) d += (*pA++) * (*pB++); } return d; } #define I(x, y) ( (y*xres) + x ) #define Ix(r) ( r % xres ) // X coordinate from row #define Iy(r) ( r / xres ) // Y coordinate from row inline MatrixF &MatrixF::MatrixVector5 (MatrixF& x, int mrows, MatrixF& b) { double v; // A( 2, r ) * B ( r ) + A(1,r)*B(r-1) + A(3,r)*B(r+1) + A(0, r)*B( R-( r ) ) + A(4, r)*B( R+( r ) ) for (int r = 0; r < mrows; r++) { v = GetVal(2, r) * x(0,r); if ( r > 0 ) v += GetVal(1,r) * x(0,r-1); if ( r < mrows-1) v += GetVal(3,r) * x(0,r+1); if ( (int) GetVal(5, r) >= 0) v += GetVal(0,r) * x(0, (int) GetVal(5,r)); if ( (int) GetVal(6, r) >= 0) v += GetVal(4,r) * x(0, (int) GetVal(6,r)); b(0,r) = v; } return *this; } inline MatrixF &MatrixF::ConjugateGradient (MatrixF &b) { return *this; } // Sparse Conjugate Gradient 2D (special case) // This compute conjugate gradients on a // sparse "5-7" x N positive definite matrix. // Only 'mrows' subset of the row-size of A and b will be used. inline MatrixF &MatrixF::ConjugateGradient5 (MatrixF &b, int mrows ) { double a, g, rdot; int i, imax; MatrixF x, xnew; // solution vector MatrixF r, rnew; // residual MatrixF p, ptemp; // search direction MatrixF v; x.Resize ( 1, mrows ); xnew.Resize ( 1, mrows ); r.Resize ( 1, mrows ); rnew.Resize ( 1, mrows ); p.Resize ( 1, mrows ); ptemp.Resize ( 1, mrows ); v.Resize ( 1, mrows ); r.Submatrix ( b, 1, mrows); MatrixVector5 ( x, mrows, v ); // (Ax -> v) r -= v; // r = b - Ax p = r; imax = 20; for (i=0; i < imax; i++) { MatrixVector5 ( p, mrows, v ); // v = Ap rdot = r.Dot ( r ); a = rdot / p.Dot ( v ); // a = (r . r) / (p . v) xnew = p; xnew *= a; xnew += x; // x = x + p*a v *= a; rnew = r; // rnew = r - v*a rnew -= v; g = rnew.Dot ( rnew ) / rdot; // g = (rnew . rnew) / (r . r) p *= g; p += rnew; // p = rnew + p*g r = rnew; x = xnew; } for (int rx=0; rx < mrows; rx++) b(0, rx) = x(0, rx); return *this; } inline int MatrixF::GetX() {return cols;} inline int MatrixF::GetY() {return rows;} inline int MatrixF::GetRows(void) {return rows;} inline int MatrixF::GetCols(void) {return cols;} inline int MatrixF::GetLength(void) {return len;} inline VTYPE *MatrixF::GetData(void) {return data;} inline double MatrixF::GetF (const int r, const int c) {return (double) (*(data + r*cols + c));} inline void MatrixF::GetRowVec (int r, Vector3DF &v) { VTYPE *n = data + r*cols; v.x = (float) *n++; v.y = (float) *n++; v.z= (float) *n++; } inline void MatrixF::Print ( char* fname ) { char buf[2000]; FILE* fp = fopen ( fname, "w+" ); for (int r=0; r < rows; r++) { buf[0] = '\0'; for (int c =0; c < cols; c++) { sprintf ( buf, "%s %04.3f", buf, GetVal(c, r) ); } fprintf ( fp, "%s\n", buf); } fprintf ( fp, "---------------------------------------\n", buf); fflush ( fp ); fclose ( fp ); } // MatrixF Code Definition #undef VTYPE #define VNAME F #define VTYPE float // Constructors/Destructors inline Matrix4F::Matrix4F (void) { for (int n=0; n < 16; n++) data[n] = 0.0; } inline Matrix4F &Matrix4F::operator= (const unsigned char op) {for ( int n=0; n<16; n++) data[n] = (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator= (const int op) {for ( int n=0; n<16; n++) data[n] = (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator= (const double op) {for ( int n=0; n<16; n++) data[n] = (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator+= (const unsigned char op) {for ( int n=0; n<16; n++) data[n] += (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator+= (const int op) {for ( int n=0; n<16; n++) data[n] += (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator+= (const double op) {for ( int n=0; n<16; n++) data[n] += (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator-= (const unsigned char op) {for ( int n=0; n<16; n++) data[n] -= (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator-= (const int op) {for ( int n=0; n<16; n++) data[n] -= (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator-= (const double op) {for ( int n=0; n<16; n++) data[n] -= (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator*= (const unsigned char op) {for ( int n=0; n<16; n++) data[n] *= (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator*= (const int op) {for ( int n=0; n<16; n++) data[n] *= (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator*= (const double op) {for ( int n=0; n<16; n++) data[n] *= (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator/= (const unsigned char op) {for ( int n=0; n<16; n++) data[n] /= (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator/= (const int op) {for ( int n=0; n<16; n++) data[n] /= (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::operator/= (const double op) {for ( int n=0; n<16; n++) data[n] /= (VTYPE) op; return *this;} inline Matrix4F &Matrix4F::Multiply (const Matrix4F &op) { register float orig[16]; // Temporary storage memcpy ( orig, data, 16*sizeof(float) ); // Calculate First Row data[0] = orig[0]*op.data[0] + orig[1]*op.data[4] + orig[2]*op.data[8] + orig[3]*op.data[12]; data[1] = orig[0]*op.data[1] + orig[1]*op.data[5] + orig[2]*op.data[9] + orig[3]*op.data[13]; data[2] = orig[0]*op.data[2] + orig[1]*op.data[6] + orig[2]*op.data[10] + orig[3]*op.data[14]; data[3] = orig[0]*op.data[3] + orig[1]*op.data[7] + orig[2]*op.data[11] + orig[3]*op.data[15]; // Calculate Second Row data[4] = orig[4]*op.data[0] + orig[5]*op.data[4] + orig[6]*op.data[8] + orig[7]*op.data[12]; data[5] = orig[4]*op.data[1] + orig[5]*op.data[5] + orig[6]*op.data[9] + orig[7]*op.data[13]; data[6] = orig[4]*op.data[2] + orig[5]*op.data[6] + orig[6]*op.data[10] + orig[7]*op.data[14]; data[7] = orig[4]*op.data[3] + orig[5]*op.data[7] + orig[6]*op.data[11] + orig[7]*op.data[15]; // Calculate Third Row data[8] = orig[8]*op.data[0] + orig[9]*op.data[4] + orig[10]*op.data[8] + orig[11]*op.data[12]; data[9] = orig[8]*op.data[1] + orig[9]*op.data[5] + orig[10]*op.data[9] + orig[11]*op.data[13]; data[10] = orig[8]*op.data[2] + orig[9]*op.data[6] + orig[10]*op.data[10] + orig[11]*op.data[14]; data[11] = orig[8]*op.data[3] + orig[9]*op.data[7] + orig[10]*op.data[11] + orig[11]*op.data[15]; // Calculate Four Row data[12] = orig[12]*op.data[0] + orig[13]*op.data[4] + orig[14]*op.data[8] + orig[15]*op.data[12]; data[13] = orig[12]*op.data[1] + orig[13]*op.data[5] + orig[14]*op.data[9] + orig[15]*op.data[13]; data[14] = orig[12]*op.data[2] + orig[13]*op.data[6] + orig[14]*op.data[10] + orig[15]*op.data[14]; data[15] = orig[12]*op.data[3] + orig[13]*op.data[7] + orig[14]*op.data[11] + orig[15]*op.data[15]; return *this; } inline Matrix4F &Matrix4F::Transpose (void) { register float orig[16]; // Temporary storage memcpy ( orig, data, 16*sizeof(VTYPE) ); data[0] = orig[0]; data[1] = orig[4]; data[2] = orig[8]; data[3] = orig[12]; data[4] = orig[1]; data[5] = orig[5]; data[6] = orig[9]; data[7] = orig[13]; data[8] = orig[2]; data[9] = orig[6]; data[10] = orig[10];data[11] = orig[14]; data[12] = orig[3]; data[13] = orig[7]; data[14] = orig[11];data[15] = orig[15]; return *this; } inline Matrix4F &Matrix4F::Identity (const int order) { memset (data, 0, 16*sizeof(VTYPE)); data[0] = 1.0; data[5] = 1.0; data[10] = 1.0; data[15] = 1.0; return *this; } inline Matrix4F &Matrix4F::RotateX (const double ang) { memset (data, 0, 16*sizeof(VTYPE)); double c,s; c = cos(ang * 3.141592/180); s = sin(ang * 3.141592/180); data[0] = 1; data[5] = (VTYPE) c; data[6] = (VTYPE) s; data[9] = (VTYPE) -s; data[10] = (VTYPE) c; data[15] = 1; return *this; } // rotates points >>counter-clockwise<< when looking down the Y+ axis toward the origin inline Matrix4F &Matrix4F::RotateY (const double ang) { memset (data, 0, 16*sizeof(VTYPE)); double c,s; c = cos(ang * 3.141592/180); s = sin(ang * 3.141592/180); data[0] = (VTYPE) c; data[2] = (VTYPE) -s; data[5] = 1; data[8] = (VTYPE) s; data[10] = (VTYPE) c; data[15] = 1; return *this; } // rotates points >>counter-clockwise<< when looking down the Z+ axis toward the origin inline Matrix4F &Matrix4F::RotateZ (const double ang) { memset (data, 0, 16*sizeof(VTYPE)); double c,s; c = cos(ang * 3.141592/180); s = sin(ang * 3.141592/180); data[0] = (VTYPE) c; data[1] = (VTYPE) s; data[4] = (VTYPE) -s; data[5] = (VTYPE) c; data[10] = 1; data[15] = 1; return *this; } inline Matrix4F &Matrix4F::Ortho (double sx, double sy, double vn, double vf) { // simplified version of OpenGL's glOrtho function data[ 0] = (VTYPE) (1.0/sx);data[ 1] = (VTYPE) 0.0; data[ 2] = (VTYPE) 0.0; data[ 3]= (VTYPE) 0.0; data[ 4] = (VTYPE) 0.0; data[ 5] = (VTYPE) (1.0/sy);data[ 6] = (VTYPE) 0.0; data[ 7] = (VTYPE) 0.0; data[ 8] = (VTYPE) 0.0; data[ 9] = (VTYPE) 0.0; data[10]= (VTYPE) (-2.0/(vf-vn)); data[11] = (VTYPE) (-(vf+vn)/(vf-vn)); data[12] = (VTYPE) 0.0; data[13] = (VTYPE) 0.0; data[14] = (VTYPE) 0; data[15] = (VTYPE) 1.0; } inline Matrix4F &Matrix4F::Translate (double tx, double ty, double tz) { data[ 0] = (VTYPE) 1.0; data[ 1] = (VTYPE) 0.0; data[ 2] = (VTYPE) 0.0; data[ 3] = (VTYPE) 0.0; data[ 4] = (VTYPE) 0.0; data[ 5] = (VTYPE) 1.0; data[ 6] = (VTYPE) 0.0; data[ 7] = (VTYPE) 0.0; data[ 8] = (VTYPE) 0.0; data[ 9] = (VTYPE) 0.0; data[10] = (VTYPE) 1.0; data[11] = (VTYPE) 0.0; data[12] = (VTYPE) tx; data[13] = (VTYPE) ty; data[14] = (VTYPE) tz; data[15] = (VTYPE) 1.0; return *this; } inline Matrix4F &Matrix4F::Basis (const Vector3DF &c1, const Vector3DF &c2, const Vector3DF &c3) { data[ 0] = (VTYPE) c1.x; data[ 1] = (VTYPE) c2.x; data[ 2] = (VTYPE) c3.x; data[ 3] = (VTYPE) 0.0; data[ 4] = (VTYPE) c1.y; data[ 5] = (VTYPE) c2.y; data[ 6] = (VTYPE) c3.y; data[ 7] = (VTYPE) 0.0; data[ 8] = (VTYPE) c1.z; data[ 9] = (VTYPE) c2.z; data[10] = (VTYPE) c3.z; data[11] = (VTYPE) 0.0; data[12] = (VTYPE) 0.0; data[13] = (VTYPE) 0.0; data[14] = (VTYPE) 0.0; data[15] = (VTYPE) 1.0; return *this; } inline Matrix4F &Matrix4F::SRT (const Vector3DF &c1, const Vector3DF &c2, const Vector3DF &c3, const Vector3DF& t, const Vector3DF& s) { data[ 0] = (VTYPE) c1.x*s.x; data[ 1] = (VTYPE) c2.x*s.x; data[ 2] = (VTYPE) c3.x*s.x; data[ 3] = (VTYPE) 0.0; data[ 4] = (VTYPE) c1.y*s.y; data[ 5] = (VTYPE) c2.y*s.y; data[ 6] = (VTYPE) c3.y*s.y; data[ 7] = (VTYPE) 0.0; data[ 8] = (VTYPE) c1.z*s.z; data[ 9] = (VTYPE) c2.z*s.z; data[10] = (VTYPE) c3.z*s.z; data[11] = (VTYPE) 0.0; data[12] = (VTYPE) t.x; data[13] = (VTYPE) t.y; data[14] = (VTYPE) t.z; data[15] = (VTYPE) 1.0; } inline Matrix4F &Matrix4F::SRT (const Vector3DF &c1, const Vector3DF &c2, const Vector3DF &c3, const Vector3DF& t, const float s) { data[ 0] = (VTYPE) c1.x*s; data[ 1] = (VTYPE) c1.y*s; data[ 2] = (VTYPE) c1.z*s; data[ 3] = (VTYPE) 0.0; data[ 4] = (VTYPE) c2.x*s; data[ 5] = (VTYPE) c2.y*s; data[ 6] = (VTYPE) c2.z*s; data[ 7] = (VTYPE) 0.0; data[ 8] = (VTYPE) c3.x*s; data[ 9] = (VTYPE) c3.y*s; data[10] = (VTYPE) c3.z*s; data[11] = (VTYPE) 0.0; data[12] = (VTYPE) t.x; data[13] = (VTYPE) t.y; data[14] = (VTYPE) t.z; data[15] = (VTYPE) 1.0; return *this; } inline Matrix4F &Matrix4F::InvTRS (const Vector3DF &c1, const Vector3DF &c2, const Vector3DF &c3, const Vector3DF& t, const Vector3DF& s) { data[ 0] = (VTYPE) c1.x/s.x; data[ 1] = (VTYPE) c1.y/s.y; data[ 2] = (VTYPE) c1.z/s.z; data[ 3] = (VTYPE) 0.0; data[ 4] = (VTYPE) c2.x/s.x; data[ 5] = (VTYPE) c2.y/s.y; data[ 6] = (VTYPE) c2.z/s.z; data[ 7] = (VTYPE) 0.0; data[ 8] = (VTYPE) c3.x/s.x; data[ 9] = (VTYPE) c3.y/s.y; data[10] = (VTYPE) c3.z/s.z; data[11] = (VTYPE) 0.0; data[12] = (VTYPE) -t.x/s.x; data[13] = (VTYPE) -t.y/s.y; data[14] = (VTYPE) -t.z/s.z; data[15] = (VTYPE) 1.0; } inline Matrix4F &Matrix4F::InvTRS (const Vector3DF &c1, const Vector3DF &c2, const Vector3DF &c3, const Vector3DF& t, const float s) { data[ 0] = (VTYPE) c1.x/s; data[ 1] = (VTYPE) c1.y/s; data[ 2] = (VTYPE) c1.z/s; data[ 3] = (VTYPE) 0.0; data[ 4] = (VTYPE) c2.x/s; data[ 5] = (VTYPE) c2.y/s; data[ 6] = (VTYPE) c2.z/s; data[ 7] = (VTYPE) 0.0; data[ 8] = (VTYPE) c3.x/s; data[ 9] = (VTYPE) c3.y/s; data[10] = (VTYPE) c3.z/s; data[11] = (VTYPE) 0.0; data[12] = (VTYPE) -t.x/s; data[13] = (VTYPE) -t.y/s; data[14] = (VTYPE) -t.z/s; data[15] = (VTYPE) 1.0; } inline float Matrix4F::GetF (const int r, const int c) {return (float) data[ (r<<2) + c];} inline void Matrix4F::GetRowVec (int r, Vector3DF &v) { v.x = data[ (r<<2) ]; v.y = data[ (r<<2)+1 ]; v.z = data[ (r<<2)+2 ]; } #undef VTYPE #undef VNAME