00001
00020 #pragma once
00021
00022 #include "standard.h"
00023
00024 #pragma warning( push, 3 )
00025 #include <numeric>
00026 #include <xutility>
00027 #pragma warning ( pop )
00028
00029 #include <malloc.h>
00030 #include <assert.h>
00031
00033 #ifndef COMPILETIME_ASSERT
00034 #define COMPILETIME_ASSERT(assertion) do { if (0) { char ch[(assertion)] = { 'a' }; ch;} } while (false)
00035 #endif
00036
00037
00038 #pragma warning ( disable:4127 ) // conditional expression is constant
00039
00040
00041
00042
00043
00045 template < int cols, int rows, typename T >
00046 class Matrix;
00047
00049 template< int size, typename T >
00050 class SymmetricMatrix;
00051
00053 template< int height, typename T >
00054 class ColVector;
00055
00056
00061 template< int size, typename T >
00062 class DataBlock
00063 {
00064 protected:
00065
00066 inline DataBlock() {}
00067 inline DataBlock<size,T> add(const DataBlock< size, T > &d) const
00068 {
00069 DataBlock<size,T> rtn;
00070
00071 for (int i = 0; i < size; i++)
00072 rtn.array[i] = array[i] + d.array[i];
00073
00074 return rtn;
00075 }
00076
00077 inline void addToMe(const DataBlock< size, T> &d)
00078 {
00079 for (int i = 0; i < size; i++)
00080 array[i] = array[i] + d.array[i];
00081 }
00082
00083 inline void subtractFromMe(const DataBlock< size, T> &d)
00084 {
00085 for (int i = 0; i < size; i++)
00086 array[i] = array[i] - d[i];
00087 }
00088
00089 inline DataBlock<size,T> subtract (const DataBlock< size, T> &d) const
00090 {
00091 DataBlock<size,T> rtn;
00092 for (int i = 0; i < size; i++)
00093 rtn.array[i] = array[i] - d.array[i];
00094
00095 return rtn;
00096 }
00097
00098 inline bool isEqualTo (const DataBlock< size, T> &d) const
00099 {
00100 return (memcmp (array, d.array, sizeof(array)) == 0);
00101 }
00102
00103 inline void copyFrom (const DataBlock<size, T> &d)
00104 {
00105 memcpy (&array[0], &d.array[0], sizeof(array));
00106 }
00107
00108
00109
00110 inline DataBlock<size,T> multiply (int n) const
00111 {
00112 DataBlock<size,T> rtn;
00113 for (int i = 0; i < size; i++)
00114 rtn.array[i] = array[i] * n;
00115
00116 return rtn;
00117 }
00118
00119 inline DataBlock<size,T> multiply (float n) const
00120 {
00121 DataBlock<size,T> rtn;
00122 for (int i = 0; i < size; i++)
00123 rtn.array[i] = array[i] * n;
00124
00125 return rtn;
00126 }
00127
00128
00129 inline DataBlock<size,T> multiply (double n) const
00130 {
00131 DataBlock<size,T> rtn;
00132 for (int i = 0; i < size; i++)
00133 rtn.array[i] = (T)(array[i] * n);
00134
00135 return rtn;
00136 }
00137
00138
00139
00140 inline DataBlock<size,T> divide (int n) const
00141 {
00142 DataBlock<size,T> rtn;
00143 T inverse = 1. / n;
00144
00145 for (int i = 0; i < size; i++)
00146 rtn.array[i] = array[i] * inverse;
00147
00148 return rtn;
00149 }
00150
00151 inline DataBlock<size,T> divide (float n) const
00152 {
00153 DataBlock<size,T> rtn;
00154 T inverse = 1. / n;
00155
00156 for (int i = 0; i < size; i++)
00157 rtn.array[i] = array[i] * inverse;
00158
00159 return rtn;
00160 }
00161
00162 inline DataBlock<size,T> divide (double n) const
00163 {
00164 DataBlock<size,T> rtn;
00165
00166 T inverse = (T)(1. / n);
00167
00168 for (int i = 0; i < size; i++)
00169 rtn.array[i] = array[i] * inverse;
00170
00171 return rtn;
00172 }
00173
00174
00175 T array[size];
00176 public:
00177
00178 inline T * getData()
00179 { return array; }
00180
00181 inline setToZero()
00182 {
00183 memset(array, 0, sizeof(array));
00184 }
00185 };
00186
00189 #define TRIANGULAR(i) ( ((i + 1)*i) / 2)
00190
00203 template< int size, typename T >
00204 class SymmetricMatrix : public DataBlock< TRIANGULAR(size), T >
00205 {
00206 private:
00207 typedef SymmetricMatrix< size, T > _Myt;
00208 typedef DataBlock< TRIANGULAR(size), T > parentType;
00209 typedef Matrix< size, size, T > MtxAsymmetric;
00210
00211 public:
00212
00213 SymmetricMatrix() {}
00214 SymmetricMatrix(const parentType &p) {copyFrom (p);}
00215 SymmetricMatrix(const MtxAsymmetric &m)
00216 {
00217 this->operator=(m);
00218 }
00219 const enum {nColumns = size};
00220 const enum {nRows = size};
00221
00222
00223
00224 _Myt operator-(const _Myt &m) const { return this->subtract(m);}
00225 _Myt operator+(const _Myt &m) const { return this->add(m);}
00226 _Myt operator*(int n) const { return this->multiply(n); }
00227 _Myt operator*(float f) const { return this->multiply(f); }
00228 _Myt operator*(double f) const { return this->multiply(f); }
00229 _Myt operator/(int n) const { return this->divide(n); }
00230 _Myt operator/(float n) const { return this->divide(n); }
00231 _Myt operator/(double n) const { return this->divide(n); }
00232 bool operator==(_Myt &m) const { return this->isEqualTo (m); }
00233 void operator+=(_Myt &m) { this->addToMe (m); }
00234 void operator-=(_Myt &m) { this->subtractFromMe (m); }
00235 void operator=(const _Myt &m) { this->copyFrom (m); }
00236 inline T & operator()(int col, int row) { return elementAt(col,row);}
00237 inline T & operator[](int n) { return array[n]; }
00238 inline T operator[](int n) const { return array[n]; }
00239 void print(char *str = "") const { printMatrix(*this,str); }
00240
00241 template <int N>
00242 Matrix< N, nRows, T> operator* (const SymmetricMatrix<N, T> &m) const
00243 {
00244
00245
00246
00247
00248 COMPILETIME_ASSERT (cols == N);
00249
00250 return multMatrix< _Myt, Matrix< N, N, T >, T, rows, N>(*this, m);
00251 }
00252
00253 template <int theirCols, int theirRows>
00254 Matrix< theirCols, nRows, T> operator* (const Matrix< theirCols, theirRows, T> &m) const
00255 {
00256
00257
00258
00259
00260 COMPILETIME_ASSERT (cols == theirRows);
00261
00262 return multMatrix< _Myt, Matrix< theirCols, theirRows, T >, T, nRows, theirCols>(*this, m);
00263 }
00264
00265
00266
00267 void operator=(const Matrix<size, size, T> &m)
00268 {
00269 for (int col = 0; col < nColumns; col++)
00270 for (int row = col; row < nRows; row++)
00271 elementAt (col,row) = m.elementAt(col,row);
00272 }
00273
00274 inline T & elementAt (int col, int row)
00275 {
00276 assert (col >= 0 && row >= 0 && col < nColumns && row < nRows);
00277
00278 return (col > row)?
00279 array[row*nRows + col - TRIANGULAR(row)]:
00280 array[col*nRows + row - TRIANGULAR(col)];
00281 }
00282
00283 inline T elementAt (int col, int row) const
00284 {
00285 assert (col >= 0 && row >= 0 && col < nColumns && row < nRows);
00286
00287 return (col > row)?
00288 array[row*nRows + col - TRIANGULAR(row)]:
00289 array[col*nRows + row - TRIANGULAR(col)];
00290 }
00291 };
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301 template < int cols, int rows, typename T >
00302 class Matrix : public DataBlock< cols*rows, T >
00303 {
00304 private:
00305 typedef Matrix< cols, rows, T > _Myt;
00306 typedef DataBlock< cols*rows, T> parentType;
00307 typedef SymmetricMatrix< cols, T > MtxSymmetric;
00308
00309 public:
00310 Matrix() {}
00311 Matrix(const parentType &p) {copyFrom (p);}
00312 Matrix(const MtxSymmetric &m)
00313 {
00314 COMPILETIME_ASSERT(nRows == nColumns);
00315 this->operator=(m);
00316 }
00317
00318 const enum {nColumns = cols};
00319 const enum {nRows = rows};
00320
00321
00322
00323 _Myt operator-(const _Myt &m) const { return this->subtract(m);}
00324 _Myt operator+(const _Myt &m) const { return this->add(m);}
00325 _Myt operator*(int n) const { return this->multiply(n); }
00326 _Myt operator*(float f) const { return this->multiply(f); }
00327 _Myt operator*(double f) const { return this->multiply(f); }
00328 _Myt operator/(int n) const { return this->divide(n); }
00329 _Myt operator/(float n) const { return this->divide(n); }
00330 _Myt operator/(double n) const { return this->divide(n); }
00331 bool operator==(_Myt &m) const { return this->isEqualTo (m); }
00332 void operator+=(_Myt &m) { this->addToMe (m); }
00333 void operator-=(_Myt &m) { this->subtractFromMe (m); }
00334 void operator=(const _Myt &m) { this->copyFrom (m); }
00335 inline T & operator()(int col, int row) { return elementAt(col,row);}
00336 inline T & operator[](int n) { return array[n]; }
00337 inline T operator[](int n) const { return array[n]; }
00338 void print(char *str = "") const { printMatrix(*this,str); }
00339
00340 template <int N>
00341 Matrix< N, nRows, T> operator* (const SymmetricMatrix<N, T> &m) const
00342 {
00343
00344
00345
00346
00347 COMPILETIME_ASSERT (cols == N);
00348
00349 return multMatrix< _Myt, Matrix< N, N, T >, T, rows, N>(*this, m);
00350 }
00351
00352 template <int theirCols, int theirRows>
00353 Matrix< theirCols, nRows, T> operator* (const Matrix< theirCols, theirRows, T> &m) const
00354 {
00355
00356
00357
00358
00359 COMPILETIME_ASSERT (cols==theirRows);
00360
00361 return multMatrix< _Myt, Matrix< theirCols, theirRows, T >, T, nRows, theirCols>(*this, m);
00362 }
00363
00364
00365 void operator=(const SymmetricMatrix<cols, T> &m)
00366 {
00367 for (int col = 0; col < cols; col++)
00368 for (int row = 0; row < rows; row++)
00369 elementAt (col,row) = m.elementAt (col,row);
00370 }
00371
00372
00373
00374 T determinant()
00375 {
00376 COMPILETIME_ASSERT(nRows==nColumns);
00377 COMPILETIME_ASSERT(nRows>1);
00378
00379 if (nRows == 1)
00380 {
00381 return 0;
00382 }
00383
00384 if (nRows == 2)
00385 {
00386 return (elementAt(0,0) * elementAt(1,1) -
00387 elementAt(1,0) * elementAt(0,1));
00388 }
00389
00390 T total = 0.;
00391 for (int i = 0; i < nColumns; i++)
00392 {
00393 Submatrix sub;
00394 sub = getSubmatrix(i, 0);
00395
00396 T det = sub.determinant();
00397
00398 if (0 == i % 2)
00399 total += det;
00400 else
00401 total -= det;
00402 }
00403
00404 return total;
00405 }
00406
00407 inline T & elementAt (int col, int row)
00408 {
00409 assert (col >= 0 && row >= 0 && col < nColumns && row < nRows);
00410
00411 return array[col*rows + row];
00412 }
00413
00414 inline T elementAt (int col, int row) const
00415 {
00416 assert (col >= 0 && row >= 0 && col < nColumns && row < nRows);
00417
00418 return array[col*rows + row];
00419 }
00420
00421 Matrix <rows, cols, T> getTranspose() const
00422 {
00423 Matrix<rows, cols, T> rtn;
00424 for (int row = 0; row < rows; row++)
00425 for (int col = 0; col < cols; col++)
00426 rtn(row,col) = elementAt(col,row);
00427
00428 return rtn;
00429 }
00430
00431
00432 void setToIdentity()
00433 {
00434 COMPILETIME_ASSERT(nRows==nColumns);
00435 setToZero();
00436
00437 for (int n = 0; n < cols; n++)
00438 elementAt (n,n) = 1;
00439 }
00440
00441 bool getInverse(Matrix<cols,rows,T> &answer) const
00442 {
00443 COMPILETIME_ASSERT(nRows==nColumns);
00444
00445 Matrix<cols,rows,T> mtx;
00446 mtx = *this;
00447 answer.setToIdentity();
00448
00449
00450 for (int col = 0; col < nColumns; col++)
00451 {
00452 int rowMax = col;
00453
00454 for (int row=col+1; row<nRows; row++)
00455 {
00456 if (mtx(row,col) > mtx(rowMax, col))
00457 rowMax = row;
00458 }
00459
00460 if (mtx(rowMax, col) == 0)
00461 {
00462 return false;
00463 }
00464
00465
00466 for (int cc=0; cc<nColumns; cc++)
00467 {
00468 T tmp = mtx(col,cc);
00469 mtx(col,cc) = mtx(rowMax,cc);
00470 mtx(rowMax,cc) = tmp;
00471 tmp = answer(col,cc);
00472 answer(col,cc) = answer(rowMax,cc);
00473 answer(rowMax,cc) = tmp;
00474 }
00475
00476
00477
00478 T tmp = mtx(col,col);
00479 for (cc=0; cc<nColumns; cc++)
00480 {
00481 mtx(col,cc) = mtx(col,cc) / tmp;
00482 answer(col,cc) = answer(col,cc) / tmp;
00483 }
00484
00485
00486 for (row = 0; row < nRows; row++)
00487 {
00488 if (row != col)
00489 {
00490 tmp = mtx (row,col);
00491 for (cc=0; cc<nColumns; cc++)
00492 {
00493 mtx(row,cc) = mtx(row,cc) - mtx(col,cc) * tmp;
00494 answer(row,cc) = answer(row,cc) - answer(col,cc)*tmp;
00495 }
00496 }
00497 }
00498
00499 }
00500 return true;
00501 }
00502
00503 private:
00504 typedef Matrix< (nColumns>2?nColumns-1:nColumns), (nRows>2?nRows-1:nRows), T > Submatrix;
00505 Submatrix getSubmatrix (int colToDelete, int rowToDelete)
00506 {
00507 COMPILETIME_ASSERT(nRows==nColumns);
00508 COMPILETIME_ASSERT(nRows>1);
00509
00510 Submatrix rtn;
00511
00512 int curSpot = 0;
00513 for (int col = 0; col < nColumns; col++)
00514 {
00515 for (int row = 0; row < nRows; row++)
00516 {
00517 if (row != rowToDelete && col != colToDelete)
00518 {
00519 rtn[curSpot] = elementAt(col,row);
00520 curSpot++;
00521 }
00522 }
00523 }
00524
00525 return rtn;
00526 }
00527 };
00528
00529
00530
00531
00532
00533
00534 template< int height, typename T >
00535 class ColVector : public Matrix< 1, height, T >
00536 {
00537 public:
00538 typedef Matrix<1,height,T> parentType;
00539 typedef ColVector< height, T > _Myt;
00540
00541 inline ColVector(parentType &p) { parentType::operator=(p); }
00542 inline void operator=(const parentType &p) { parentType::operator=(p); }
00543
00544
00545 template< typename C >
00546 inline _Myt operator/(const C n) const { return parentType::operator/(n); }
00547
00548 template< typename C >
00549 inline _Myt operator+(const C n) const { return parentType::operator+(n); }
00550
00551 template< typename C >
00552 inline _Myt operator-(const C n) const { return parentType::operator-(n); }
00553
00554 inline _Myt operator*(int n) const { return parentType::operator*(n);}
00555 inline _Myt operator*(float n) const { return parentType::operator*(n);}
00556 inline _Myt operator*(double n) const { return parentType::operator*(n);}
00557
00558 inline bool operator==(const _Myt &m) const { return parentType::operator==((parentType)m);}
00559
00560
00561 inline void operator+=(const _Myt &m) { parentType::operator+=((parentType)m);}
00562 inline void operator-=(const _Myt &m) { parentType::operator-=((parentType)m);}
00563 inline void operator= (const _Myt &m) { parentType::operator=((parentType)m);}
00564
00565
00566 template <int theirCols, int theirRows>
00567 inline Matrix< theirCols, height, T> operator* (const Matrix< theirCols, theirRows, T> &m) const
00568 {
00569
00570
00571
00572
00573 COMPILETIME_ASSERT (1==theirRows);
00574
00575 return multMatrix< _Myt, Matrix< theirCols, theirRows, T >, T, nRows, theirCols>(*this, m);
00576 }
00577
00578 Matrix <height, 1, T> getTranspose() const
00579 {
00580 Matrix<height, 1, T> rtn;
00581 memcpy(rtn.getData(), const_cast<_Myt*>(this)->getData(), sizeof(array));
00582 return rtn;
00583 }
00584
00585
00586 ColVector () {}
00587
00588 ColVector (T a)
00589 {
00590 COMPILETIME_ASSERT (nRows == 1); array[0] = a;
00591 }
00592
00593 ColVector (T a, T b)
00594 {
00595 COMPILETIME_ASSERT (nRows == 2);
00596 array[0] = a; array[1] = b;
00597 }
00598
00599 ColVector (T a, T b, T c)
00600 {
00601 COMPILETIME_ASSERT (nRows == 3); array[0] = a;
00602 array[0] = a; array[1] = b; array[2] = c;
00603 }
00604
00605 ColVector (T a, T b, T c, T d)
00606 {
00607 COMPILETIME_ASSERT (nRows == 4); array[0] = a;
00608 array[0] = a; array[1] = b; array[2] = c; array[3] = d;
00609 }
00610
00611
00612 T getLength () const
00613 {
00614 return (T)sqrt(getLengthSquared());
00615 }
00616
00617 T getLengthSquared() const
00618 {
00619 return (T)std::inner_product(&array[0], &array[nRows], &array[0], 0.);
00620 }
00621
00622 ColVector<3, T> crossProduct (const ColVector<height, T> &vx2) const
00623 {
00624 const ColVector<3, T> &vx1 = *this;
00625 ColVector<3, T> v;
00626
00627 v[0] = vx1[1]*vx2[2] - vx1[2]*vx2[1];
00628 v[1] = vx1[2]*vx2[0] - vx1[0]*vx2[2];
00629 v[2] = vx1[0]*vx2[1] - vx1[1]*vx2[0];
00630 return v;
00631 }
00632
00633 _Myt getReflection(const _Myt & normal) const
00634 {
00635 _Myt rtn;
00636 rtn = *this - normal * 2. * this->dotProduct(normal);
00637
00638 return rtn;
00639 }
00640
00641 T dotProduct (const _Myt &v) const
00642 {
00643 T rtn = 0;
00644 for (int i = 0; i < height; i++)
00645 rtn += array[i] * v[i];
00646
00647 return rtn;
00648 }
00649
00650 void normalize()
00651 {
00652 T len = getLength();
00653 if (len) {
00654 for (int i = 0; i < nRows; i++)
00655 array[i] /= len;
00656 }
00657 else
00658 assert(!"ColVector::normalize(): can't normalize a zero vector.");
00659 }
00660
00661 #if 0 // this is too dangerous to be used in practice
00662 ColVector( T first, ... )
00663 {
00664 va_list marker;
00665
00666 array[0] = first;
00667
00668 va_start( marker, first );
00669 for (int i = 1; i < nRows; i++)
00670 {
00671 array[i] = va_arg( marker, T);
00672 }
00673 va_end( marker );
00674 }
00675 #endif
00676
00677 };
00678
00679
00680
00681
00682 template< int height, typename T >
00683 class Position : public Matrix< 1, height, T >
00684 {
00685 public:
00686 typedef Matrix< 1,height,T > parentType;
00687 typedef Position< height, T > _Myt;
00688
00689 inline Position(parentType &p) { parentType::operator=(p); }
00690 inline void operator=(const parentType &p) { parentType::operator=(p); }
00691
00692
00693 Position () {}
00694
00695 Position (T a)
00696 {
00697 COMPILETIME_ASSERT (nRows == 1); array[0] = a;
00698 }
00699
00700 Position (T a, T b)
00701 {
00702 COMPILETIME_ASSERT (nRows == 2);
00703 array[0] = a; array[1] = b;
00704 }
00705
00706 Position (T a, T b, T c)
00707 {
00708 COMPILETIME_ASSERT (nRows == 3); array[0] = a;
00709 array[0] = a; array[1] = b; array[2] = c;
00710 }
00711
00712 Position (T a, T b, T c, T d)
00713 {
00714 COMPILETIME_ASSERT (nRows == 4); array[0] = a;
00715 array[0] = a; array[1] = b; array[2] = c; array[3] = d;
00716 }
00717
00718 _Myt linearlyInterpolate (const _Myt & p, double t)
00719 {
00720 return ((*this)*(1-t) + (p*t));
00721 }
00722
00723 inline bool operator==(const _Myt &m) const { return parentType::operator==((parentType)m);}
00724 inline void operator= (const _Myt &m) { parentType::operator=((parentType)m);}
00725
00726 Matrix <height, 1, T> getTranspose() const
00727 {
00728 Matrix<height, 1, T> rtn;
00729 memcpy(rtn.getData(), const_cast<_Myt*>(this)->getData(), sizeof(array));
00730 return rtn;
00731 }
00732
00733 template< typename C >
00734 inline ColVector< height, T > operator-(const C n) const { return parentType::operator-(n); }
00735
00736
00737
00738
00739
00740
00741 template< typename C >
00742 inline _Myt operator/(const C n) const { return parentType::operator/(n); }
00743
00744 template< typename C >
00745 inline _Myt operator+(const C &n) const { return parentType::operator+(n); }
00746
00747
00748 inline _Myt operator*(int n) const { return parentType::operator*(n);}
00749 inline _Myt operator*(float n) const { return parentType::operator*(n);}
00750 inline _Myt operator*(double n) const { return parentType::operator*(n);}
00751
00752
00753 inline void operator+=(const _Myt &m) { parentType::operator+=((parentType)m);}
00754 inline void operator-=(const _Myt &m) { parentType::operator-=((parentType)m);}
00755
00756
00757 template <int theirCols, int theirRows>
00758 inline Matrix< theirCols, height, T> operator* (const Matrix< theirCols, theirRows, T> &m) const
00759 {
00760
00761
00762
00763
00764 COMPILETIME_ASSERT (1==theirRows);
00765
00766 return multMatrix< _Myt, Matrix< theirCols, theirRows, T >, T, nRows, theirCols>(*this, m);
00767 }
00768 };
00769
00770
00771
00772
00773
00774
00775
00776 template< typename A, typename B, typename T, int rows1, int cols2>
00777 inline Matrix< cols2, rows1, T> multMatrix (A m1, B m2)
00778 {
00779 Matrix< m2.nColumns, m1.nRows, T> rtn;
00780 int row1, col2;
00781 for (row1 = 0; row1 < m1.nRows; row1++)
00782 {
00783 for (col2 = 0; col2 < B::nColumns; col2++)
00784 {
00785 T result = 0;
00786
00787 for (int i = 0; i < A::nColumns; i++)
00788 result += m1.elementAt (i, row1) * m2.elementAt (col2, i);
00789
00790 rtn (col2, row1) = result;
00791 }
00792 }
00793
00794 return rtn;
00795 }
00796
00797
00798
00799
00800
00801
00802 template < typename T >
00803 void printMatrix (const T & mtx, const char *str)
00804 {
00805 MTRACE("\n---- %s -----", str);
00806
00807 if (T::nRows == 1)
00808 {
00809 if (T::nColumns == 1)
00810 MTRACE("scalar");
00811 else
00812 MTRACE("%d element row vector", T::nColumns);
00813 }
00814 else
00815 {
00816 if (T::nColumns == 1)
00817 MTRACE("%d element col vector", T::nRows);
00818 else
00819 MTRACE("%d cols x %d rows matrix", T::nColumns, T::nRows);
00820 }
00821
00822 MTRACE(" ----------\n");
00823 for (int row = 0; row < T::nRows; row++)
00824 {
00825 for (int col = 0; col < T::nColumns; col++)
00826 MTRACE ("%.3lf ", mtx.elementAt(col,row));
00827
00828 MTRACE("\n");
00829 }
00830 }
00831
00832