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
1.5.6