vmmlib  1.12.0
Templatized C++ vector and matrix math library
matrix.hpp
1 /*
2  * Copyright (c) 2006-2016, Visualization and Multimedia Lab,
3  * University of Zurich <http://vmml.ifi.uzh.ch>,
4  * Eyescale Software GmbH,
5  * Blue Brain Project, EPFL
6  *
7  * This file is part of VMMLib <https://github.com/VMML/vmmlib/>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  * Redistributions of source code must retain the above copyright notice, this
13  * list of conditions and the following disclaimer. Redistributions in binary
14  * form must reproduce the above copyright notice, this list of conditions and
15  * the following disclaimer in the documentation and/or other materials provided
16  * with the distribution. Neither the name of the Visualization and Multimedia
17  * Lab, University of Zurich nor the names of its contributors may be used to
18  * endorse or promote products derived from this software without specific prior
19  * written permission.
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef __VMML__MATRIX__HPP__
34 #define __VMML__MATRIX__HPP__
35 
36 #include <vmmlib/enable_if.hpp>
37 #include <vmmlib/types.hpp>
38 
39 #include <algorithm>
40 #include <cmath>
41 #include <cstring>
42 #include <iomanip>
43 #include <iostream>
44 #include <limits>
45 #include <stdexcept>
46 #include <vector>
47 
48 namespace vmml
49 {
51 template< size_t R, size_t C, typename T > class Matrix
52 {
53 public:
58  Matrix();
59 
64  Matrix( const T* begin, const T* end );
65 
70  explicit Matrix( const std::vector< T >& data );
71 
76  template< size_t P, size_t Q > Matrix( const Matrix< P, Q, T >& source );
77 
82  template< size_t S >
83  Matrix( const Quaternion< T >& rotation, const vector< S, T >& translation,
84  typename enable_if< R == S+1 && C == S+1 && S == 3 >::type* = 0 );
85 
90  template< size_t S >
91  Matrix( const vector< S, T >& eye, const vector< S, T >& lookat,
92  const vector< S, T >& up,
93  typename enable_if< R == S+1 && C == S+1 && S == 3 >::type* = 0 );
94 
98  bool operator==( const Matrix& other ) const;
99 
101  bool operator!=( const Matrix& other ) const;
102 
104  bool equals( const Matrix& other,
105  T tolerance = std::numeric_limits< T >::epsilon( )) const;
106 
108  template< size_t P >
110  const Matrix< P, C, T >& right );
111 
113  template< size_t P >
114  Matrix< R, P, T > operator*( const Matrix< C, P, T >& other ) const;
115 
117 #ifdef VMMLIB_USE_CXX03
118  template< size_t O, size_t P >
119  typename enable_if< R == C && O == P && R == O >::type*
120 #else
121  template< size_t O, size_t P,
122  typename = typename enable_if< R == C && O == P && R == O >::type >
124 #endif
125  operator*=( const Matrix< O, P, T >& right );
126 
128  Matrix operator+( const Matrix& other ) const;
129 
131  Matrix operator-( const Matrix& other ) const;
132 
134  void operator+=( const Matrix& other );
135 
137  void operator-=( const Matrix& other );
139 
143  vector< R, T > operator*( const vector< C, T >& other ) const;
145 
149  T& operator()( size_t rowIndex, size_t colIndex );
150 
152  T operator()( size_t rowIndex, size_t colIndex ) const;
153 
155  const T* data() const { return array; }
156 
158  template< size_t O, size_t P >
159  Matrix< O, P, T > getSubMatrix( size_t rowOffset, size_t colOffset,
160  typename enable_if< O <= R && P <= C >::type* = 0 ) const;
161 
163  template< size_t O, size_t P > typename enable_if< O <= R && P <= C >::type*
164  setSubMatrix( const Matrix< O, P, T >& sub_matrix, size_t rowOffset,
165  size_t colOffset );
166 
168  const Matrix& operator=( const Matrix< R, C, T >& source_ );
169 
175  template< size_t P, size_t Q >
176  const Matrix& operator=( const Matrix< P, Q, T >& source_ );
177 
183  void operator=( const std::vector< T >& data );
184 
187 
189  vector< R, T > getColumn( size_t columnIndex ) const;
190 
192  void setColumn( size_t index, const vector< R, T >& column );
193 
195  vector< C, T > getRow( size_t index ) const;
196 
198  void setRow( size_t index, const vector< C, T >& row );
199 
201  vector< C-1, T > getTranslation() const;
202 
204  Matrix< R, C, T >& setTranslation( const vector< C-1, T >& t );
205 
210  template< size_t S >
211  void getLookAt( vector< S, T >& eye, vector< S, T >& lookAt,
212  vector< S, T >& up,
213  typename enable_if< R == S+1 && C == S+1 && S == 3 >::type* = 0 ) const;
215 
221  Matrix< R, C, T > inverse() const;
222 
223  template< size_t O, size_t P >
225  getAdjugate( Matrix< O, P, T >& adjugate ) const;
226 
227  template< size_t O, size_t P >
228  typename enable_if< O == P && R == C && O == R && R >= 2 >::type*
229  getCofactors( Matrix< O, P, T >& cofactors ) const;
230 
231  // returns the determinant of a square matrix R-1, C-1
232  template< size_t O, size_t P >
233  T getMinor( Matrix< O, P, T >& minor_, size_t row_to_cut, size_t col_to_cut,
234  typename enable_if< O == R-1 && P == C-1 && R == C && R >= 2 >::type* = 0 ) const;
235 
238  template< typename TT >
239  Matrix< R, C, T >& rotate_x( TT angle,
240  typename enable_if< R == C && R == 4, TT >::type* = 0 );
241 
242  template< typename TT >
243  Matrix< R, C, T >& rotate_y( TT angle,
244  typename enable_if< R == C && R == 4, TT >::type* = 0 );
245 
246  template< typename TT >
247  Matrix< R, C, T >& rotate_z( TT angle,
248  typename enable_if< R == C && R == 4, TT >::type* = 0 );
249 
250  template< typename TT >
251  Matrix< R, C, T >& pre_rotate_x( TT angle,
252  typename enable_if< R == C && R == 4, TT >::type* = 0 );
253 
254  template< typename TT >
255  Matrix< R, C, T >& pre_rotate_y( TT angle,
256  typename enable_if< R == C && R == 4, TT >::type* = 0 );
257 
258  template< typename TT >
259  Matrix< R, C, T >& pre_rotate_z( TT angle,
260  typename enable_if< R == C && R == 4, TT >::type* = 0 );
261 
262  template< typename TT >
263  Matrix< R, C, T >& scale( const vector< 3, TT >& scale_,
264  typename enable_if< R == C && R == 4, TT >::type* = 0 );
265 
266  template< typename TT >
267  Matrix< R, C, T >& scaleTranslation( const vector< 3, TT >& scale_,
268  typename enable_if< R == C && R == 4, TT >::type* = 0 );
270 
271  friend std::ostream& operator << ( std::ostream& os,
272  const Matrix< R, C, T >& matrix )
273  {
274  const std::ios::fmtflags flags = os.flags();
275  const int prec = os.precision();
276 
277  os.setf( std::ios::right, std::ios::adjustfield );
278  os.precision( 7 );
279 
280  for( size_t rowIndex = 0; rowIndex < R; ++rowIndex )
281  {
282  os << "|";
283  for( size_t colIndex = 0; colIndex < C; ++colIndex )
284  os << std::setw(10) << matrix( rowIndex, colIndex ) << " ";
285  os << "|" << std::endl;
286  }
287  os.precision( prec );
288  os.setf( flags );
289  return os;
290  };
291 
292  T array[ R * C ];
293 };
294 }
295 
296 #include <vmmlib/quaternion.hpp>
297 #include <vmmlib/vector.hpp>
298 
299 namespace vmml
300 {
303 template< typename T >
304 inline T computeDeterminant( const Matrix< 1, 1, T >& matrix_ )
305 {
306  return matrix_.array[ 0 ];
307 }
308 
309 template< typename T >
310 inline T computeDeterminant( const Matrix< 2, 2, T >& matrix_ )
311 {
312  return matrix_( 0, 0 ) * matrix_( 1, 1 ) - matrix_( 0, 1 ) * matrix_( 1, 0);
313 }
314 
315 template< typename T >
316 inline T computeDeterminant( const Matrix< 3, 3, T >& m_ )
317 {
318  return m_( 0,0 ) * ( m_( 1,1 ) * m_( 2,2 ) - m_( 1,2 ) * m_( 2,1 )) +
319  m_( 0,1 ) * ( m_( 1,2 ) * m_( 2,0 ) - m_( 1,0 ) * m_( 2,2 )) +
320  m_( 0,2 ) * ( m_( 1,0 ) * m_( 2,1 ) - m_( 1,1 ) * m_( 2,0 ));
321 }
322 
323 template< typename T >
324 inline T computeDeterminant( const Matrix< 4, 4, T >& m )
325 {
326  return m( 0, 3 ) * m( 1, 2 ) * m( 2, 1 ) * m( 3, 0 )
327  - m( 0, 2 ) * m( 1, 3 ) * m( 2, 1 ) * m( 3, 0 )
328  - m( 0, 3 ) * m( 1, 1 ) * m( 2, 2 ) * m( 3, 0 )
329  + m( 0, 1 ) * m( 1, 3 ) * m( 2, 2 ) * m( 3, 0 )
330  + m( 0, 2 ) * m( 1, 1 ) * m( 2, 3 ) * m( 3, 0 )
331  - m( 0, 1 ) * m( 1, 2 ) * m( 2, 3 ) * m( 3, 0 )
332  - m( 0, 3 ) * m( 1, 2 ) * m( 2, 0 ) * m( 3, 1 )
333  + m( 0, 2 ) * m( 1, 3 ) * m( 2, 0 ) * m( 3, 1 )
334  + m( 0, 3 ) * m( 1, 0 ) * m( 2, 2 ) * m( 3, 1 )
335  - m( 0, 0 ) * m( 1, 3 ) * m( 2, 2 ) * m( 3, 1 )
336  - m( 0, 2 ) * m( 1, 0 ) * m( 2, 3 ) * m( 3, 1 )
337  + m( 0, 0 ) * m( 1, 2 ) * m( 2, 3 ) * m( 3, 1 )
338  + m( 0, 3 ) * m( 1, 1 ) * m( 2, 0 ) * m( 3, 2 )
339  - m( 0, 1 ) * m( 1, 3 ) * m( 2, 0 ) * m( 3, 2 )
340  - m( 0, 3 ) * m( 1, 0 ) * m( 2, 1 ) * m( 3, 2 )
341  + m( 0, 0 ) * m( 1, 3 ) * m( 2, 1 ) * m( 3, 2 )
342  + m( 0, 1 ) * m( 1, 0 ) * m( 2, 3 ) * m( 3, 2 )
343  - m( 0, 0 ) * m( 1, 1 ) * m( 2, 3 ) * m( 3, 2 )
344  - m( 0, 2 ) * m( 1, 1 ) * m( 2, 0 ) * m( 3, 3 )
345  + m( 0, 1 ) * m( 1, 2 ) * m( 2, 0 ) * m( 3, 3 )
346  + m( 0, 2 ) * m( 1, 0 ) * m( 2, 1 ) * m( 3, 3 )
347  - m( 0, 0 ) * m( 1, 2 ) * m( 2, 1 ) * m( 3, 3 )
348  - m( 0, 1 ) * m( 1, 0 ) * m( 2, 2 ) * m( 3, 3 )
349  + m( 0, 0 ) * m( 1, 1 ) * m( 2, 2 ) * m( 3, 3 );
350 }
351 
352 template< typename T >
353 Matrix< 1, 1, T > computeInverse( const Matrix< 1, 1, T >& m_ )
354 {
355  return Matrix< 1, 1, T >( std::vector< T >( T(1) / m_( 0, 0 ), 1 ));
356 }
357 
358 template< typename T >
359 Matrix< 2, 2, T > computeInverse( const Matrix< 2, 2, T >& m_ )
360 {
361  const T det = computeDeterminant( m_ );
362  if( std::abs( det ) < std::numeric_limits< T >::epsilon( ))
363  return Matrix< 2, 2, T >(
364  std::vector< T >( 4, std::numeric_limits< T >::quiet_NaN( )));
365 
366  Matrix< 2, 2, T > inverse;
367  m_.getAdjugate( inverse );
368  const T detinv = 1 / det;
369  inverse( 0, 0 ) *= detinv;
370  inverse( 0, 1 ) *= detinv;
371  inverse( 1, 0 ) *= detinv;
372  inverse( 1, 1 ) *= detinv;
373  return inverse;
374 }
375 
376 template< typename T >
377 Matrix< 3, 3, T > computeInverse( const Matrix< 3, 3, T >& m_ )
378 {
379  // Invert a 3x3 using cofactors. This is about 8 times faster than
380  // the Numerical Recipes code which uses Gaussian elimination.
381  Matrix< 3, 3, T > inverse;
382  inverse( 0, 0 ) = m_( 1, 1 ) * m_( 2, 2 ) - m_( 1, 2 ) * m_( 2, 1 );
383  inverse( 0, 1 ) = m_( 0, 2 ) * m_( 2, 1 ) - m_( 0, 1 ) * m_( 2, 2 );
384  inverse( 0, 2 ) = m_( 0, 1 ) * m_( 1, 2 ) - m_( 0, 2 ) * m_( 1, 1 );
385  inverse( 1, 0 ) = m_( 1, 2 ) * m_( 2, 0 ) - m_( 1, 0 ) * m_( 2, 2 );
386  inverse( 1, 1 ) = m_( 0, 0 ) * m_( 2, 2 ) - m_( 0, 2 ) * m_( 2, 0 );
387  inverse( 1, 2 ) = m_( 0, 2 ) * m_( 1, 0 ) - m_( 0, 0 ) * m_( 1, 2 );
388  inverse( 2, 0 ) = m_( 1, 0 ) * m_( 2, 1 ) - m_( 1, 1 ) * m_( 2, 0 );
389  inverse( 2, 1 ) = m_( 0, 1 ) * m_( 2, 0 ) - m_( 0, 0 ) * m_( 2, 1 );
390  inverse( 2, 2 ) = m_( 0, 0 ) * m_( 1, 1 ) - m_( 0, 1 ) * m_( 1, 0 );
391 
392  const T determinant = m_( 0, 0 ) * inverse( 0, 0 ) +
393  m_( 0, 1 ) * inverse( 1, 0 ) +
394  m_( 0, 2 ) * inverse( 2, 0 );
395 
396  if ( std::abs( determinant ) <= std::numeric_limits< T >::epsilon( ))
397  return Matrix< 3, 3, T >(
398  std::vector< T >( 9, std::numeric_limits< T >::quiet_NaN( )));
399 
400  const T detinv = static_cast< T >( 1.0 ) / determinant;
401 
402  inverse( 0, 0 ) *= detinv;
403  inverse( 0, 1 ) *= detinv;
404  inverse( 0, 2 ) *= detinv;
405  inverse( 1, 0 ) *= detinv;
406  inverse( 1, 1 ) *= detinv;
407  inverse( 1, 2 ) *= detinv;
408  inverse( 2, 0 ) *= detinv;
409  inverse( 2, 1 ) *= detinv;
410  inverse( 2, 2 ) *= detinv;
411  return inverse;
412 }
413 
414 template< typename T >
415 Matrix< 4, 4, T > computeInverse( const Matrix< 4, 4, T >& m_ )
416 {
417  const T* array = m_.array;
418 
419  // tuned version from Claude Knaus
420  /* first set of 2x2 determinants: 12 multiplications, 6 additions */
421  const T t1[6] = { array[ 2] * array[ 7] - array[ 6] * array[ 3],
422  array[ 2] * array[11] - array[10] * array[ 3],
423  array[ 2] * array[15] - array[14] * array[ 3],
424  array[ 6] * array[11] - array[10] * array[ 7],
425  array[ 6] * array[15] - array[14] * array[ 7],
426  array[10] * array[15] - array[14] * array[11] };
427 
428  /* first half of comatrix: 24 multiplications, 16 additions */
429  Matrix< 4, 4, T > inv;
430  inv.array[0] = array[ 5] * t1[5] - array[ 9] * t1[4] + array[13] * t1[3];
431  inv.array[1] = array[ 9] * t1[2] - array[13] * t1[1] - array[ 1] * t1[5];
432  inv.array[2] = array[13] * t1[0] - array[ 5] * t1[2] + array[ 1] * t1[4];
433  inv.array[3] = array[ 5] * t1[1] - array[ 1] * t1[3] - array[ 9] * t1[0];
434  inv.array[4] = array[ 8] * t1[4] - array[ 4] * t1[5] - array[12] * t1[3];
435  inv.array[5] = array[ 0] * t1[5] - array[ 8] * t1[2] + array[12] * t1[1];
436  inv.array[6] = array[ 4] * t1[2] - array[12] * t1[0] - array[ 0] * t1[4];
437  inv.array[7] = array[ 0] * t1[3] - array[ 4] * t1[1] + array[ 8] * t1[0];
438 
439  /* second set of 2x2 determinants: 12 multiplications, 6 additions */
440  const T t2[6] = { array[ 0] * array[ 5] - array[ 4] * array[ 1],
441  array[ 0] * array[ 9] - array[ 8] * array[ 1],
442  array[ 0] * array[13] - array[12] * array[ 1],
443  array[ 4] * array[ 9] - array[ 8] * array[ 5],
444  array[ 4] * array[13] - array[12] * array[ 5],
445  array[ 8] * array[13] - array[12] * array[ 9] };
446 
447  /* second half of comatrix: 24 multiplications, 16 additions */
448  inv.array[8] = array[ 7] * t2[5] - array[11] * t2[4] + array[15] * t2[3];
449  inv.array[9] = array[11] * t2[2] - array[15] * t2[1] - array[ 3] * t2[5];
450  inv.array[10] = array[15] * t2[0] - array[ 7] * t2[2] + array[ 3] * t2[4];
451  inv.array[11] = array[ 7] * t2[1] - array[ 3] * t2[3] - array[11] * t2[0];
452  inv.array[12] = array[10] * t2[4] - array[ 6] * t2[5] - array[14] * t2[3];
453  inv.array[13] = array[ 2] * t2[5] - array[10] * t2[2] + array[14] * t2[1];
454  inv.array[14] = array[ 6] * t2[2] - array[14] * t2[0] - array[ 2] * t2[4];
455  inv.array[15] = array[ 2] * t2[3] - array[ 6] * t2[1] + array[10] * t2[0];
456 
457  /* determinant: 4 multiplications, 3 additions */
458  const T determinant = array[0] * inv.array[0] + array[4] * inv.array[1] +
459  array[8] * inv.array[2] + array[12] * inv.array[3];
460 
461  /* division: 16 multiplications, 1 division */
462  const T detinv = T( 1 ) / determinant;
463  for( size_t i = 0; i != 16; ++i )
464  inv.array[i] *= detinv;
465  return inv;
466 }
467 
468 template< size_t R, size_t C, typename T >
469 Matrix< R, C, T > computeInverse( const Matrix< R, C, T >& )
470 {
471  throw std::runtime_error( "Can't compute inverse of this matrix" );
472 }
473 
475 template< size_t R, size_t C, typename T > inline
477 {
478  Matrix< C, R, T > transposed;
479  for( size_t row = 0; row< R; ++row )
480  for( size_t col = 0; col < C; ++col )
481  transposed( col, row ) = matrix( row, col );
482  return transposed;
483 }
485 
486 template< size_t R, size_t C, typename T >
488  : array() // http://stackoverflow.com/questions/5602030
489 {
490  if( R == C )
491  for( size_t i = 0; i < R; ++i )
492  (*this)( i, i ) = 1;
493 }
494 
495 template< size_t R, size_t C, typename T >
496 Matrix< R, C, T >::Matrix( const T* begin_, const T* end_ )
497  : array() // http://stackoverflow.com/questions/5602030
498 {
499  const T* to = std::min( end_, begin_ + R * C );
500  ::memcpy( array, begin_, (to - begin_) * sizeof( T ));
501 }
502 
503 template< size_t R, size_t C, typename T >
504 Matrix< R, C, T >::Matrix( const std::vector< T >& values )
505 {
506  *this = values;
507 }
508 
509 template< size_t R, size_t C, typename T >
510 template< size_t P, size_t Q >
512 {
513  *this = source;
514 }
515 
516 template< size_t R, size_t C, typename T > template< size_t O >
518  const vector< O, T >& translation,
519  typename enable_if< R == O+1 && C == O+1 && O == 3 >::type* )
520 {
521  *this = rotation.getRotationMatrix();
522  setTranslation( translation );
523  (*this)( 3, 0 ) = 0;
524  (*this)( 3, 1 ) = 0;
525  (*this)( 3, 2 ) = 0;
526  (*this)( 3, 3 ) = 1;
527 }
528 
529 template< size_t R, size_t C, typename T > template< size_t S >
531  const vector< S, T >& lookat,
532  const vector< S, T >& up,
533  typename enable_if< R == S+1 && C == S+1 && S == 3 >::type* )
534  : array() // http://stackoverflow.com/questions/5602030
535 {
536  const vector< 3, T > f( vmml::normalize( lookat - eye ));
537  const vector< 3, T > s( vmml::normalize( vmml::cross( f, up )));
538  const vector< 3, T > u( vmml::cross( s, f ));
539 
540  (*this)( 0, 0 ) = s.x();
541  (*this)( 0, 1 ) = s.y();
542  (*this)( 0, 2 ) = s.z();
543  (*this)( 1, 0 ) = u.x();
544  (*this)( 1, 1 ) = u.y();
545  (*this)( 1, 2 ) = u.z();
546  (*this)( 2, 0 ) = -f.x();
547  (*this)( 2, 1 ) = -f.y();
548  (*this)( 2, 2 ) = -f.z();
549  (*this)( 0, 3 ) = -vmml::dot( s, eye );
550  (*this)( 1, 3 ) = -vmml::dot( u, eye );
551  (*this)( 2, 3 ) = vmml::dot( f, eye );
552  (*this)( 3, 3 ) = 1;
553 }
554 
555 template< size_t R, size_t C, typename T > inline
556 T& Matrix< R, C, T >::operator()( size_t rowIndex, size_t colIndex )
557 {
558  if ( rowIndex >= R || colIndex >= C )
559  throw std::runtime_error( "matrix( row, column ) index out of bounds" );
560  return array[ colIndex * R + rowIndex ];
561 }
562 
563 template< size_t R, size_t C, typename T > inline
564 T Matrix< R, C, T >::operator()( size_t rowIndex, size_t colIndex ) const
565 {
566  if ( rowIndex >= R || colIndex >= C )
567  throw std::runtime_error( "matrix( row, column ) index out of bounds" );
568  return array[ colIndex * R + rowIndex ];
569 }
570 
571 template< size_t R, size_t C, typename T >
573 {
574  for( size_t i = 0; i < R * C; ++i )
575  if( array[ i ] != other.array[ i ])
576  return false;
577  return true;
578 }
579 
580 template< size_t R, size_t C, typename T >
582 {
583  return ! operator==( other );
584 }
585 
586 template< size_t R, size_t C, typename T >
588  const T tolerance ) const
589 {
590  for( size_t i = 0; i < R * C; ++i )
591  if( std::abs( array[ i ] - other.array[ i ]) > tolerance )
592  return false;
593  return true;
594 }
595 
596 template< size_t R, size_t C, typename T > const Matrix< R, C, T >&
598 {
599  ::memcpy( array, source.array, R * C * sizeof( T ));
600  return *this;
601 }
602 
603 template< size_t R, size_t C, typename T > template< size_t P, size_t Q >
604 const Matrix< R, C, T >&
606 {
607  const size_t minL = std::min( P, R );
608  const size_t minC = std::min( Q, C );
609 
610  for ( size_t i = 0 ; i < minL ; ++i )
611  for ( size_t j = 0 ; j < minC ; ++j )
612  (*this)( i, j ) = source( i, j );
613  for ( size_t i = minL ; i< R ; ++i )
614  for ( size_t j = minC ; j < C ; ++j )
615  (*this)( i, j ) = 0;
616  return *this;
617 }
618 
619 template< size_t R, size_t C, typename T >
620 void Matrix< R, C, T >::operator=( const std::vector< T >& values )
621 {
622  const size_t to = std::min( R * C, values.size( ));
623  ::memcpy( array, values.data(), to * sizeof( T ));
624  if( to < R * C )
625  {
626 #ifdef _WIN32
627  ::memset( array + to, 0, (R * C - to) * sizeof( T ));
628 #else
629  ::bzero( array + to, (R * C - to) * sizeof( T ));
630 #endif
631  }
632 }
633 
634 template< size_t R, size_t C, typename T > template< size_t P >
636  const Matrix< P, C, T >& right )
637 {
638  // Create copy for multiplication with self
639  if( &left == this )
640  return multiply( Matrix< R, P, T >( left ), right );
641  if( &right == this )
642  return multiply( left, Matrix< R, P, T >( right ));
643 
644  for( size_t rowIndex = 0; rowIndex< R; ++rowIndex )
645  {
646  for( size_t colIndex = 0; colIndex < C; ++colIndex )
647  {
648  T& component = (*this)( rowIndex, colIndex );
649  component = static_cast< T >( 0.0 );
650  for( size_t p = 0; p < P; p++)
651  component += left( rowIndex, p ) * right( p, colIndex );
652  }
653  }
654  return *this;
655 }
656 
657 template< size_t R, size_t C, typename T > template< size_t P >
659  const
660 {
661  Matrix< R, P, T > result;
662  return result.multiply( *this, other );
663 }
664 
665 #ifdef VMMLIB_USE_CXX03
666 template< size_t R, size_t C, typename T > template< size_t O, size_t P >
667 typename enable_if< R == C && O == P && R == O >::type*
668 #else
669 template< size_t R, size_t C, typename T > template< size_t O, size_t P, typename >
671 #endif
673 {
674  Matrix< R, C, T > copy( *this );
675  multiply( copy, right );
676 #ifdef VMMLIB_USE_CXX03
677  return 0;
678 #else
679  return *this;
680 #endif
681 }
682 
683 template< size_t R, size_t C, typename T >
685 {
686  vector< R, T > result;
687 
688  // this < R, 1 > = < R, P > * < P, 1 >
689  for( size_t i = 0; i< R; ++i )
690  {
691  T tmp( 0 );
692  for( size_t j = 0; j < C; ++j )
693  tmp += (*this)( i, j ) * vec( j );
694  result( i ) = tmp;
695  }
696  return result;
697 }
698 
699 template< size_t R, size_t C, typename T > inline
701 {
702  Matrix< R, C, T > result;
703  for( size_t i = 0; i< R * C; ++i )
704  result.array[ i ] = -array[ i ];
705  return result;
706 }
707 
708 template< size_t R, size_t C, typename T >
709 vector< R, T > Matrix< R, C, T >::getColumn( const size_t index ) const
710 {
711  if ( index >= C )
712  throw std::runtime_error( "getColumn() - index out of bounds." );
713  vector< R, T > column;
714  ::memcpy( &column.array[0], &array[ R * index ], R * sizeof( T ));
715  return column;
716 }
717 
718 template< size_t R, size_t C, typename T >
719 void Matrix< R, C, T >::setColumn( size_t index, const vector< R, T >& column )
720 {
721  if ( index >= C )
722  throw std::runtime_error( "setColumn() - index out of bounds." );
723  memcpy( array + R * index, column.array, R * sizeof( T ) );
724 }
725 
726 template< size_t R, size_t C, typename T >
727 vector< C, T > Matrix< R, C, T >::getRow( size_t index ) const
728 {
729  if ( index >= R )
730  throw std::runtime_error( "getRow() - index out of bounds." );
731 
732  vector< C, T > row;
733  for( size_t colIndex = 0; colIndex < C; ++colIndex )
734  row( colIndex ) = (*this)( index, colIndex );
735  return row;
736 }
737 
738 template< size_t R, size_t C, typename T >
739 void Matrix< R, C, T >::setRow( size_t rowIndex, const vector< C, T >& row )
740 {
741  if ( rowIndex >= R )
742  throw std::runtime_error( "setRow() - index out of bounds." );
743 
744  for( size_t colIndex = 0; colIndex < C; ++colIndex )
745  (*this)( rowIndex, colIndex ) = row( colIndex );
746 }
747 
748 template< size_t R, size_t C, typename T > inline
750  const
751 {
752  Matrix< R, C, T > result( *this );
753  result += other;
754  return result;
755 }
756 
757 template< size_t R, size_t C, typename T >
759 {
760  for( size_t i = 0; i < R * C; ++i )
761  array[i] += other.array[i];
762 }
763 
764 template< size_t R, size_t C, typename T > inline
766  const
767 {
768  Matrix< R, C, T > result( *this );
769  result -= other;
770  return result;
771 }
772 
773 template< size_t R, size_t C, typename T >
775 {
776  for( size_t i = 0; i < R * C; ++i )
777  array[i] -= other.array[i];
778 }
779 
780 template< size_t R, size_t C, typename T > template< size_t O, size_t P >
782  size_t colOffset,
783  typename enable_if< O <= R && P <= C >::type* ) const
784 {
785  Matrix< O, P, T > result;
786  if ( O + rowOffset > R || P + colOffset > C )
787  throw std::runtime_error( "index out of bounds." );
788 
789  for( size_t row = 0; row < O; ++row )
790  for( size_t col = 0; col < P; ++col )
791  result( row, col ) = (*this)( rowOffset + row, colOffset + col );
792 
793  return result;
794 }
795 
796 template< size_t R, size_t C, typename T > template< size_t O, size_t P >
799  size_t rowOffset, size_t colOffset )
800 {
801  for( size_t row = 0; row < O; ++row )
802  for( size_t col = 0; col < P; ++col )
803  (*this)( rowOffset + row, colOffset + col ) = sub_matrix( row, col);
804  return 0; // for sfinae
805 }
806 
807 template< size_t R, size_t C, typename T >
809 {
810  return computeInverse( *this );
811 }
812 
813 template< size_t R, size_t C, typename T > template< size_t O, size_t P >
816 {
817  getCofactors( adjugate );
818  adjugate = transpose( adjugate );
819  return 0;
820 }
821 
822 template< size_t R, size_t C, typename T > template< size_t O, size_t P >
823 typename enable_if< O == P && R == C && O == R && R >= 2 >::type*
825 {
826  Matrix< R-1, C-1, T > minor_;
827 
828  const size_t _negate = 1u;
829  for( size_t rowIndex = 0; rowIndex< R; ++rowIndex )
830  for( size_t colIndex = 0; colIndex < C; ++colIndex )
831  if ( ( rowIndex + colIndex ) & _negate )
832  cofactors( rowIndex, colIndex ) = -getMinor( minor_, rowIndex, colIndex );
833  else
834  cofactors( rowIndex, colIndex ) = getMinor( minor_, rowIndex, colIndex );
835 
836  return 0;
837 }
838 
839 template< size_t R, size_t C, typename T > template< size_t O, size_t P >
840 T Matrix< R, C, T >::getMinor( Matrix< O, P, T >& minor_, size_t row_to_cut,
841  size_t col_to_cut,
842  typename enable_if< O == R-1 && P == C-1 && R == C && R >= 2 >::type* ) const
843 {
844  size_t rowOffset = 0;
845  size_t colOffset = 0;
846  for( size_t rowIndex = 0; rowIndex< R; ++rowIndex )
847  {
848  if ( rowIndex == row_to_cut )
849  rowOffset = -1;
850  else
851  {
852  for( size_t colIndex = 0; colIndex < R; ++colIndex )
853  {
854  if ( colIndex == col_to_cut )
855  colOffset = -1;
856  else
857  minor_( rowIndex + rowOffset, colIndex + colOffset )
858  = (*this)( rowIndex, colIndex );
859  }
860  colOffset = 0;
861  }
862  }
863  return computeDeterminant( minor_ );
864 }
865 
866 template< size_t R, size_t C, typename T > template< typename TT >
868  typename enable_if< R == C && R == 4, TT >::type* )
869 {
870  const T angle = static_cast< T >( angle_ );
871  const T sine = std::sin( angle );
872  const T cosine = std::cos( angle );
873 
874  T tmp;
875 
876  tmp = array[ 4 ] * cosine + array[ 8 ] * sine;
877  array[ 8 ] = - array[ 4 ] * sine + array[ 8 ] * cosine;
878  array[ 4 ] = tmp;
879 
880  tmp = array[ 5 ] * cosine + array[ 9 ] * sine;
881  array[ 9 ] = - array[ 5 ] * sine + array[ 9 ] * cosine;
882  array[ 5 ] = tmp;
883 
884  tmp = array[ 6 ] * cosine + array[ 10 ] * sine;
885  array[ 10 ] = - array[ 6 ] * sine + array[ 10 ] * cosine;
886  array[ 6 ] = tmp;
887 
888  tmp = array[ 7 ] * cosine + array[ 11 ] * sine;
889  array[ 11 ] = - array[ 7 ] * sine + array[ 11 ] * cosine;
890  array[ 7 ] = tmp;
891 
892  return *this;
893 }
894 
895 template< size_t R, size_t C, typename T > template< typename TT >
897  typename enable_if< R == C && R == 4, TT >::type* )
898 {
899  const T angle = static_cast< T >( angle_ );
900  const T sine = std::sin( angle );
901  const T cosine = std::cos( angle );
902 
903  T tmp;
904 
905  tmp = array[ 0 ] * cosine - array[ 8 ] * sine;
906  array[ 8 ] = array[ 0 ] * sine + array[ 8 ] * cosine;
907  array[ 0 ] = tmp;
908 
909  tmp = array[ 1 ] * cosine - array[ 9 ] * sine;
910  array[ 9 ] = array[ 1 ] * sine + array[ 9 ] * cosine;
911  array[ 1 ] = tmp;
912 
913  tmp = array[ 2 ] * cosine - array[ 10 ] * sine;
914  array[ 10 ] = array[ 2 ] * sine + array[ 10 ] * cosine;
915  array[ 2 ] = tmp;
916 
917  tmp = array[ 3 ] * cosine - array[ 11 ] * sine;
918  array[ 11 ] = array[ 3 ] * sine + array[ 11 ] * cosine;
919  array[ 3 ] = tmp;
920 
921  return *this;
922 }
923 
924 template< size_t R, size_t C, typename T > template< typename TT >
926  typename enable_if< R == C && R == 4, TT >::type* )
927 {
928  const T angle = static_cast< T >( angle_ );
929  const T sine = std::sin( angle );
930  const T cosine = std::cos( angle );
931 
932  T tmp;
933 
934  tmp = array[ 0 ] * cosine + array[ 4 ] * sine;
935  array[ 4 ] = - array[ 0 ] * sine + array[ 4 ] * cosine;
936  array[ 0 ] = tmp;
937 
938  tmp = array[ 1 ] * cosine + array[ 5 ] * sine;
939  array[ 5 ] = - array[ 1 ] * sine + array[ 5 ] * cosine;
940  array[ 1 ] = tmp;
941 
942  tmp = array[ 2 ] * cosine + array[ 6 ] * sine;
943  array[ 6 ] = - array[ 2 ] * sine + array[ 6 ] * cosine;
944  array[ 2 ] = tmp;
945 
946  tmp = array[ 3 ] * cosine + array[ 7 ] * sine;
947  array[ 7 ] = - array[ 3 ] * sine + array[ 7 ] * cosine;
948  array[ 3 ] = tmp;
949 
950  return *this;
951 }
952 
953 template< size_t R, size_t C, typename T > template< typename TT >
955  typename enable_if< R == C && R == 4, TT >::type* )
956 {
957  const T angle = static_cast< T >( angle_ );
958  const T sine = std::sin( angle );
959  const T cosine = std::cos( angle );
960 
961  T tmp;
962 
963  tmp = array[ 1 ];
964  array[ 1 ] = array[ 1 ] * cosine + array[ 2 ] * sine;
965  array[ 2 ] = tmp * -sine + array[ 2 ] * cosine;
966 
967  tmp = array[ 5 ];
968  array[ 5 ] = array[ 5 ] * cosine + array[ 6 ] * sine;
969  array[ 6 ] = tmp * -sine + array[ 6 ] * cosine;
970 
971  tmp = array[ 9 ];
972  array[ 9 ] = array[ 9 ] * cosine + array[ 10 ] * sine;
973  array[ 10 ] = tmp * -sine + array[ 10 ] * cosine;
974 
975  tmp = array[ 13 ];
976  array[ 13 ] = array[ 13 ] * cosine + array[ 14 ] * sine;
977  array[ 14 ] = tmp * -sine + array[ 14 ] * cosine;
978 
979  return *this;
980 }
981 
982 template< size_t R, size_t C, typename T > template< typename TT >
984  typename enable_if< R == C && R == 4, TT >::type* )
985 {
986  const T angle = static_cast< T >( angle_ );
987  const T sine = std::sin( angle );
988  const T cosine = std::cos( angle );
989 
990  T tmp;
991 
992  tmp = array[ 0 ];
993  array[ 0 ] = array[ 0 ] * cosine - array[ 2 ] * sine;
994  array[ 2 ] = tmp * sine + array[ 2 ] * cosine;
995 
996  tmp = array[ 4 ];
997  array[ 4 ] = array[ 4 ] * cosine - array[ 6 ] * sine;
998  array[ 6 ] = tmp * sine + array[ 6 ] * cosine;
999 
1000  tmp = array[ 8 ];
1001  array[ 8 ] = array[ 8 ] * cosine - array[ 10 ] * sine;
1002  array[ 10 ] = tmp * sine + array[ 10 ] * cosine;
1003 
1004  tmp = array[ 12 ];
1005  array[ 12 ] = array[ 12 ] * cosine - array[ 14 ] * sine;
1006  array[ 14 ] = tmp * sine + array[ 14 ] * cosine;
1007 
1008  return *this;
1009 }
1010 
1011 template< size_t R, size_t C, typename T > template< typename TT >
1013  typename enable_if< R == C && R == 4, TT >::type* )
1014 {
1015  const T angle = static_cast< T >( angle_ );
1016  const T sine = std::sin( angle );
1017  const T cosine = std::cos( angle );
1018 
1019  T tmp;
1020 
1021  tmp = array[ 0 ];
1022  array[ 0 ] = array[ 0 ] * cosine + array[ 1 ] * sine;
1023  array[ 1 ] = tmp * -sine + array[ 1 ] * cosine;
1024 
1025  tmp = array[ 4 ];
1026  array[ 4 ] = array[ 4 ] * cosine + array[ 5 ] * sine;
1027  array[ 5 ] = tmp * -sine + array[ 5 ] * cosine;
1028 
1029  tmp = array[ 8 ];
1030  array[ 8 ] = array[ 8 ] * cosine + array[ 9 ] * sine;
1031  array[ 9 ] = tmp * -sine + array[ 9 ] * cosine;
1032 
1033  tmp = array[ 12 ];
1034  array[ 12 ] = array[ 12 ] * cosine + array[ 13 ] * sine;
1035  array[ 13 ] = tmp * -sine + array[ 13 ] * cosine;
1036 
1037  return *this;
1038 }
1039 
1040 template< size_t R, size_t C, typename T > template< typename TT > inline
1042  typename enable_if< R == C && R == 4, TT >::type* )
1043 {
1044  array[0] *= scale_[ 0 ];
1045  array[1] *= scale_[ 0 ];
1046  array[2] *= scale_[ 0 ];
1047  array[3] *= scale_[ 0 ];
1048  array[4] *= scale_[ 1 ];
1049  array[5] *= scale_[ 1 ];
1050  array[6] *= scale_[ 1 ];
1051  array[7] *= scale_[ 1 ];
1052  array[8] *= scale_[ 2 ];
1053  array[9] *= scale_[ 2 ];
1054  array[10] *= scale_[ 2 ];
1055  array[11] *= scale_[ 2 ];
1056  return *this;
1057 }
1058 
1059 
1060 template< size_t R, size_t C, typename T > template< typename TT > inline
1062  const vector< 3, TT >& scale_,
1063  typename enable_if< R == C && R == 4, TT >::type* )
1064 {
1065  array[12] *= static_cast< T >( scale_[0] );
1066  array[13] *= static_cast< T >( scale_[1] );
1067  array[14] *= static_cast< T >( scale_[2] );
1068  return *this;
1069 }
1070 
1071 
1072 template< size_t R, size_t C, typename T > inline Matrix< R, C, T >&
1074 {
1075  for( size_t i = 0; i < C-1; ++i )
1076  array[ i + R * (C - 1) ] = trans[ i ];
1077  return *this;
1078 }
1079 
1080 template< size_t R, size_t C, typename T > inline
1081 vector< C-1, T > Matrix< R, C, T >::getTranslation() const
1082 {
1083  vector< C-1, T > result;
1084  for( size_t i = 0; i < C-1; ++i )
1085  result[ i ] = array[ i + R * (C - 1) ];
1086  return result;
1087 }
1088 
1089 template< size_t R, size_t C, typename T > template< size_t S >
1091  vector< S, T >& up,
1092  typename enable_if< R == S+1 && C == S+1 && S == 3 >::type* ) const
1093 {
1094  const Matrix< 4, 4, T >& inv = inverse();
1095  const Matrix< 3, 3, T > rotation( transpose( Matrix< 3, 3, T >( *this )));
1096 
1097  eye = vector< S, T >( inv * vector< 4, T >::zero( ));
1098  up = rotation * vector< 3, T >::up();
1099  lookAt = rotation * vector< 3, T >::forward();
1100  lookAt.normalize();
1101  lookAt = eye + lookAt;
1102 }
1103 
1104 } // namespace vmml
1105 
1106 #endif
Matrix< R, P, T > operator*(const Matrix< C, P, T > &other) const
Definition: matrix.hpp:658
Matrix operator+(const Matrix &other) const
Element-wise addition of two matrices.
Definition: matrix.hpp:749
enable_if< O<=R &&P<=C >::type *setSubMatrix(const Matrix< O, P, T > &sub_matrix, size_t rowOffset, size_t colOffset);const Matrix &operator=(const Matrix< R, C, T > &source_);template< size_t P, size_t Q > const Matrix &operator=(const Matrix< P, Q, T > &source_);void operator=(const std::vector< T > &data);Matrix< R, C, T > operator-() const ;vector< R, T > getColumn(size_t columnIndex) const ;void setColumn(size_t index, const vector< R, T > &column);vector< C, T > getRow(size_t index) const ;void setRow(size_t index, const vector< C, T > &row);vector< C-1, T > getTranslation() const ;Matrix< R, C, T > &setTranslation(const vector< C-1, T > &t);template< size_t S > void getLookAt(vector< S, T > &eye, vector< S, T > &lookAt, vector< S, T > &up, typename enable_if< R==S+1 &&C==S+1 &&S==3 >::type *=0) const ;Matrix< R, C, T > inverse() const ;template< size_t O, size_t P > typename enable_if< O==P &&R==C &&O==R &&R >=2 >::type *getAdjugate(Matrix< O, P, T > &adjugate) const ;template< size_t O, size_t P > typename enable_if< O==P &&R==C &&O==R &&R >=2 >::type * getCofactors(Matrix< O, P, T > &cofactors) const
Set the sub matrix of size OxP at the given start indices.
bool operator==(const Matrix &other) const
Definition: matrix.hpp:572
Matrix< R, C, T > & operator*=(const Matrix< O, P, T > &right)
Multiply two square matrices.
Definition: matrix.hpp:672
Matrix()
Construct a zero-initialized matrix.
Definition: matrix.hpp:487
const T * data() const
Definition: matrix.hpp:155
T array[R *C]
column by column storage
Definition: matrix.hpp:290
Matrix operator-(const Matrix &other) const
Element-wise substraction of two matrices.
Definition: matrix.hpp:700
bool equals(const Matrix &other, T tolerance=std::numeric_limits< T >::epsilon()) const
Definition: matrix.hpp:587
heavily inspired by boost::enable_if http://www.boost.org, file: boost/utility/enable_if.hpp, Copyright 2003 Jaakko Järvi, Jeremiah Willcock, Andrew Lumsdaine
Definition: aabb.hpp:40
void operator-=(const Matrix &other)
Element-wise substraction of two matrices.
Definition: matrix.hpp:774
T & operator()(size_t rowIndex, size_t colIndex)
Definition: matrix.hpp:556
Matrix< C, R, T > transpose(const Matrix< R, C, T > &matrix)
Definition: matrix.hpp:476
T array[M]
storage
Definition: vector.hpp:309
Matrix< 3, 3, T > getRotationMatrix() const
Definition: quaternion.hpp:447
bool operator!=(const Matrix &other) const
Definition: matrix.hpp:581
Matrix< O, P, T > getSubMatrix(size_t rowOffset, size_t colOffset, typename enable_if< O<=R &&P<=C >::type *=0) const
Definition: matrix.hpp:781
Matrix< R, C, T > & multiply(const Matrix< R, P, T > &left, const Matrix< P, C, T > &right)
Set this to the product of the two matrices (left_RxP * right_PxC)
Definition: matrix.hpp:635
void operator+=(const Matrix &other)
Element-wise addition of two matrices.
Definition: matrix.hpp:758
Matrix with R rows and C columns of element type T.
Definition: matrix.hpp:51