vmmlib  1.11.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  {
285  os << std::setw(10) << matrix( rowIndex, colIndex ) << " ";
286  }
287  os << "|" << std::endl;
288  }
289  os.precision( prec );
290  os.setf( flags );
291  return os;
292  };
293 
294  T array[ R * C ];
295 };
296 }
297 
298 #include <vmmlib/quaternion.hpp>
299 #include <vmmlib/vector.hpp>
300 
301 namespace vmml
302 {
305 template< typename T >
306 inline T computeDeterminant( const Matrix< 1, 1, T >& matrix_ )
307 {
308  return matrix_.array[ 0 ];
309 }
310 
311 template< typename T >
312 inline T computeDeterminant( const Matrix< 2, 2, T >& matrix_ )
313 {
314  return matrix_( 0, 0 ) * matrix_( 1, 1 ) - matrix_( 0, 1 ) * matrix_( 1, 0);
315 }
316 
317 template< typename T >
318 inline T computeDeterminant( const Matrix< 3, 3, T >& m_ )
319 {
320  return m_( 0,0 ) * ( m_( 1,1 ) * m_( 2,2 ) - m_( 1,2 ) * m_( 2,1 )) +
321  m_( 0,1 ) * ( m_( 1,2 ) * m_( 2,0 ) - m_( 1,0 ) * m_( 2,2 )) +
322  m_( 0,2 ) * ( m_( 1,0 ) * m_( 2,1 ) - m_( 1,1 ) * m_( 2,0 ));
323 }
324 
325 template< typename T >
326 inline T computeDeterminant( const Matrix< 4, 4, T >& m )
327 {
328  return m( 0, 3 ) * m( 1, 2 ) * m( 2, 1 ) * m( 3, 0 )
329  - m( 0, 2 ) * m( 1, 3 ) * m( 2, 1 ) * m( 3, 0 )
330  - m( 0, 3 ) * m( 1, 1 ) * m( 2, 2 ) * m( 3, 0 )
331  + m( 0, 1 ) * m( 1, 3 ) * m( 2, 2 ) * m( 3, 0 )
332  + m( 0, 2 ) * m( 1, 1 ) * m( 2, 3 ) * m( 3, 0 )
333  - m( 0, 1 ) * m( 1, 2 ) * m( 2, 3 ) * m( 3, 0 )
334  - m( 0, 3 ) * m( 1, 2 ) * m( 2, 0 ) * m( 3, 1 )
335  + m( 0, 2 ) * m( 1, 3 ) * m( 2, 0 ) * m( 3, 1 )
336  + m( 0, 3 ) * m( 1, 0 ) * m( 2, 2 ) * m( 3, 1 )
337  - m( 0, 0 ) * m( 1, 3 ) * m( 2, 2 ) * m( 3, 1 )
338  - m( 0, 2 ) * m( 1, 0 ) * m( 2, 3 ) * m( 3, 1 )
339  + m( 0, 0 ) * m( 1, 2 ) * m( 2, 3 ) * m( 3, 1 )
340  + m( 0, 3 ) * m( 1, 1 ) * m( 2, 0 ) * m( 3, 2 )
341  - m( 0, 1 ) * m( 1, 3 ) * m( 2, 0 ) * m( 3, 2 )
342  - m( 0, 3 ) * m( 1, 0 ) * m( 2, 1 ) * m( 3, 2 )
343  + m( 0, 0 ) * m( 1, 3 ) * m( 2, 1 ) * m( 3, 2 )
344  + m( 0, 1 ) * m( 1, 0 ) * m( 2, 3 ) * m( 3, 2 )
345  - m( 0, 0 ) * m( 1, 1 ) * m( 2, 3 ) * m( 3, 2 )
346  - m( 0, 2 ) * m( 1, 1 ) * m( 2, 0 ) * m( 3, 3 )
347  + m( 0, 1 ) * m( 1, 2 ) * m( 2, 0 ) * m( 3, 3 )
348  + m( 0, 2 ) * m( 1, 0 ) * m( 2, 1 ) * m( 3, 3 )
349  - m( 0, 0 ) * m( 1, 2 ) * m( 2, 1 ) * m( 3, 3 )
350  - m( 0, 1 ) * m( 1, 0 ) * m( 2, 2 ) * m( 3, 3 )
351  + m( 0, 0 ) * m( 1, 1 ) * m( 2, 2 ) * m( 3, 3 );
352 }
353 
354 template< typename T >
355 Matrix< 1, 1, T > computeInverse( const Matrix< 1, 1, T >& m_ )
356 {
357  return Matrix< 1, 1, T >( std::vector< T >( T(1) / m_( 0, 0 ), 1 ));
358 }
359 
360 template< typename T >
361 Matrix< 2, 2, T > computeInverse( const Matrix< 2, 2, T >& m_ )
362 {
363  const T det = computeDeterminant( m_ );
364  if( std::abs( det ) < std::numeric_limits< T >::epsilon( ))
365  return Matrix< 2, 2, T >(
366  std::vector< T >( 4, std::numeric_limits< T >::quiet_NaN( )));
367 
368  Matrix< 2, 2, T > inverse;
369  m_.getAdjugate( inverse );
370  const T detinv = 1 / det;
371  inverse( 0, 0 ) *= detinv;
372  inverse( 0, 1 ) *= detinv;
373  inverse( 1, 0 ) *= detinv;
374  inverse( 1, 1 ) *= detinv;
375  return inverse;
376 }
377 
378 template< typename T >
379 Matrix< 3, 3, T > computeInverse( const Matrix< 3, 3, T >& m_ )
380 {
381  // Invert a 3x3 using cofactors. This is about 8 times faster than
382  // the Numerical Recipes code which uses Gaussian elimination.
383  Matrix< 3, 3, T > inverse;
384  inverse( 0, 0 ) = m_( 1, 1 ) * m_( 2, 2 ) - m_( 1, 2 ) * m_( 2, 1 );
385  inverse( 0, 1 ) = m_( 0, 2 ) * m_( 2, 1 ) - m_( 0, 1 ) * m_( 2, 2 );
386  inverse( 0, 2 ) = m_( 0, 1 ) * m_( 1, 2 ) - m_( 0, 2 ) * m_( 1, 1 );
387  inverse( 1, 0 ) = m_( 1, 2 ) * m_( 2, 0 ) - m_( 1, 0 ) * m_( 2, 2 );
388  inverse( 1, 1 ) = m_( 0, 0 ) * m_( 2, 2 ) - m_( 0, 2 ) * m_( 2, 0 );
389  inverse( 1, 2 ) = m_( 0, 2 ) * m_( 1, 0 ) - m_( 0, 0 ) * m_( 1, 2 );
390  inverse( 2, 0 ) = m_( 1, 0 ) * m_( 2, 1 ) - m_( 1, 1 ) * m_( 2, 0 );
391  inverse( 2, 1 ) = m_( 0, 1 ) * m_( 2, 0 ) - m_( 0, 0 ) * m_( 2, 1 );
392  inverse( 2, 2 ) = m_( 0, 0 ) * m_( 1, 1 ) - m_( 0, 1 ) * m_( 1, 0 );
393 
394  const T determinant = m_( 0, 0 ) * inverse( 0, 0 ) +
395  m_( 0, 1 ) * inverse( 1, 0 ) +
396  m_( 0, 2 ) * inverse( 2, 0 );
397 
398  if ( std::abs( determinant ) <= std::numeric_limits< T >::epsilon( ))
399  return Matrix< 3, 3, T >(
400  std::vector< T >( 9, std::numeric_limits< T >::quiet_NaN( )));
401 
402  const T detinv = static_cast< T >( 1.0 ) / determinant;
403 
404  inverse( 0, 0 ) *= detinv;
405  inverse( 0, 1 ) *= detinv;
406  inverse( 0, 2 ) *= detinv;
407  inverse( 1, 0 ) *= detinv;
408  inverse( 1, 1 ) *= detinv;
409  inverse( 1, 2 ) *= detinv;
410  inverse( 2, 0 ) *= detinv;
411  inverse( 2, 1 ) *= detinv;
412  inverse( 2, 2 ) *= detinv;
413  return inverse;
414 }
415 
416 template< typename T >
417 Matrix< 4, 4, T > computeInverse( const Matrix< 4, 4, T >& m_ )
418 {
419  const T* array = m_.array;
420 
421  // tuned version from Claude Knaus
422  /* first set of 2x2 determinants: 12 multiplications, 6 additions */
423  const T t1[6] = { array[ 2] * array[ 7] - array[ 6] * array[ 3],
424  array[ 2] * array[11] - array[10] * array[ 3],
425  array[ 2] * array[15] - array[14] * array[ 3],
426  array[ 6] * array[11] - array[10] * array[ 7],
427  array[ 6] * array[15] - array[14] * array[ 7],
428  array[10] * array[15] - array[14] * array[11] };
429 
430  /* first half of comatrix: 24 multiplications, 16 additions */
431  Matrix< 4, 4, T > inv;
432  inv.array[0] = array[ 5] * t1[5] - array[ 9] * t1[4] + array[13] * t1[3];
433  inv.array[1] = array[ 9] * t1[2] - array[13] * t1[1] - array[ 1] * t1[5];
434  inv.array[2] = array[13] * t1[0] - array[ 5] * t1[2] + array[ 1] * t1[4];
435  inv.array[3] = array[ 5] * t1[1] - array[ 1] * t1[3] - array[ 9] * t1[0];
436  inv.array[4] = array[ 8] * t1[4] - array[ 4] * t1[5] - array[12] * t1[3];
437  inv.array[5] = array[ 0] * t1[5] - array[ 8] * t1[2] + array[12] * t1[1];
438  inv.array[6] = array[ 4] * t1[2] - array[12] * t1[0] - array[ 0] * t1[4];
439  inv.array[7] = array[ 0] * t1[3] - array[ 4] * t1[1] + array[ 8] * t1[0];
440 
441  /* second set of 2x2 determinants: 12 multiplications, 6 additions */
442  const T t2[6] = { array[ 0] * array[ 5] - array[ 4] * array[ 1],
443  array[ 0] * array[ 9] - array[ 8] * array[ 1],
444  array[ 0] * array[13] - array[12] * array[ 1],
445  array[ 4] * array[ 9] - array[ 8] * array[ 5],
446  array[ 4] * array[13] - array[12] * array[ 5],
447  array[ 8] * array[13] - array[12] * array[ 9] };
448 
449  /* second half of comatrix: 24 multiplications, 16 additions */
450  inv.array[8] = array[ 7] * t2[5] - array[11] * t2[4] + array[15] * t2[3];
451  inv.array[9] = array[11] * t2[2] - array[15] * t2[1] - array[ 3] * t2[5];
452  inv.array[10] = array[15] * t2[0] - array[ 7] * t2[2] + array[ 3] * t2[4];
453  inv.array[11] = array[ 7] * t2[1] - array[ 3] * t2[3] - array[11] * t2[0];
454  inv.array[12] = array[10] * t2[4] - array[ 6] * t2[5] - array[14] * t2[3];
455  inv.array[13] = array[ 2] * t2[5] - array[10] * t2[2] + array[14] * t2[1];
456  inv.array[14] = array[ 6] * t2[2] - array[14] * t2[0] - array[ 2] * t2[4];
457  inv.array[15] = array[ 2] * t2[3] - array[ 6] * t2[1] + array[10] * t2[0];
458 
459  /* determinant: 4 multiplications, 3 additions */
460  const T determinant = array[0] * inv.array[0] + array[4] * inv.array[1] +
461  array[8] * inv.array[2] + array[12] * inv.array[3];
462 
463  if( std::abs( determinant ) <= std::numeric_limits< T >::epsilon( ))
464  return Matrix< 4, 4, T >(
465  std::vector< T >( 16, std::numeric_limits< T >::quiet_NaN( )));
466 
467  /* division: 16 multiplications, 1 division */
468  const T detinv = T( 1 ) / determinant;
469  for( size_t i = 0; i != 16; ++i )
470  inv.array[i] *= detinv;
471  return inv;
472 }
473 
474 template< size_t R, size_t C, typename T >
475 Matrix< R, C, T > computeInverse( const Matrix< R, C, T >& )
476 {
477  throw std::runtime_error( "Can't compute inverse of this matrix" );
478 }
479 
481 template< size_t R, size_t C, typename T > inline
483 {
484  Matrix< C, R, T > transposed;
485  for( size_t row = 0; row< R; ++row )
486  for( size_t col = 0; col < C; ++col )
487  transposed( col, row ) = matrix( row, col );
488  return transposed;
489 }
491 
492 template< size_t R, size_t C, typename T >
494  : array() // http://stackoverflow.com/questions/5602030
495 {
496  if( R == C )
497  for( size_t i = 0; i < R; ++i )
498  (*this)( i, i ) = 1;
499 }
500 
501 template< size_t R, size_t C, typename T >
502 Matrix< R, C, T >::Matrix( const T* begin_, const T* end_ )
503  : array() // http://stackoverflow.com/questions/5602030
504 {
505  const T* to = std::min( end_, begin_ + R * C );
506  ::memcpy( array, begin_, (to - begin_) * sizeof( T ));
507 }
508 
509 template< size_t R, size_t C, typename T >
510 Matrix< R, C, T >::Matrix( const std::vector< T >& values )
511 {
512  *this = values;
513 }
514 
515 template< size_t R, size_t C, typename T >
516 template< size_t P, size_t Q >
518 {
519  *this = source;
520 }
521 
522 template< size_t R, size_t C, typename T > template< size_t O >
524  const vector< O, T >& translation,
525  typename enable_if< R == O+1 && C == O+1 && O == 3 >::type* )
526 {
527  *this = rotation.getRotationMatrix();
528  setTranslation( translation );
529  (*this)( 3, 0 ) = 0;
530  (*this)( 3, 1 ) = 0;
531  (*this)( 3, 2 ) = 0;
532  (*this)( 3, 3 ) = 1;
533 }
534 
535 template< size_t R, size_t C, typename T > template< size_t S >
537  const vector< S, T >& lookat,
538  const vector< S, T >& up,
539  typename enable_if< R == S+1 && C == S+1 && S == 3 >::type* )
540  : array() // http://stackoverflow.com/questions/5602030
541 {
542  const vector< 3, T > f( vmml::normalize( lookat - eye ));
543  const vector< 3, T > s( vmml::normalize( vmml::cross( f, up )));
544  const vector< 3, T > u( vmml::cross( s, f ));
545 
546  (*this)( 0, 0 ) = s.x();
547  (*this)( 0, 1 ) = s.y();
548  (*this)( 0, 2 ) = s.z();
549  (*this)( 1, 0 ) = u.x();
550  (*this)( 1, 1 ) = u.y();
551  (*this)( 1, 2 ) = u.z();
552  (*this)( 2, 0 ) = -f.x();
553  (*this)( 2, 1 ) = -f.y();
554  (*this)( 2, 2 ) = -f.z();
555  (*this)( 0, 3 ) = -vmml::dot( s, eye );
556  (*this)( 1, 3 ) = -vmml::dot( u, eye );
557  (*this)( 2, 3 ) = vmml::dot( f, eye );
558  (*this)( 3, 3 ) = 1;
559 }
560 
561 template< size_t R, size_t C, typename T > inline
562 T& Matrix< R, C, T >::operator()( size_t rowIndex, size_t colIndex )
563 {
564  if ( rowIndex >= R || colIndex >= C )
565  throw std::runtime_error( "matrix( row, column ) index out of bounds" );
566  return array[ colIndex * R + rowIndex ];
567 }
568 
569 template< size_t R, size_t C, typename T > inline
570 T Matrix< R, C, T >::operator()( size_t rowIndex, size_t colIndex ) const
571 {
572  if ( rowIndex >= R || colIndex >= C )
573  throw std::runtime_error( "matrix( row, column ) index out of bounds" );
574  return array[ colIndex * R + rowIndex ];
575 }
576 
577 template< size_t R, size_t C, typename T >
579 {
580  for( size_t i = 0; i < R * C; ++i )
581  if( array[ i ] != other.array[ i ])
582  return false;
583  return true;
584 }
585 
586 template< size_t R, size_t C, typename T >
588 {
589  return ! operator==( other );
590 }
591 
592 template< size_t R, size_t C, typename T >
594  const T tolerance ) const
595 {
596  for( size_t i = 0; i < R * C; ++i )
597  if( std::abs( array[ i ] - other.array[ i ]) > tolerance )
598  return false;
599  return true;
600 }
601 
602 template< size_t R, size_t C, typename T > const Matrix< R, C, T >&
604 {
605  ::memcpy( array, source.array, R * C * sizeof( T ));
606  return *this;
607 }
608 
609 template< size_t R, size_t C, typename T > template< size_t P, size_t Q >
610 const Matrix< R, C, T >&
611 Matrix< R, C, T >::operator=( const Matrix< P, Q, T >& source )
612 {
613  const size_t minL = std::min( P, R );
614  const size_t minC = std::min( Q, C );
615 
616  for ( size_t i = 0 ; i < minL ; ++i )
617  for ( size_t j = 0 ; j < minC ; ++j )
618  (*this)( i, j ) = source( i, j );
619  for ( size_t i = minL ; i< R ; ++i )
620  for ( size_t j = minC ; j < C ; ++j )
621  (*this)( i, j ) = 0;
622  return *this;
623 }
624 
625 template< size_t R, size_t C, typename T >
626 void Matrix< R, C, T >::operator=( const std::vector< T >& values )
627 {
628  const size_t to = std::min( R * C, values.size( ));
629  ::memcpy( array, values.data(), to * sizeof( T ));
630  if( to < R * C )
631  {
632 #ifdef _WIN32
633  ::memset( array + to, 0, (R * C - to) * sizeof( T ));
634 #else
635  ::bzero( array + to, (R * C - to) * sizeof( T ));
636 #endif
637  }
638 }
639 
640 template< size_t R, size_t C, typename T > template< size_t P >
642  const Matrix< P, C, T >& right )
643 {
644  // Create copy for multiplication with self
645  if( &left == this )
646  return multiply( Matrix< R, P, T >( left ), right );
647  if( &right == this )
648  return multiply( left, Matrix< R, P, T >( right ));
649 
650  for( size_t rowIndex = 0; rowIndex< R; ++rowIndex )
651  {
652  for( size_t colIndex = 0; colIndex < C; ++colIndex )
653  {
654  T& component = (*this)( rowIndex, colIndex );
655  component = static_cast< T >( 0.0 );
656  for( size_t p = 0; p < P; p++)
657  component += left( rowIndex, p ) * right( p, colIndex );
658  }
659  }
660  return *this;
661 }
662 
663 template< size_t R, size_t C, typename T > template< size_t P >
665  const
666 {
667  Matrix< R, P, T > result;
668  return result.multiply( *this, other );
669 }
670 
671 #ifdef VMMLIB_USE_CXX03
672 template< size_t R, size_t C, typename T > template< size_t O, size_t P >
673 typename enable_if< R == C && O == P && R == O >::type*
674 #else
675 template< size_t R, size_t C, typename T > template< size_t O, size_t P, typename >
677 #endif
679 {
680  Matrix< R, C, T > copy( *this );
681  multiply( copy, right );
682 #ifdef VMMLIB_USE_CXX03
683  return 0;
684 #else
685  return *this;
686 #endif
687 }
688 
689 template< size_t R, size_t C, typename T >
691 {
692  vector< R, T > result;
693 
694  // this < R, 1 > = < R, P > * < P, 1 >
695  for( size_t i = 0; i< R; ++i )
696  {
697  T tmp( 0 );
698  for( size_t j = 0; j < C; ++j )
699  tmp += (*this)( i, j ) * vec( j );
700  result( i ) = tmp;
701  }
702  return result;
703 }
704 
705 template< size_t R, size_t C, typename T > inline
707 {
708  Matrix< R, C, T > result;
709  for( size_t i = 0; i< R * C; ++i )
710  result.array[ i ] = -array[ i ];
711  return result;
712 }
713 
714 template< size_t R, size_t C, typename T >
715 vector< R, T > Matrix< R, C, T >::getColumn( const size_t index ) const
716 {
717  if ( index >= C )
718  throw std::runtime_error( "getColumn() - index out of bounds." );
719  vector< R, T > column;
720  ::memcpy( &column.array[0], &array[ R * index ], R * sizeof( T ));
721  return column;
722 }
723 
724 template< size_t R, size_t C, typename T >
725 void Matrix< R, C, T >::setColumn( size_t index, const vector< R, T >& column )
726 {
727  if ( index >= C )
728  throw std::runtime_error( "setColumn() - index out of bounds." );
729  memcpy( array + R * index, column.array, R * sizeof( T ) );
730 }
731 
732 template< size_t R, size_t C, typename T >
733 vector< C, T > Matrix< R, C, T >::getRow( size_t index ) const
734 {
735  if ( index >= R )
736  throw std::runtime_error( "getRow() - index out of bounds." );
737 
738  vector< C, T > row;
739  for( size_t colIndex = 0; colIndex < C; ++colIndex )
740  row( colIndex ) = (*this)( index, colIndex );
741  return row;
742 }
743 
744 template< size_t R, size_t C, typename T >
745 void Matrix< R, C, T >::setRow( size_t rowIndex, const vector< C, T >& row )
746 {
747  if ( rowIndex >= R )
748  throw std::runtime_error( "setRow() - index out of bounds." );
749 
750  for( size_t colIndex = 0; colIndex < C; ++colIndex )
751  (*this)( rowIndex, colIndex ) = row( colIndex );
752 }
753 
754 template< size_t R, size_t C, typename T > inline
756  const
757 {
758  Matrix< R, C, T > result( *this );
759  result += other;
760  return result;
761 }
762 
763 template< size_t R, size_t C, typename T >
765 {
766  for( size_t i = 0; i < R * C; ++i )
767  array[i] += other.array[i];
768 }
769 
770 template< size_t R, size_t C, typename T > inline
772  const
773 {
774  Matrix< R, C, T > result( *this );
775  result -= other;
776  return result;
777 }
778 
779 template< size_t R, size_t C, typename T >
781 {
782  for( size_t i = 0; i < R * C; ++i )
783  array[i] -= other.array[i];
784 }
785 
786 template< size_t R, size_t C, typename T > template< size_t O, size_t P >
788  size_t colOffset,
789  typename enable_if< O <= R && P <= C >::type* ) const
790 {
791  Matrix< O, P, T > result;
792  if ( O + rowOffset > R || P + colOffset > C )
793  throw std::runtime_error( "index out of bounds." );
794 
795  for( size_t row = 0; row < O; ++row )
796  for( size_t col = 0; col < P; ++col )
797  result( row, col ) = (*this)( rowOffset + row, colOffset + col );
798 
799  return result;
800 }
801 
802 template< size_t R, size_t C, typename T > template< size_t O, size_t P >
805  size_t rowOffset, size_t colOffset )
806 {
807  for( size_t row = 0; row < O; ++row )
808  for( size_t col = 0; col < P; ++col )
809  (*this)( rowOffset + row, colOffset + col ) = sub_matrix( row, col);
810  return 0; // for sfinae
811 }
812 
813 template< size_t R, size_t C, typename T >
814 Matrix< R, C, T > Matrix< R, C, T >::inverse() const
815 {
816  return computeInverse( *this );
817 }
818 
819 template< size_t R, size_t C, typename T > template< size_t O, size_t P >
820 typename enable_if< O == P && R == C && O == R && R >= 2 >::type*
821 Matrix< R, C, T >::getAdjugate( Matrix< O, P, T >& adjugate ) const
822 {
823  getCofactors( adjugate );
824  adjugate = transpose( adjugate );
825  return 0;
826 }
827 
828 template< size_t R, size_t C, typename T > template< size_t O, size_t P >
829 typename enable_if< O == P && R == C && O == R && R >= 2 >::type*
830 Matrix< R, C, T >::getCofactors( Matrix< O, P, T >& cofactors ) const
831 {
832  Matrix< R-1, C-1, T > minor_;
833 
834  const size_t _negate = 1u;
835  for( size_t rowIndex = 0; rowIndex< R; ++rowIndex )
836  for( size_t colIndex = 0; colIndex < C; ++colIndex )
837  if ( ( rowIndex + colIndex ) & _negate )
838  cofactors( rowIndex, colIndex ) = -getMinor( minor_, rowIndex, colIndex );
839  else
840  cofactors( rowIndex, colIndex ) = getMinor( minor_, rowIndex, colIndex );
841 
842  return 0;
843 }
844 
845 template< size_t R, size_t C, typename T > template< size_t O, size_t P >
846 T Matrix< R, C, T >::getMinor( Matrix< O, P, T >& minor_, size_t row_to_cut,
847  size_t col_to_cut,
848  typename enable_if< O == R-1 && P == C-1 && R == C && R >= 2 >::type* ) const
849 {
850  size_t rowOffset = 0;
851  size_t colOffset = 0;
852  for( size_t rowIndex = 0; rowIndex< R; ++rowIndex )
853  {
854  if ( rowIndex == row_to_cut )
855  rowOffset = -1;
856  else
857  {
858  for( size_t colIndex = 0; colIndex < R; ++colIndex )
859  {
860  if ( colIndex == col_to_cut )
861  colOffset = -1;
862  else
863  minor_( rowIndex + rowOffset, colIndex + colOffset )
864  = (*this)( rowIndex, colIndex );
865  }
866  colOffset = 0;
867  }
868  }
869  return computeDeterminant( minor_ );
870 }
871 
872 template< size_t R, size_t C, typename T > template< typename TT >
873 Matrix< R, C, T >& Matrix< R, C, T >::rotate_x( const TT angle_,
874  typename enable_if< R == C && R == 4, TT >::type* )
875 {
876  const T angle = static_cast< T >( angle_ );
877  const T sine = std::sin( angle );
878  const T cosine = std::cos( angle );
879 
880  T tmp;
881 
882  tmp = array[ 4 ] * cosine + array[ 8 ] * sine;
883  array[ 8 ] = - array[ 4 ] * sine + array[ 8 ] * cosine;
884  array[ 4 ] = tmp;
885 
886  tmp = array[ 5 ] * cosine + array[ 9 ] * sine;
887  array[ 9 ] = - array[ 5 ] * sine + array[ 9 ] * cosine;
888  array[ 5 ] = tmp;
889 
890  tmp = array[ 6 ] * cosine + array[ 10 ] * sine;
891  array[ 10 ] = - array[ 6 ] * sine + array[ 10 ] * cosine;
892  array[ 6 ] = tmp;
893 
894  tmp = array[ 7 ] * cosine + array[ 11 ] * sine;
895  array[ 11 ] = - array[ 7 ] * sine + array[ 11 ] * cosine;
896  array[ 7 ] = tmp;
897 
898  return *this;
899 }
900 
901 template< size_t R, size_t C, typename T > template< typename TT >
902 Matrix< R, C, T >& Matrix< R, C, T >::rotate_y( const TT angle_,
903  typename enable_if< R == C && R == 4, TT >::type* )
904 {
905  const T angle = static_cast< T >( angle_ );
906  const T sine = std::sin( angle );
907  const T cosine = std::cos( angle );
908 
909  T tmp;
910 
911  tmp = array[ 0 ] * cosine - array[ 8 ] * sine;
912  array[ 8 ] = array[ 0 ] * sine + array[ 8 ] * cosine;
913  array[ 0 ] = tmp;
914 
915  tmp = array[ 1 ] * cosine - array[ 9 ] * sine;
916  array[ 9 ] = array[ 1 ] * sine + array[ 9 ] * cosine;
917  array[ 1 ] = tmp;
918 
919  tmp = array[ 2 ] * cosine - array[ 10 ] * sine;
920  array[ 10 ] = array[ 2 ] * sine + array[ 10 ] * cosine;
921  array[ 2 ] = tmp;
922 
923  tmp = array[ 3 ] * cosine - array[ 11 ] * sine;
924  array[ 11 ] = array[ 3 ] * sine + array[ 11 ] * cosine;
925  array[ 3 ] = tmp;
926 
927  return *this;
928 }
929 
930 template< size_t R, size_t C, typename T > template< typename TT >
931 Matrix< R, C, T >& Matrix< R, C, T >::rotate_z( const TT angle_,
932  typename enable_if< R == C && R == 4, TT >::type* )
933 {
934  const T angle = static_cast< T >( angle_ );
935  const T sine = std::sin( angle );
936  const T cosine = std::cos( angle );
937 
938  T tmp;
939 
940  tmp = array[ 0 ] * cosine + array[ 4 ] * sine;
941  array[ 4 ] = - array[ 0 ] * sine + array[ 4 ] * cosine;
942  array[ 0 ] = tmp;
943 
944  tmp = array[ 1 ] * cosine + array[ 5 ] * sine;
945  array[ 5 ] = - array[ 1 ] * sine + array[ 5 ] * cosine;
946  array[ 1 ] = tmp;
947 
948  tmp = array[ 2 ] * cosine + array[ 6 ] * sine;
949  array[ 6 ] = - array[ 2 ] * sine + array[ 6 ] * cosine;
950  array[ 2 ] = tmp;
951 
952  tmp = array[ 3 ] * cosine + array[ 7 ] * sine;
953  array[ 7 ] = - array[ 3 ] * sine + array[ 7 ] * cosine;
954  array[ 3 ] = tmp;
955 
956  return *this;
957 }
958 
959 template< size_t R, size_t C, typename T > template< typename TT >
960 Matrix< R, C, T >& Matrix< R, C, T >::pre_rotate_x( const TT angle_,
961  typename enable_if< R == C && R == 4, TT >::type* )
962 {
963  const T angle = static_cast< T >( angle_ );
964  const T sine = std::sin( angle );
965  const T cosine = std::cos( angle );
966 
967  T tmp;
968 
969  tmp = array[ 1 ];
970  array[ 1 ] = array[ 1 ] * cosine + array[ 2 ] * sine;
971  array[ 2 ] = tmp * -sine + array[ 2 ] * cosine;
972 
973  tmp = array[ 5 ];
974  array[ 5 ] = array[ 5 ] * cosine + array[ 6 ] * sine;
975  array[ 6 ] = tmp * -sine + array[ 6 ] * cosine;
976 
977  tmp = array[ 9 ];
978  array[ 9 ] = array[ 9 ] * cosine + array[ 10 ] * sine;
979  array[ 10 ] = tmp * -sine + array[ 10 ] * cosine;
980 
981  tmp = array[ 13 ];
982  array[ 13 ] = array[ 13 ] * cosine + array[ 14 ] * sine;
983  array[ 14 ] = tmp * -sine + array[ 14 ] * cosine;
984 
985  return *this;
986 }
987 
988 template< size_t R, size_t C, typename T > template< typename TT >
989 Matrix< R, C, T >& Matrix< R, C, T >::pre_rotate_y( const TT angle_,
990  typename enable_if< R == C && R == 4, TT >::type* )
991 {
992  const T angle = static_cast< T >( angle_ );
993  const T sine = std::sin( angle );
994  const T cosine = std::cos( angle );
995 
996  T tmp;
997 
998  tmp = array[ 0 ];
999  array[ 0 ] = array[ 0 ] * cosine - array[ 2 ] * sine;
1000  array[ 2 ] = tmp * sine + array[ 2 ] * cosine;
1001 
1002  tmp = array[ 4 ];
1003  array[ 4 ] = array[ 4 ] * cosine - array[ 6 ] * sine;
1004  array[ 6 ] = tmp * sine + array[ 6 ] * cosine;
1005 
1006  tmp = array[ 8 ];
1007  array[ 8 ] = array[ 8 ] * cosine - array[ 10 ] * sine;
1008  array[ 10 ] = tmp * sine + array[ 10 ] * cosine;
1009 
1010  tmp = array[ 12 ];
1011  array[ 12 ] = array[ 12 ] * cosine - array[ 14 ] * sine;
1012  array[ 14 ] = tmp * sine + array[ 14 ] * cosine;
1013 
1014  return *this;
1015 }
1016 
1017 template< size_t R, size_t C, typename T > template< typename TT >
1018 Matrix< R, C, T >& Matrix< R, C, T >::pre_rotate_z( const TT angle_,
1019  typename enable_if< R == C && R == 4, TT >::type* )
1020 {
1021  const T angle = static_cast< T >( angle_ );
1022  const T sine = std::sin( angle );
1023  const T cosine = std::cos( angle );
1024 
1025  T tmp;
1026 
1027  tmp = array[ 0 ];
1028  array[ 0 ] = array[ 0 ] * cosine + array[ 1 ] * sine;
1029  array[ 1 ] = tmp * -sine + array[ 1 ] * cosine;
1030 
1031  tmp = array[ 4 ];
1032  array[ 4 ] = array[ 4 ] * cosine + array[ 5 ] * sine;
1033  array[ 5 ] = tmp * -sine + array[ 5 ] * cosine;
1034 
1035  tmp = array[ 8 ];
1036  array[ 8 ] = array[ 8 ] * cosine + array[ 9 ] * sine;
1037  array[ 9 ] = tmp * -sine + array[ 9 ] * cosine;
1038 
1039  tmp = array[ 12 ];
1040  array[ 12 ] = array[ 12 ] * cosine + array[ 13 ] * sine;
1041  array[ 13 ] = tmp * -sine + array[ 13 ] * cosine;
1042 
1043  return *this;
1044 }
1045 
1046 template< size_t R, size_t C, typename T > template< typename TT > inline
1047 Matrix< R, C, T >& Matrix< R, C, T >::scale( const vector< 3, TT >& scale_,
1048  typename enable_if< R == C && R == 4, TT >::type* )
1049 {
1050  array[0] *= scale_[ 0 ];
1051  array[1] *= scale_[ 0 ];
1052  array[2] *= scale_[ 0 ];
1053  array[3] *= scale_[ 0 ];
1054  array[4] *= scale_[ 1 ];
1055  array[5] *= scale_[ 1 ];
1056  array[6] *= scale_[ 1 ];
1057  array[7] *= scale_[ 1 ];
1058  array[8] *= scale_[ 2 ];
1059  array[9] *= scale_[ 2 ];
1060  array[10] *= scale_[ 2 ];
1061  array[11] *= scale_[ 2 ];
1062  return *this;
1063 }
1064 
1065 
1066 template< size_t R, size_t C, typename T > template< typename TT > inline
1067 Matrix< R, C, T >& Matrix< R, C, T >::scaleTranslation(
1068  const vector< 3, TT >& scale_,
1069  typename enable_if< R == C && R == 4, TT >::type* )
1070 {
1071  array[12] *= static_cast< T >( scale_[0] );
1072  array[13] *= static_cast< T >( scale_[1] );
1073  array[14] *= static_cast< T >( scale_[2] );
1074  return *this;
1075 }
1076 
1077 
1078 template< size_t R, size_t C, typename T > inline Matrix< R, C, T >&
1079 Matrix< R, C, T >::setTranslation( const vector< C-1, T >& trans )
1080 {
1081  for( size_t i = 0; i < C-1; ++i )
1082  array[ i + R * (C - 1) ] = trans[ i ];
1083  return *this;
1084 }
1085 
1086 template< size_t R, size_t C, typename T > inline
1087 vector< C-1, T > Matrix< R, C, T >::getTranslation() const
1088 {
1089  vector< C-1, T > result;
1090  for( size_t i = 0; i < C-1; ++i )
1091  result[ i ] = array[ i + R * (C - 1) ];
1092  return result;
1093 }
1094 
1095 template< size_t R, size_t C, typename T > template< size_t S >
1096 void Matrix< R, C, T >::getLookAt( vector< S, T >& eye, vector< S, T >& lookAt,
1097  vector< S, T >& up,
1098  typename enable_if< R == S+1 && C == S+1 && S == 3 >::type* ) const
1099 {
1100  const Matrix< 4, 4, T >& inv = inverse();
1101  const Matrix< 3, 3, T > rotation( transpose( Matrix< 3, 3, T >( *this )));
1102 
1103  eye = inv * vector< 3, T >::ZERO;
1104  up = rotation * vector< 3, T >::UP;
1105  lookAt = rotation * vector< 3, T >::FORWARD;
1106  lookAt.normalize();
1107  lookAt = eye + lookAt;
1108 }
1109 
1110 } // namespace vmml
1111 
1112 #endif
Matrix< R, P, T > operator*(const Matrix< C, P, T > &other) const
Definition: matrix.hpp:664
Matrix operator+(const Matrix &other) const
Element-wise addition of two matrices.
Definition: matrix.hpp:755
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:578
Matrix< R, C, T > & operator*=(const Matrix< O, P, T > &right)
Multiply two square matrices.
Definition: matrix.hpp:678
Matrix()
Construct a zero-initialized matrix.
Definition: matrix.hpp:493
const T * data() const
Definition: matrix.hpp:155
T array[R *C]
column by column storage
Definition: matrix.hpp:292
Matrix operator-(const Matrix &other) const
Element-wise substraction of two matrices.
Definition: matrix.hpp:706
bool equals(const Matrix &other, T tolerance=std::numeric_limits< T >::epsilon()) const
Definition: matrix.hpp:593
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:780
T & operator()(size_t rowIndex, size_t colIndex)
Definition: matrix.hpp:562
Matrix< C, R, T > transpose(const Matrix< R, C, T > &matrix)
Definition: matrix.hpp:482
T array[M]
storage
Definition: vector.hpp:327
Matrix< 3, 3, T > getRotationMatrix() const
Definition: quaternion.hpp:447
bool operator!=(const Matrix &other) const
Definition: matrix.hpp:587
Matrix< O, P, T > getSubMatrix(size_t rowOffset, size_t colOffset, typename enable_if< O<=R &&P<=C >::type *=0) const
Definition: matrix.hpp:787
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:641
void operator+=(const Matrix &other)
Element-wise addition of two matrices.
Definition: matrix.hpp:764
Matrix with R rows and C columns of element type T.
Definition: matrix.hpp:51