vmmlib  1.13.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/types.hpp>
37 
38 #include <algorithm>
39 #include <cmath>
40 #include <cstring>
41 #include <iomanip>
42 #include <iostream>
43 #include <limits>
44 #include <stdexcept>
45 #include <type_traits>
46 #include <vector>
47 
48 namespace vmml
49 {
51 template <size_t R, size_t C, typename T>
52 class Matrix
53 {
54 public:
59  Matrix();
60 
65  Matrix(const T* begin, const T* end);
66 
71  explicit Matrix(const std::vector<T>& data);
72 
77  template <size_t P, size_t Q>
78  Matrix(const Matrix<P, Q, T>& source);
79 
84  template <size_t S>
85  Matrix(
86  const Quaternion<T>& rotation, const vector<S, T>& translation,
87  typename std::enable_if<R == S + 1 && C == S + 1 && S == 3>::type* = 0);
88 
93  template <size_t S>
94  Matrix(
95  const vector<S, T>& eye, const vector<S, T>& lookat,
96  const vector<S, T>& up,
97  typename std::enable_if<R == S + 1 && C == S + 1 && S == 3>::type* = 0);
98 
102  bool operator==(const Matrix& other) const;
103 
105  bool operator!=(const Matrix& other) const;
106 
108  bool equals(const Matrix& other,
109  T tolerance = std::numeric_limits<T>::epsilon()) const;
110 
112  template <size_t P>
114  const Matrix<P, C, T>& right);
115 
117  template <size_t P>
118  Matrix<R, P, T> operator*(const Matrix<C, P, T>& other) const;
119 
121  template <size_t O, size_t P, typename = typename std::enable_if<
122  R == C && O == P && R == O>::type>
124 
126  Matrix operator+(const Matrix& other) const;
127 
129  Matrix operator-(const Matrix& other) const;
130 
132  void operator+=(const Matrix& other);
133 
135  void operator-=(const Matrix& other);
137 
141  vector<R, T> operator*(const vector<C, T>& other) const;
143 
147  T& operator()(size_t rowIndex, size_t colIndex);
148 
150  T operator()(size_t rowIndex, size_t colIndex) const;
151 
153  const T* data() const { return array; }
155  template <size_t O, size_t P>
157  size_t rowOffset, size_t colOffset,
158  typename std::enable_if<O <= R && P <= C>::type* = 0) const;
159 
161  template <size_t O, size_t P>
162  typename std::enable_if<O <= R && P <= C>::type* setSubMatrix(
163  const Matrix<O, P, T>& sub_matrix, size_t rowOffset, size_t colOffset);
164 
166  const Matrix& operator=(const Matrix<R, C, T>& source_);
167 
173  template <size_t P, size_t Q>
174  const Matrix& operator=(const Matrix<P, Q, T>& source_);
175 
181  void operator=(const std::vector<T>& data);
182 
184  Matrix<R, C, T> operator-() const;
185 
187  vector<R, T> getColumn(size_t columnIndex) const;
188 
190  void setColumn(size_t index, const vector<R, T>& column);
191 
193  vector<C, T> getRow(size_t index) const;
194 
196  void setRow(size_t index, const vector<C, T>& row);
197 
199  vector<C - 1, T> getTranslation() const;
200 
202  Matrix<R, C, T>& setTranslation(const vector<C - 1, T>& t);
203 
208  template <size_t S>
209  void getLookAt(vector<S, T>& eye, vector<S, T>& lookAt, vector<S, T>& up,
210  typename std::enable_if<R == S + 1 && C == S + 1 &&
211  S == 3>::type* = 0) const;
213 
219  Matrix<R, C, T> inverse() const;
220 
221  template <size_t O, size_t P>
222  typename std::enable_if<O == P && R == C && O == R && R >= 2>::type*
223  getAdjugate(Matrix<O, P, T>& adjugate) const;
224 
225  template <size_t O, size_t P>
226  typename std::enable_if<O == P && R == C && O == R && R >= 2>::type*
227  getCofactors(Matrix<O, P, T>& cofactors) const;
228 
229  // returns the determinant of a square matrix R-1, C-1
230  template <size_t O, size_t P>
231  T getMinor(Matrix<O, P, T>& minor_, size_t row_to_cut, size_t col_to_cut,
232  typename std::enable_if<O == R - 1 && P == C - 1 && R == C &&
233  R >= 2>::type* = 0) const;
234 
237  template <typename TT>
238  Matrix<R, C, T>& rotate_x(
239  TT angle, typename std::enable_if<R == C && R == 4, TT>::type* = 0);
240 
241  template <typename TT>
242  Matrix<R, C, T>& rotate_y(
243  TT angle, typename std::enable_if<R == C && R == 4, TT>::type* = 0);
244 
245  template <typename TT>
246  Matrix<R, C, T>& rotate_z(
247  TT angle, typename std::enable_if<R == C && R == 4, TT>::type* = 0);
248 
249  template <typename TT>
250  Matrix<R, C, T>& pre_rotate_x(
251  TT angle, typename std::enable_if<R == C && R == 4, TT>::type* = 0);
252 
253  template <typename TT>
254  Matrix<R, C, T>& pre_rotate_y(
255  TT angle, typename std::enable_if<R == C && R == 4, TT>::type* = 0);
256 
257  template <typename TT>
258  Matrix<R, C, T>& pre_rotate_z(
259  TT angle, typename std::enable_if<R == C && R == 4, TT>::type* = 0);
260 
261  template <typename TT>
262  Matrix<R, C, T>& scale(
263  const vector<3, TT>& scale_,
264  typename std::enable_if<R == C && R == 4, TT>::type* = 0);
265 
266  template <typename TT>
267  Matrix<R, C, T>& scaleTranslation(
268  const vector<3, TT>& scale_,
269  typename std::enable_if<R == C && R == 4, TT>::type* = 0);
271 
272  friend std::ostream& operator<<(std::ostream& os,
273  const Matrix<R, C, T>& matrix)
274  {
275  const std::ios::fmtflags flags = os.flags();
276  const int prec = os.precision();
277 
278  os.setf(std::ios::right, std::ios::adjustfield);
279  os.precision(7);
280 
281  for (size_t rowIndex = 0; rowIndex < R; ++rowIndex)
282  {
283  os << "|";
284  for (size_t colIndex = 0; colIndex < C; ++colIndex)
285  os << std::setw(10) << matrix(rowIndex, colIndex) << " ";
286  os << "|" << std::endl;
287  }
288  os.precision(prec);
289  os.setf(flags);
290  return os;
291  };
292 
293  T array[R * C];
294 };
295 }
296 
297 #include <vmmlib/quaternion.hpp>
298 #include <vmmlib/vector.hpp>
299 
300 namespace vmml
301 {
304 template <typename T>
305 inline T computeDeterminant(const Matrix<1, 1, T>& matrix_)
306 {
307  return matrix_.array[0];
308 }
309 
310 template <typename T>
311 inline T computeDeterminant(const Matrix<2, 2, T>& matrix_)
312 {
313  return matrix_(0, 0) * matrix_(1, 1) - matrix_(0, 1) * matrix_(1, 0);
314 }
315 
316 template <typename T>
317 inline T computeDeterminant(const Matrix<3, 3, T>& m_)
318 {
319  return m_(0, 0) * (m_(1, 1) * m_(2, 2) - m_(1, 2) * m_(2, 1)) +
320  m_(0, 1) * (m_(1, 2) * m_(2, 0) - m_(1, 0) * m_(2, 2)) +
321  m_(0, 2) * (m_(1, 0) * m_(2, 1) - m_(1, 1) * m_(2, 0));
322 }
323 
324 template <typename T>
325 inline T computeDeterminant(const Matrix<4, 4, T>& m)
326 {
327  return m(0, 3) * m(1, 2) * m(2, 1) * m(3, 0) -
328  m(0, 2) * m(1, 3) * m(2, 1) * m(3, 0) -
329  m(0, 3) * m(1, 1) * m(2, 2) * m(3, 0) +
330  m(0, 1) * m(1, 3) * m(2, 2) * m(3, 0) +
331  m(0, 2) * m(1, 1) * m(2, 3) * m(3, 0) -
332  m(0, 1) * m(1, 2) * m(2, 3) * m(3, 0) -
333  m(0, 3) * m(1, 2) * m(2, 0) * m(3, 1) +
334  m(0, 2) * m(1, 3) * m(2, 0) * m(3, 1) +
335  m(0, 3) * m(1, 0) * m(2, 2) * m(3, 1) -
336  m(0, 0) * m(1, 3) * m(2, 2) * m(3, 1) -
337  m(0, 2) * m(1, 0) * m(2, 3) * m(3, 1) +
338  m(0, 0) * m(1, 2) * m(2, 3) * m(3, 1) +
339  m(0, 3) * m(1, 1) * m(2, 0) * m(3, 2) -
340  m(0, 1) * m(1, 3) * m(2, 0) * m(3, 2) -
341  m(0, 3) * m(1, 0) * m(2, 1) * m(3, 2) +
342  m(0, 0) * m(1, 3) * m(2, 1) * m(3, 2) +
343  m(0, 1) * m(1, 0) * m(2, 3) * m(3, 2) -
344  m(0, 0) * m(1, 1) * m(2, 3) * m(3, 2) -
345  m(0, 2) * m(1, 1) * m(2, 0) * m(3, 3) +
346  m(0, 1) * m(1, 2) * m(2, 0) * m(3, 3) +
347  m(0, 2) * m(1, 0) * m(2, 1) * m(3, 3) -
348  m(0, 0) * m(1, 2) * m(2, 1) * m(3, 3) -
349  m(0, 1) * m(1, 0) * m(2, 2) * m(3, 3) +
350  m(0, 0) * m(1, 1) * m(2, 2) * m(3, 3);
351 }
352 
353 template <typename T>
354 Matrix<1, 1, T> computeInverse(const Matrix<1, 1, T>& m_)
355 {
356  return Matrix<1, 1, T>(std::vector<T>(T(1) / m_(0, 0), 1));
357 }
358 
359 template <typename T>
360 Matrix<2, 2, T> computeInverse(const Matrix<2, 2, T>& m_)
361 {
362  const T det = computeDeterminant(m_);
363  if (std::abs(det) < std::numeric_limits<T>::epsilon())
364  return Matrix<2, 2, T>(
365  std::vector<T>(4, std::numeric_limits<T>::quiet_NaN()));
366 
367  Matrix<2, 2, T> inverse;
368  m_.getAdjugate(inverse);
369  const T detinv = 1 / det;
370  inverse(0, 0) *= detinv;
371  inverse(0, 1) *= detinv;
372  inverse(1, 0) *= detinv;
373  inverse(1, 1) *= detinv;
374  return inverse;
375 }
376 
377 template <typename T>
378 Matrix<3, 3, T> computeInverse(const Matrix<3, 3, T>& m_)
379 {
380  // Invert a 3x3 using cofactors. This is about 8 times faster than
381  // the Numerical Recipes code which uses Gaussian elimination.
382  Matrix<3, 3, T> inverse;
383  inverse(0, 0) = m_(1, 1) * m_(2, 2) - m_(1, 2) * m_(2, 1);
384  inverse(0, 1) = m_(0, 2) * m_(2, 1) - m_(0, 1) * m_(2, 2);
385  inverse(0, 2) = m_(0, 1) * m_(1, 2) - m_(0, 2) * m_(1, 1);
386  inverse(1, 0) = m_(1, 2) * m_(2, 0) - m_(1, 0) * m_(2, 2);
387  inverse(1, 1) = m_(0, 0) * m_(2, 2) - m_(0, 2) * m_(2, 0);
388  inverse(1, 2) = m_(0, 2) * m_(1, 0) - m_(0, 0) * m_(1, 2);
389  inverse(2, 0) = m_(1, 0) * m_(2, 1) - m_(1, 1) * m_(2, 0);
390  inverse(2, 1) = m_(0, 1) * m_(2, 0) - m_(0, 0) * m_(2, 1);
391  inverse(2, 2) = m_(0, 0) * m_(1, 1) - m_(0, 1) * m_(1, 0);
392 
393  const T determinant = m_(0, 0) * inverse(0, 0) + 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>
476 inline Matrix<C, R, T> transpose(const Matrix<R, C, T>& matrix)
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>
517 template <size_t O>
519  const Quaternion<T>& rotation, const vector<O, T>& translation,
520  typename std::enable_if<R == O + 1 && C == O + 1 && O == 3>::type*)
521 {
522  *this = rotation.getRotationMatrix();
523  setTranslation(translation);
524  (*this)(3, 0) = 0;
525  (*this)(3, 1) = 0;
526  (*this)(3, 2) = 0;
527  (*this)(3, 3) = 1;
528 }
529 
530 template <size_t R, size_t C, typename T>
531 template <size_t S>
533  const vector<S, T>& eye, const vector<S, T>& lookat, const vector<S, T>& up,
534  typename std::enable_if<R == S + 1 && C == S + 1 && S == 3>::type*)
535  : array() // http://stackoverflow.com/questions/5602030
536 {
537  const vector<3, T> f(vmml::normalize(lookat - eye));
538  const vector<3, T> s(vmml::normalize(vmml::cross(f, up)));
539  const vector<3, T> u(vmml::cross(s, f));
540 
541  (*this)(0, 0) = s.x();
542  (*this)(0, 1) = s.y();
543  (*this)(0, 2) = s.z();
544  (*this)(1, 0) = u.x();
545  (*this)(1, 1) = u.y();
546  (*this)(1, 2) = u.z();
547  (*this)(2, 0) = -f.x();
548  (*this)(2, 1) = -f.y();
549  (*this)(2, 2) = -f.z();
550  (*this)(0, 3) = -vmml::dot(s, eye);
551  (*this)(1, 3) = -vmml::dot(u, eye);
552  (*this)(2, 3) = vmml::dot(f, eye);
553  (*this)(3, 3) = 1;
554 }
555 
556 template <size_t R, size_t C, typename T>
557 inline T& Matrix<R, C, T>::operator()(size_t rowIndex, size_t colIndex)
558 {
559  if (rowIndex >= R || colIndex >= C)
560  throw std::runtime_error("matrix( row, column ) index out of bounds");
561  return array[colIndex * R + rowIndex];
562 }
563 
564 template <size_t R, size_t C, typename T>
565 inline T Matrix<R, C, T>::operator()(size_t rowIndex, size_t colIndex) const
566 {
567  if (rowIndex >= R || colIndex >= C)
568  throw std::runtime_error("matrix( row, column ) index out of bounds");
569  return array[colIndex * R + rowIndex];
570 }
571 
572 template <size_t R, size_t C, typename T>
574 {
575  for (size_t i = 0; i < R * C; ++i)
576  if (array[i] != other.array[i])
577  return false;
578  return true;
579 }
580 
581 template <size_t R, size_t C, typename T>
583 {
584  return !operator==(other);
585 }
586 
587 template <size_t R, size_t C, typename T>
589  const T tolerance) const
590 {
591  for (size_t i = 0; i < R * C; ++i)
592  if (std::abs(array[i] - other.array[i]) > tolerance)
593  return false;
594  return true;
595 }
596 
597 template <size_t R, size_t C, typename T>
599 {
600  ::memcpy(array, source.array, R * C * sizeof(T));
601  return *this;
602 }
603 
604 template <size_t R, size_t C, typename T>
605 template <size_t P, size_t Q>
607 {
608  const size_t minL = std::min(P, R);
609  const size_t minC = std::min(Q, C);
610 
611  for (size_t i = 0; i < minL; ++i)
612  for (size_t j = 0; j < minC; ++j)
613  (*this)(i, j) = source(i, j);
614  for (size_t i = minL; i < R; ++i)
615  for (size_t j = minC; j < C; ++j)
616  (*this)(i, j) = 0;
617  return *this;
618 }
619 
620 template <size_t R, size_t C, typename T>
621 void Matrix<R, C, T>::operator=(const std::vector<T>& values)
622 {
623  const size_t to = std::min(R * C, values.size());
624  ::memcpy(array, values.data(), to * sizeof(T));
625  if (to < R * C)
626  {
627 #ifdef _WIN32
628  ::memset(array + to, 0, (R * C - to) * sizeof(T));
629 #else
630  ::bzero(array + to, (R * C - to) * sizeof(T));
631 #endif
632  }
633 }
634 
635 template <size_t R, size_t C, typename T>
636 template <size_t P>
638  const Matrix<P, C, T>& right)
639 {
640  // Create copy for multiplication with self
641  if (&left == this)
642  return multiply(Matrix<R, P, T>(left), right);
643  if (&right == this)
644  return multiply(left, Matrix<R, P, T>(right));
645 
646  for (size_t rowIndex = 0; rowIndex < R; ++rowIndex)
647  {
648  for (size_t colIndex = 0; colIndex < C; ++colIndex)
649  {
650  T& component = (*this)(rowIndex, colIndex);
651  component = static_cast<T>(0.0);
652  for (size_t p = 0; p < P; p++)
653  component += left(rowIndex, p) * right(p, colIndex);
654  }
655  }
656  return *this;
657 }
658 
659 template <size_t R, size_t C, typename T>
660 template <size_t P>
662 {
663  Matrix<R, P, T> result;
664  return result.multiply(*this, other);
665 }
666 
667 template <size_t R, size_t C, typename T>
668 template <size_t O, size_t P, typename>
670 {
671  Matrix<R, C, T> copy(*this);
672  multiply(copy, right);
673  return *this;
674 }
675 
676 template <size_t R, size_t C, typename T>
678 {
679  vector<R, T> result;
680 
681  // this < R, 1 > = < R, P > * < P, 1 >
682  for (size_t i = 0; i < R; ++i)
683  {
684  T tmp(0);
685  for (size_t j = 0; j < C; ++j)
686  tmp += (*this)(i, j) * vec(j);
687  result(i) = tmp;
688  }
689  return result;
690 }
691 
692 template <size_t R, size_t C, typename T>
694 {
695  Matrix<R, C, T> result;
696  for (size_t i = 0; i < R * C; ++i)
697  result.array[i] = -array[i];
698  return result;
699 }
700 
701 template <size_t R, size_t C, typename T>
702 vector<R, T> Matrix<R, C, T>::getColumn(const size_t index) const
703 {
704  if (index >= C)
705  throw std::runtime_error("getColumn() - index out of bounds.");
706  vector<R, T> column;
707  ::memcpy(&column.array[0], &array[R * index], R * sizeof(T));
708  return column;
709 }
710 
711 template <size_t R, size_t C, typename T>
712 void Matrix<R, C, T>::setColumn(size_t index, const vector<R, T>& column)
713 {
714  if (index >= C)
715  throw std::runtime_error("setColumn() - index out of bounds.");
716  memcpy(array + R * index, column.array, R * sizeof(T));
717 }
718 
719 template <size_t R, size_t C, typename T>
720 vector<C, T> Matrix<R, C, T>::getRow(size_t index) const
721 {
722  if (index >= R)
723  throw std::runtime_error("getRow() - index out of bounds.");
724 
725  vector<C, T> row;
726  for (size_t colIndex = 0; colIndex < C; ++colIndex)
727  row(colIndex) = (*this)(index, colIndex);
728  return row;
729 }
730 
731 template <size_t R, size_t C, typename T>
732 void Matrix<R, C, T>::setRow(size_t rowIndex, const vector<C, T>& row)
733 {
734  if (rowIndex >= R)
735  throw std::runtime_error("setRow() - index out of bounds.");
736 
737  for (size_t colIndex = 0; colIndex < C; ++colIndex)
738  (*this)(rowIndex, colIndex) = row(colIndex);
739 }
740 
741 template <size_t R, size_t C, typename T>
743  const Matrix<R, C, T>& other) const
744 {
745  Matrix<R, C, T> result(*this);
746  result += other;
747  return result;
748 }
749 
750 template <size_t R, size_t C, typename T>
752 {
753  for (size_t i = 0; i < R * C; ++i)
754  array[i] += other.array[i];
755 }
756 
757 template <size_t R, size_t C, typename T>
759  const Matrix<R, C, T>& other) const
760 {
761  Matrix<R, C, T> result(*this);
762  result -= other;
763  return result;
764 }
765 
766 template <size_t R, size_t C, typename T>
768 {
769  for (size_t i = 0; i < R * C; ++i)
770  array[i] -= other.array[i];
771 }
772 
773 template <size_t R, size_t C, typename T>
774 template <size_t O, size_t P>
776  size_t rowOffset, size_t colOffset,
777  typename std::enable_if<O <= R && P <= C>::type*) const
778 {
779  Matrix<O, P, T> result;
780  if (O + rowOffset > R || P + colOffset > C)
781  throw std::runtime_error("index out of bounds.");
782 
783  for (size_t row = 0; row < O; ++row)
784  for (size_t col = 0; col < P; ++col)
785  result(row, col) = (*this)(rowOffset + row, colOffset + col);
786 
787  return result;
788 }
789 
790 template <size_t R, size_t C, typename T>
791 template <size_t O, size_t P>
792 typename std::enable_if<O <= R && P <= C>::type* Matrix<R, C, T>::setSubMatrix(
793  const Matrix<O, P, T>& sub_matrix, size_t rowOffset, size_t colOffset)
794 {
795  for (size_t row = 0; row < O; ++row)
796  for (size_t col = 0; col < P; ++col)
797  (*this)(rowOffset + row, colOffset + col) = sub_matrix(row, col);
798  return 0; // for sfinae
799 }
800 
801 template <size_t R, size_t C, typename T>
803 {
804  return computeInverse(*this);
805 }
806 
807 template <size_t R, size_t C, typename T>
808 template <size_t O, size_t P>
809 typename std::enable_if<O == P && R == C && O == R && R >= 2>::type*
811 {
812  getCofactors(adjugate);
813  adjugate = transpose(adjugate);
814  return 0;
815 }
816 
817 template <size_t R, size_t C, typename T>
818 template <size_t O, size_t P>
819 typename std::enable_if<O == P && R == C && O == R && R >= 2>::type*
821 {
822  Matrix<R - 1, C - 1, T> minor_;
823 
824  const size_t _negate = 1u;
825  for (size_t rowIndex = 0; rowIndex < R; ++rowIndex)
826  for (size_t colIndex = 0; colIndex < C; ++colIndex)
827  if ((rowIndex + colIndex) & _negate)
828  cofactors(rowIndex, colIndex) =
829  -getMinor(minor_, rowIndex, colIndex);
830  else
831  cofactors(rowIndex, colIndex) =
832  getMinor(minor_, rowIndex, colIndex);
833 
834  return 0;
835 }
836 
837 template <size_t R, size_t C, typename T>
838 template <size_t O, size_t P>
840  Matrix<O, P, T>& minor_, size_t row_to_cut, size_t col_to_cut,
841  typename std::enable_if<O == R - 1 && P == C - 1 && R == C &&
842  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>
867 template <typename TT>
869  const TT angle_, typename std::enable_if<R == C && R == 4, TT>::type*)
870 {
871  const T angle = static_cast<T>(angle_);
872  const T sine = std::sin(angle);
873  const T cosine = std::cos(angle);
874 
875  T tmp;
876 
877  tmp = array[4] * cosine + array[8] * sine;
878  array[8] = -array[4] * sine + array[8] * cosine;
879  array[4] = tmp;
880 
881  tmp = array[5] * cosine + array[9] * sine;
882  array[9] = -array[5] * sine + array[9] * cosine;
883  array[5] = tmp;
884 
885  tmp = array[6] * cosine + array[10] * sine;
886  array[10] = -array[6] * sine + array[10] * cosine;
887  array[6] = tmp;
888 
889  tmp = array[7] * cosine + array[11] * sine;
890  array[11] = -array[7] * sine + array[11] * cosine;
891  array[7] = tmp;
892 
893  return *this;
894 }
895 
896 template <size_t R, size_t C, typename T>
897 template <typename TT>
899  const TT angle_, typename std::enable_if<R == C && R == 4, TT>::type*)
900 {
901  const T angle = static_cast<T>(angle_);
902  const T sine = std::sin(angle);
903  const T cosine = std::cos(angle);
904 
905  T tmp;
906 
907  tmp = array[0] * cosine - array[8] * sine;
908  array[8] = array[0] * sine + array[8] * cosine;
909  array[0] = tmp;
910 
911  tmp = array[1] * cosine - array[9] * sine;
912  array[9] = array[1] * sine + array[9] * cosine;
913  array[1] = tmp;
914 
915  tmp = array[2] * cosine - array[10] * sine;
916  array[10] = array[2] * sine + array[10] * cosine;
917  array[2] = tmp;
918 
919  tmp = array[3] * cosine - array[11] * sine;
920  array[11] = array[3] * sine + array[11] * cosine;
921  array[3] = tmp;
922 
923  return *this;
924 }
925 
926 template <size_t R, size_t C, typename T>
927 template <typename TT>
929  const TT angle_, typename std::enable_if<R == C && R == 4, TT>::type*)
930 {
931  const T angle = static_cast<T>(angle_);
932  const T sine = std::sin(angle);
933  const T cosine = std::cos(angle);
934 
935  T tmp;
936 
937  tmp = array[0] * cosine + array[4] * sine;
938  array[4] = -array[0] * sine + array[4] * cosine;
939  array[0] = tmp;
940 
941  tmp = array[1] * cosine + array[5] * sine;
942  array[5] = -array[1] * sine + array[5] * cosine;
943  array[1] = tmp;
944 
945  tmp = array[2] * cosine + array[6] * sine;
946  array[6] = -array[2] * sine + array[6] * cosine;
947  array[2] = tmp;
948 
949  tmp = array[3] * cosine + array[7] * sine;
950  array[7] = -array[3] * sine + array[7] * cosine;
951  array[3] = tmp;
952 
953  return *this;
954 }
955 
956 template <size_t R, size_t C, typename T>
957 template <typename TT>
959  const TT angle_, typename std::enable_if<R == C && R == 4, TT>::type*)
960 {
961  const T angle = static_cast<T>(angle_);
962  const T sine = std::sin(angle);
963  const T cosine = std::cos(angle);
964 
965  T tmp;
966 
967  tmp = array[1];
968  array[1] = array[1] * cosine + array[2] * sine;
969  array[2] = tmp * -sine + array[2] * cosine;
970 
971  tmp = array[5];
972  array[5] = array[5] * cosine + array[6] * sine;
973  array[6] = tmp * -sine + array[6] * cosine;
974 
975  tmp = array[9];
976  array[9] = array[9] * cosine + array[10] * sine;
977  array[10] = tmp * -sine + array[10] * cosine;
978 
979  tmp = array[13];
980  array[13] = array[13] * cosine + array[14] * sine;
981  array[14] = tmp * -sine + array[14] * cosine;
982 
983  return *this;
984 }
985 
986 template <size_t R, size_t C, typename T>
987 template <typename TT>
989  const TT angle_, typename std::enable_if<R == C && R == 4, TT>::type*)
990 {
991  const T angle = static_cast<T>(angle_);
992  const T sine = std::sin(angle);
993  const T cosine = std::cos(angle);
994 
995  T tmp;
996 
997  tmp = array[0];
998  array[0] = array[0] * cosine - array[2] * sine;
999  array[2] = tmp * sine + array[2] * cosine;
1000 
1001  tmp = array[4];
1002  array[4] = array[4] * cosine - array[6] * sine;
1003  array[6] = tmp * sine + array[6] * cosine;
1004 
1005  tmp = array[8];
1006  array[8] = array[8] * cosine - array[10] * sine;
1007  array[10] = tmp * sine + array[10] * cosine;
1008 
1009  tmp = array[12];
1010  array[12] = array[12] * cosine - array[14] * sine;
1011  array[14] = tmp * sine + array[14] * cosine;
1012 
1013  return *this;
1014 }
1015 
1016 template <size_t R, size_t C, typename T>
1017 template <typename TT>
1019  const TT angle_, typename std::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>
1047 template <typename TT>
1049  const vector<3, TT>& scale_,
1050  typename std::enable_if<R == C && R == 4, TT>::type*)
1051 {
1052  array[0] *= scale_[0];
1053  array[1] *= scale_[0];
1054  array[2] *= scale_[0];
1055  array[3] *= scale_[0];
1056  array[4] *= scale_[1];
1057  array[5] *= scale_[1];
1058  array[6] *= scale_[1];
1059  array[7] *= scale_[1];
1060  array[8] *= scale_[2];
1061  array[9] *= scale_[2];
1062  array[10] *= scale_[2];
1063  array[11] *= scale_[2];
1064  return *this;
1065 }
1066 
1067 template <size_t R, size_t C, typename T>
1068 template <typename TT>
1070  const vector<3, TT>& scale_,
1071  typename std::enable_if<R == C && R == 4, TT>::type*)
1072 {
1073  array[12] *= static_cast<T>(scale_[0]);
1074  array[13] *= static_cast<T>(scale_[1]);
1075  array[14] *= static_cast<T>(scale_[2]);
1076  return *this;
1077 }
1078 
1079 template <size_t R, size_t C, typename T>
1081  const vector<C - 1, T>& trans)
1082 {
1083  for (size_t i = 0; i < C - 1; ++i)
1084  array[i + R * (C - 1)] = trans[i];
1085  return *this;
1086 }
1087 
1088 template <size_t R, size_t C, typename T>
1089 inline vector<C - 1, T> Matrix<R, C, T>::getTranslation() const
1090 {
1091  vector<C - 1, T> result;
1092  for (size_t i = 0; i < C - 1; ++i)
1093  result[i] = array[i + R * (C - 1)];
1094  return result;
1095 }
1096 
1097 template <size_t R, size_t C, typename T>
1098 template <size_t S>
1100  vector<S, T>& eye, vector<S, T>& lookAt, vector<S, T>& up,
1101  typename std::enable_if<R == S + 1 && C == S + 1 && S == 3>::type*) const
1102 {
1103  const Matrix<4, 4, T>& inv = inverse();
1104  const Matrix<3, 3, T> rotation(transpose(Matrix<3, 3, T>(*this)));
1105 
1106  eye = vector<S, T>(inv * vector<4, T>::zero());
1107  up = rotation * vector<3, T>::up();
1108  lookAt = rotation * vector<3, T>::forward();
1109  lookAt.normalize();
1110  lookAt = eye + lookAt;
1111 }
1112 
1113 } // namespace vmml
1114 
1115 #endif
Matrix< O, P, T > getSubMatrix(size_t rowOffset, size_t colOffset, typename std::enable_if< O<=R &&P<=C >::type *=0) const
Definition: matrix.hpp:775
Matrix< R, P, T > operator*(const Matrix< C, P, T > &other) const
Definition: matrix.hpp:661
Matrix operator+(const Matrix &other) const
Element-wise addition of two matrices.
Definition: matrix.hpp:742
bool operator==(const Matrix &other) const
Definition: matrix.hpp:573
Matrix< R, C, T > & operator*=(const Matrix< O, P, T > &right)
Multiply two square matrices.
Definition: matrix.hpp:669
Matrix()
Construct a zero-initialized matrix.
Definition: matrix.hpp:487
const T * data() const
Definition: matrix.hpp:153
T array[R *C]
column by column storage
Definition: matrix.hpp:291
Matrix operator-(const Matrix &other) const
Element-wise substraction of two matrices.
Definition: matrix.hpp:693
bool equals(const Matrix &other, T tolerance=std::numeric_limits< T >::epsilon()) const
Definition: matrix.hpp:588
Definition: aabb.hpp:44
void operator-=(const Matrix &other)
Element-wise substraction of two matrices.
Definition: matrix.hpp:767
T & operator()(size_t rowIndex, size_t colIndex)
Definition: matrix.hpp:557
T array[M]
storage
Definition: vector.hpp:317
Matrix< 3, 3, T > getRotationMatrix() const
Definition: quaternion.hpp:457
bool operator!=(const Matrix &other) const
Definition: matrix.hpp:582
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:637
void operator+=(const Matrix &other)
Element-wise addition of two matrices.
Definition: matrix.hpp:751
Matrix with R rows and C columns of element type T.
Definition: matrix.hpp:52
std::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 std::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 std::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 std::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.