Matrix.inl

Go to the documentation of this file.
00001 /**<!-------------------------------------------------------------------->
00002    @file   Matrix.inl
00003    @author Travis Fischer (fisch0920@gmail.com)
00004    @date   Fall 2008
00005    
00006    @brief
00007       Provides basic functionality for a templated, arbitrarily-sized matrix
00008    
00009    A Matrix is templated to store M rows and N columns of data of 
00010    type T.  If left off, T will default to a "real_t" data type. Also, if N 
00011    is not specified, the template will default to a square MxM matrix.
00012    
00013    Included in this definition are typedefs for the most commonly used 
00014    matrices (4x4, 3x3, etc), and these can be thought of as shortcuts to 
00015    reference their associated Matrix templates.  For example, 
00016    Matrix4x4 can be used to refer to Matrix<4, 4, real_t>.
00017    
00018    A Matrix stores each of its M rows internally as an 
00019    N-length Vector called rows which has been defined as:
00020    
00021       Vector<N, T> rows[M];
00022    <!-------------------------------------------------------------------->**/
00023 
00024 #ifndef MATRIX_INL_
00025 #define MATRIX_INL_
00026 
00027 #include <iostream>
00028 using namespace std;
00029 
00030 
00031 // Constructors
00032 // ------------
00033 
00034 // Expects arguments in row-major order
00035 // (srcData is a pointer to an M*N-length array of type T)
00036 template <unsigned M, unsigned N, typename T>
00037 inline Matrix<M, N, T>::Matrix(const T *srcData) {
00038    memcpy(rows, srcData, MATRIX_SIZE);
00039 }
00040 
00041 // Constructs an zero Matrix
00042 template <unsigned M, unsigned N, typename T>
00043 inline Matrix<M, N, T>::Matrix() {
00044    memset(rows, 0, MATRIX_SIZE);
00045 }
00046 
00047 // Copy Constructor; should copy the underlying data from m to this matrix
00048 template <unsigned M, unsigned N, typename T>
00049 inline Matrix<M, N, T>::Matrix(const Matrix &m) {
00050    memcpy(rows, m.rows, MATRIX_SIZE);
00051 }
00052 
00053 
00054 // Accessor Operators
00055 // ------------------
00056 
00057 // @returns a const reference to the row at the given index
00058 template <unsigned M, unsigned N, typename T>
00059 inline const Vector<N, T>   &Matrix<M, N, T>::operator[](const unsigned rowIndex) const
00060 {
00061    ASSERT(rowIndex < M);
00062    return rows[rowIndex];
00063 }
00064 
00065 // @returns a reference to the row at the given index
00066 // @note changes to the returned vector will affect this matrix
00067 template <unsigned M, unsigned N, typename T>
00068 inline       Vector<N, T>   &Matrix<M, N, T>::operator[](const unsigned rowIndex)
00069 {
00070    ASSERT(rowIndex < M);
00071    return rows[rowIndex];
00072 }
00073 
00074 // @returns a const pointer to the raw, underlying data
00075 //    (row-major, M*N-length array of type T)
00076 template <unsigned M, unsigned N, typename T>
00077 inline const T    *Matrix<M, N, T>::operator* () const {
00078    return (T*)this;
00079 }
00080 
00081 // @returns a pointer to the raw, underlying data
00082 //    (row-major, M*N-length array of type T)
00083 template <unsigned M, unsigned N, typename T>
00084 inline       T    *Matrix<M, N, T>::operator* () {
00085    return (T*)this;
00086 }
00087  
00088    
00089 // Equality Operators
00090 // ------------------
00091 
00092 
00093 // Evaluates whether or not this matrix is the same as the matrix m.
00094 // This is an example of operator overloading in which the Matrix class
00095 // _overloads_ the "==" operator.  Consider the following code snippet:
00096 //    Matrix a,b;
00097 //    ...
00098 //    bool matrixEquality = (a == b);
00099 // Then (a == b) calls this method on the object a with the argument b.
00100 template <unsigned M, unsigned N, typename T>
00101 inline       bool       Matrix<M, N, T>::operator==(const Matrix<M, N, T> &m) const
00102 {
00103    for(unsigned i = M; i--;) {
00104       if ((*this)[i] != m[i])
00105          return false;
00106    }
00107    
00108    return true;
00109 }
00110 
00111 // Evaluates whether or not this matrix is not equal to the matrix m.
00112 template <unsigned M, unsigned N, typename T>
00113 inline       bool       Matrix<M, N, T>::operator!=(const Matrix<M, N, T> &m) const
00114 {
00115    return !((*this) == m);
00116 }
00117 
00118 
00119 // Mutator Operators
00120 // -----------------
00121 
00122 // Assigns the contents of this matrix to the contents of matrix m. This function is executed
00123 // when the equals operator is used to assign a Matrix<M,N,T> to a Matrix<M,N,T>
00124 template <unsigned M, unsigned N, typename T>
00125 inline       Matrix<M, N, T> &Matrix<M, N, T>::operator =(const Matrix<M, N, T> &m)
00126 {
00127    memcpy(rows, m.rows, MATRIX_SIZE);
00128    
00129    return *this;
00130 }
00131 
00132 template <unsigned M, unsigned N, typename T>
00133 inline       Matrix<M, N, T> &Matrix<M, N, T>::operator+=(const Matrix<M, N, T> &rhs)
00134 {
00135    for(unsigned i = M; i--;)
00136       rows[i] += rhs[i];
00137    
00138    return *this;
00139 }
00140 
00141 template <unsigned M, unsigned N, typename T>
00142 inline       Matrix<M, N, T> &Matrix<M, N, T>::operator-=(const Matrix<M, N, T> &rhs)
00143 {
00144    for(unsigned i = M; i--;)
00145       rows[i] -= rhs[i];
00146    
00147    return *this;
00148 }
00149 
00150 template <unsigned M, unsigned N, typename T>
00151 inline       Matrix<M, N, T> &Matrix<M, N, T>::operator*=(const Matrix<M, N, T> &rhs)
00152 {
00153    T d[M * N];
00154    
00155    for(unsigned i = M * N; i--;)
00156       d[i] = row(i / N).dot(rhs.col(i % N));
00157    
00158    memcpy(rows, d, MATRIX_SIZE);
00159    return *this;
00160 }
00161 
00162 
00163 // Scalar Mutator Operators
00164 template <unsigned M, unsigned N, typename T>
00165 inline       Matrix<M, N, T> &Matrix<M, N, T>::operator*=(const T &scale)
00166 {
00167    for(unsigned i = M; i--;)
00168       rows[i] *= scale;
00169    
00170    return *this;
00171 }
00172 
00173 template <unsigned M, unsigned N, typename T>
00174 inline       Matrix<M, N, T> &Matrix<M, N, T>::operator/=(const T &scale)
00175 {
00176    ASSERT(NEQ(scale, 0));
00177    
00178    for(unsigned i = M; i--;)
00179       rows[i] /= scale;
00180    
00181    return *this;
00182 }
00183 
00184 
00185 // Arithmetic Operators
00186 // -----------------
00187 template <unsigned M, unsigned N, typename T>
00188 inline       Matrix<M, N, T>  Matrix<M, N, T>::operator+ (const Matrix<M, N, T> &rhs) const
00189 {
00190    Matrix<M, N, T> ret;
00191    
00192    for(unsigned i = M; i--;)
00193       ret[i] = rows[i] + rhs[i];
00194    
00195    return ret;
00196 }
00197 
00198 template <unsigned M, unsigned N, typename T>
00199 inline       Matrix<M, N, T>  Matrix<M, N, T>::operator- (const Matrix<M, N, T> &rhs) const
00200 {
00201    Matrix<M, N, T> ret;
00202    
00203    for(unsigned i = M; i--;)
00204       ret[i] = rows[i] - rhs[i];
00205    
00206    return ret;
00207 }
00208 
00209 // MxN (square) matrix * MxN (square) matrix yields an MxN (square) matrix
00210 template <unsigned M, unsigned N, typename T>
00211 inline       Matrix<M, N, T>  Matrix<M, N, T>::operator* (const Matrix<M, N, T> &rhs) const
00212 {
00213    Matrix<M, N, T> ret = (*this);
00214    
00215    ret *= rhs;
00216    return ret;
00217 }
00218 
00219 // MxN matrix * N-length column vector yields an M-length vector
00220 // @note this method returns an M-length Vector. Make sure you understand why.
00221 template <unsigned M, unsigned N, typename T>
00222 inline       Point<M, T>     Matrix<M, N, T>::operator* (const Point<N, T> &rhs) const
00223 {
00224    Point<M, T> ret;
00225    ret[M - 1] = 0;
00226    
00227    for(unsigned i = M; i--;)
00228       for(unsigned j = N; j--;)
00229          ret[i] += rows[i][j] * rhs[j];
00230    
00231    return ret;
00232 }
00233 
00234 // MxN matrix * N-length column vector yields an M-length vector
00235 // @note this method returns an M-length Vector. Make sure you understand why.
00236 template <unsigned M, unsigned N, typename T>
00237 inline       Vector<M, T>     Matrix<M, N, T>::operator* (const Vector<N, T> &rhs) const
00238 {
00239    Vector<M, T> ret;
00240    
00241    for(unsigned i = M; i--;)
00242       ret[i] = rows[i].dot(rhs);
00243    
00244    return ret;
00245 }
00246 
00247 template <unsigned M, unsigned N, typename T>
00248 inline       Vector<M - 1, T>     Matrix<M, N, T>::operator* (const Vector<N - 1, T> &rhs) const
00249 {
00250    Vector<M - 1, T> ret;
00251    
00252    for(unsigned i = M - 1; i--;)
00253       for(unsigned j = N - 1; j--;)
00254          ret[i] += rows[i][j] * rhs[j];
00255    
00256    return ret;
00257 }
00258 
00259 
00260 // Scalar Arithmetic Operators
00261 template <unsigned M, unsigned N, typename T>
00262 inline       Matrix<M, N, T>  Matrix<M, N, T>::operator* (const T &scale) const
00263 {
00264    Matrix<M, N, T> ret;
00265    
00266    for(unsigned i = M; i--;)
00267       ret[i] = rows[i] * scale;
00268    
00269    return ret;
00270 }
00271 
00272 template <unsigned M, unsigned N, typename T>
00273 inline       Matrix<M, N, T>  Matrix<M, N, T>::operator/ (const T &scale) const
00274 {
00275    Matrix<M, N, T> ret;
00276    ASSERT(NEQ(scale, 0));
00277    
00278    for(unsigned i = M; i--;)
00279       ret[i] = rows[i] / scale;
00280    
00281    return ret;
00282 }
00283 
00284 
00285 // More Complex Functionality
00286 // --------------------------
00287 
00288 // @returns whether or not this Matrix is diagonal
00289 template <unsigned M, unsigned N, typename T>
00290 inline bool Matrix<M, N, T>::isDiagonal() const {
00291    for(unsigned i = M; i--;)
00292       for(unsigned j = N; j--;)
00293          if (i != j && NEQ((*this)[i][j], 0))
00294             return false;
00295    
00296    return true;
00297 }
00298 
00299 // @returns a Vector containing the index'th row of this matrix
00300 // Modifying the Vector returned will directly affect this Matrix's data
00301 template <unsigned M, unsigned N, typename T>
00302 inline Vector<N, T> &Matrix<M, N, T>::row(unsigned index) {
00303    ASSERT(index < M);
00304    
00305    return rows[index];
00306 }
00307 
00308 // @returns a Vector containing the index'th row of this matrix
00309 // Modifying the Vector returned will Not affect this Matrix's data
00310 template <unsigned M, unsigned N, typename T>
00311 inline Vector<N, T>  Matrix<M, N, T>::row(unsigned index) const {
00312    ASSERT(index < M);
00313    
00314    return Vector<N, T>(rows[index]);
00315 }
00316 
00317 // @returns a Vector containing the index'th column of this matrix
00318 // Modifying the Vector returned will Not affect this Matrix's data
00319 template <unsigned M, unsigned N, typename T>
00320 inline Vector<M, T>  Matrix<M, N, T>::col(unsigned index) const {
00321    ASSERT(index < N);
00322    T temp[M];
00323 
00324    for(unsigned i = M; i--;)
00325       temp[i] = rows[i][index];
00326    
00327    return Vector<M, T>(temp);
00328 }
00329 
00330 // Sets the index'th column of this matrix to the given Vector
00331 template <unsigned M, unsigned N, typename T>
00332 inline Matrix<M, N, T> &Matrix<M, N, T>::setCol(
00333       unsigned index, const Vector<M, T> &vec)
00334 {
00335    ASSERT(index < N);
00336    
00337    for(unsigned i = M; i--;)
00338       rows[i][index] = vec[i];
00339    
00340    return (*this);
00341 }
00342 
00343 
00344 // Extra operators where Matrix is on right-hand side
00345 // -----------------------------------------------------
00346 
00347 // 1xM row vector * MxN matrix yields a 1xN vector
00348 template <unsigned M, unsigned N, typename T>
00349 inline Vector<N, T> operator* (const Vector<M, T> &lhs, const Matrix<M, N, T> &rhs)
00350 {
00351    T temp[N];
00352    
00353    for(unsigned j = N; j--;)
00354       temp[j] = lhs.dot(rhs.col(j));
00355    
00356    return Vector<N, T>(temp);
00357 }
00358 
00359 // @returns the MxN matrix resulting from multiplying a scalar by an MxN matrix
00360 template <unsigned M, unsigned N, typename T>
00361 inline Matrix<M, N, T> operator* (const T &scale, const Matrix<M, N, T> &rhs)
00362 {
00363    return rhs * scale;
00364 }
00365 
00366 // Prints a Matrix to an output stream
00367 template <unsigned M, unsigned N, typename T>
00368 inline std::ostream &operator<<(std::ostream &os, const Matrix<M, N, T> &m)
00369 {
00370    os << "[ ";
00371    
00372    for(unsigned i = 0; i < M; ++i)
00373       os << m[i] << (i < M - 1 ? " " : "");
00374    
00375    os << " ]";
00376    
00377    return os;
00378 }
00379 
00380 
00381 // @returns the transpose of this matrix
00382 template <unsigned M, unsigned N, typename T>
00383 const Matrix<M, N, T> Matrix<M, N, T>::getTranspose() const {
00384    ASSERT(M == N);
00385    T temp[M * N];
00386    
00387    for(unsigned i = M; i--;)
00388       for(unsigned j = N; j--;)
00389          temp[i * N + j] = (*this)[j][i];
00390    
00391    return Matrix<M, N, T>(temp);
00392 }
00393 
00394 /*
00395  * Fills the data provided with the transpose of this matrix (since OpenGL 
00396  * matrices are stored in column-major format).
00397  */
00398 template <unsigned M, unsigned N, typename T>
00399 void Matrix<M, N, T>::fillGLMatrix(T *bufferToFill) const {
00400    ASSERT(M == N && M == 4);
00401    
00402    for(unsigned i = M; i--;)
00403       for(unsigned j = N; j--;)
00404          bufferToFill[i * N + j] = (*this)[j][i];
00405 }
00406 
00407 /*
00408  * @returns true if this matrix is strictly upper-triangular. An upper-
00409  *    triangular matrix contains only zeros below its diagonal (but may 
00410  *    contain non-zero values on and above its diagonal).
00411  * 
00412  * Example 4x4 upper triangular matrix:
00413  *    [ 1 2 3 4 ] 
00414  *    [ 0 5 6 7 ]
00415  *    [ 0 0 0 8 ] 
00416  *    [ 0 0 0 9 ]
00417  *
00418  * Example 4x4 non upper triangular matrix:
00419  *    [ 1 2 3 4 ]
00420  *    [ 0 5 6 7 ]
00421  *    [ 8 0 0 9 ]
00422  *    [ 0 0 0 0 ]
00423  */
00424 template <unsigned M, unsigned N, typename T>
00425 bool Matrix<M, N, T>::isUpperTriangular() const {
00426    for(unsigned i = M; i--;)
00427       for(unsigned j = i; j--;)
00428          if (NEQ((*this)[i][j], 0))
00429             return false;
00430    
00431    return true;
00432 }
00433 
00434 /*
00435  * @returns true if this matrix is strictly lower-triangular. An lower-
00436  *    triangular matrix contains only zeros above its diagonal (but may 
00437  *    contain non-zero values on and below its diagonal).
00438  * 
00439  * Example 4x4  triangular matrix:
00440  *    [ 1 0 0 0 ] 
00441  *    [ 2 3 0 0 ]
00442  *    [ 4 5 0 0 ] 
00443  *    [ 6 7 8 9 ]
00444  *
00445  * Example 4x4 non upper triangular matrix:
00446  *    [ 1 0 0 2 ]
00447  *    [ 3 4 0 5 ]
00448  *    [ 6 7 8 0 ]
00449  *    [ 0 0 0 0 ]
00450  */
00451 template <unsigned M, unsigned N, typename T>
00452 bool Matrix<M, N, T>::isLowerTriangular() const {
00453    for(unsigned i = M; i--;)
00454       for(unsigned j = i + 1; j < N; ++j)
00455          if (NEQ((*this)[i][j], 0))
00456             return false;
00457    
00458    return true;
00459 }
00460 
00461 // @returns the inverse of this matrix, assuming it exists
00462 template <unsigned M, unsigned N, typename T>
00463 Matrix<M, N, T> Matrix<M, N, T>::getInverse() const {
00464    const T &det = getDeterminant();
00465    
00466    if (EQ(det, 0)) {
00467       printf("Matrix not invertible. Returning the identity matrix.\n");
00468       return Matrix<M, N, T>();
00469    }
00470    
00471    const real_t &invDet = create_real(1) / det;
00472    
00473    // Ensure matrix is not singular
00474    if (M == N && M == 3) {
00475       return invDet * Matrix<M, N, T>(
00476          // Column 1
00477          ((*this)[2][2] * (*this)[1][1] - (*this)[2][1] * (*this)[1][2]), 
00478          -((*this)[2][2] * (*this)[0][1] - (*this)[2][1] * (*this)[0][2]), 
00479          ((*this)[1][2] * (*this)[0][1] - (*this)[1][1] * (*this)[0][2]), 
00480          
00481          // Column 2
00482          -((*this)[2][2] * (*this)[1][0] - (*this)[2][0] * (*this)[1][2]), 
00483          ((*this)[2][2] * (*this)[0][0] - (*this)[2][0] * (*this)[0][2]), 
00484          -((*this)[1][2] * (*this)[0][0] - (*this)[1][0] * (*this)[0][2]), 
00485          
00486          // Column 3
00487          ((*this)[2][1] * (*this)[1][0] - (*this)[2][0] * (*this)[1][1]), 
00488          -((*this)[2][1] * (*this)[0][0] - (*this)[2][0] * (*this)[0][1]), 
00489          ((*this)[1][1] * (*this)[0][0] - (*this)[1][0] * (*this)[0][1]));
00490    } else if (N == 4) {
00491       const T *data = (**this);
00492       
00493       const T &a = data[0];
00494       const T &b = data[1];
00495       const T &c = data[2];
00496       const T &d = data[3];
00497       const T &e = data[4];
00498       const T &f = data[5];
00499       const T &g = data[6];
00500       const T &h = data[7];
00501       const T &i = data[8];
00502       const T &j = data[9];
00503       const T &k = data[10];
00504       const T &l = data[11];
00505       const T &m = data[12];
00506       const T &n = data[13];
00507       const T &o = data[14];
00508       const T &p = data[15];
00509       
00510       return Matrix<M, N, T>(
00511          (-h*k*n + g*l*n + h*j*o - f*l*o - g*j*p + f*k*p) * invDet, 
00512          (d*k*n - c*l*n - d*j*o + b*l*o + c*j*p - b*k*p) * invDet, 
00513          (-d*g*n + c*h*n + d*f*o - b*h*o - c*f*p + b*g*p) * invDet, 
00514          (d*g*j - c*h*j - d*f*k + b*h*k + c*f*l - b*g*l) * invDet, 
00515          
00516          (h*k*m - g*l*m - h*i*o + e*l*o + g*i*p - e*k*p) * invDet, 
00517          (-d*k*m + c*l*m + d*i*o - a*l*o - c*i*p + a*k*p) * invDet, 
00518          (d*g*m - c*h*m - d*e*o + a*h*o + c*e*p - a*g*p) * invDet, 
00519          (-d*g*i + c*h*i + d*e*k - a*h*k - c*e*l + a*g*l) * invDet, 
00520          
00521          (-h*j*m + f*l*m + h*i*n - e*l*n - f*i*p + e*j*p) * invDet, 
00522          (d*j*m - b*l*m - d*i*n + a*l*n + b*i*p - a*j*p) * invDet, 
00523          (-d*f*m + b*h*m + d*e*n - a*h*n - b*e*p + a*f*p) * invDet, 
00524          (d*f*i - b*h*i - d*e*j + a*h*j + b*e*l - a*f*l) * invDet, 
00525          
00526          (g*j*m - f*k*m - g*i*n + e*k*n + f*i*o - e*j*o) * invDet, 
00527          (-c*j*m + b*k*m + c*i*n - a*k*n - b*i*o + a*j*o) * invDet, 
00528          (c*f*m - b*g*m - c*e*n + a*g*n + b*e*o - a*f*o) * invDet, 
00529          (-c*f*i + b*g*i + c*e*j - a*g*j - b*e*k + a*f*k) * invDet);
00530    }
00531    
00532    // TODO!!!
00533    ASSERT(0 && "Not yet Implemented"); // Matrix::getInverse for N != 3 or 4
00534 }
00535 
00536 // @returns the determinant of this matrix
00537 template <unsigned M, unsigned N, typename T>
00538 T Matrix<M, N, T>::getDeterminant() const {
00539    ASSERT(M == N && "Matrix::getDeterminant() is only defined for square matrices!\n");
00540    
00541    if (M == 3) {
00542       // (row-major indexing)
00543       return 
00544          (*this)[0][0] * ((*this)[1][1] * (*this)[2][2] - (*this)[1][2] * (*this)[2][1]) + 
00545         -(*this)[0][1] * ((*this)[1][0] * (*this)[2][2] - (*this)[1][2] * (*this)[2][0]) + 
00546          (*this)[0][2] * ((*this)[1][0] * (*this)[2][1] - (*this)[1][1] * (*this)[2][0]);
00547    } else if (M == 4) {
00548       const T *data = (**this);
00549       
00550       const T &a = data[0];
00551       const T &b = data[1];
00552       const T &c = data[2];
00553       const T &d = data[3];
00554       const T &e = data[4];
00555       const T &f = data[5];
00556       const T &g = data[6];
00557       const T &h = data[7];
00558       const T &i = data[8];
00559       const T &j = data[9];
00560       const T &k = data[10];
00561       const T &l = data[11];
00562       const T &m = data[12];
00563       const T &n = data[13];
00564       const T &o = data[14];
00565       const T &p = data[15];
00566       
00567       return 
00568          d*g*j*m - c*h*j*m - d*f*k*m + b*h*k*m + c*f*l*m - b*g*l*m - d*g*i*n + 
00569          c*h*i*n + d*e*k*n - a*h*k*n - c*e*l*n + a*g*l*n + d*f*i*o - b*h*i*o - 
00570          d*e*j*o + a*h*j*o + b*e*l*o - a*f*l*o - c*f*i*p + b*g*i*p + c*e*j*p - 
00571          a*g*j*p - b*e*k*p + a*f*k*p;
00572    }
00573    
00574    ASSERT(0 && "Not yet Implemented"); // Matrix::getInverse for N != 3 or 4
00575 }
00576 
00577 // Cleans up a matrix (0's out entries that are less than epsilon)
00578 template <unsigned M, unsigned N, typename T>
00579 void Matrix<M, N, T>::cleanup() {
00580    for (unsigned i = M; i --;)
00581       rows[i].cleanup();
00582 }
00583 
00584 // Convenience Constructor
00585 template <unsigned M, unsigned N, typename T>
00586 Matrix<M, N, T>::Matrix(const T &v0,  const T &v1,  const T &v2, 
00587                                   const T &v3,  const T &v4,  const T &v5, 
00588                                   const T &v6,  const T &v7,  const T &v8, 
00589                                   const T &v9,  const T &v10, const T &v11, 
00590                                   const T &v12, const T &v13, const T &v14, 
00591                                   const T &v15)
00592 {
00593    if (M == 4 && N == 4) {
00594       (*this)[0][0] = v0;
00595       (*this)[0][1] = v1;
00596       (*this)[0][2] = v2;
00597       (*this)[0][3] = v3;
00598       (*this)[1][0] = v4;
00599       (*this)[1][1] = v5;
00600       (*this)[1][2] = v6;
00601       (*this)[1][3] = v7;
00602       (*this)[2][0] = v8;
00603       (*this)[2][1] = v9;
00604       (*this)[2][2] = v10;
00605       (*this)[2][3] = v11;
00606       (*this)[3][0] = v12;
00607       (*this)[3][1] = v13;
00608       (*this)[3][2] = v14;
00609       (*this)[3][3] = v15;
00610    } else if (M == 3 && N == 3) {
00611       (*this)[0][0] = v0;
00612       (*this)[0][1] = v1;
00613       (*this)[0][2] = v2;
00614       (*this)[1][0] = v3;
00615       (*this)[1][1] = v4;
00616       (*this)[1][2] = v5;
00617       (*this)[2][0] = v6;
00618       (*this)[2][1] = v7;
00619       (*this)[2][2] = v8;
00620    } else {
00621       // TODO (optional) handle other cases
00622       ASSERT(0 && "Not yet implemented: Convenience constructor is only "
00623                   "currently implemented for 3x3 and 4x4 matrices\n");
00624    }
00625 }
00626 
00627 #endif // MATRIX_INL_
00628 

Generated on 28 Feb 2009 for Milton by doxygen 1.5.6