GL Studio API
gls_matrix.h
Go to the documentation of this file.
1 /*! \file
2  \brief The GlsMatrix class.
3 
4  \par Copyright Information
5 
6  Copyright (c) 2015 by The DiSTI Corporation.<br>
7  11301 Corporate Blvd; Suite 100<br>
8  Orlando, Florida 32817<br>
9  USA<br>
10  <br>
11  All rights reserved.<br>
12 
13  This Software contains proprietary trade secrets of DiSTI and may not be
14 reproduced, in whole or part, in any form, or by any means of electronic,
15 mechanical, or otherwise, without the written permission of DiSTI. Said
16 permission may be derived through the purchase of applicable DiSTI product
17 licenses which detail the distribution rights of this content and any
18 Derivative Works based on this or other copyrighted DiSTI Software.
19 
20  NO WARRANTY. THE SOFTWARE IS PROVIDED "AS-IS," WITHOUT WARRANTY OF ANY KIND,
21 AND ANY USE OF THIS SOFTWARE PRODUCT IS AT YOUR OWN RISK. TO THE MAXIMUM EXTENT
22 PERMITTED BY APPLICABLE LAW, DISTI AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES
23 AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
24 IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY AND/OR FITNESS FOR A
25 PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT, WITH REGARD TO THE SOFTWARE.
26 
27  LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW,
28 IN NO EVENT SHALL DISTI OR ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
29 INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION,
30 DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS
31 INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR
32 INABILITY TO USE THE SOFTWARE, EVEN IF DISTI HAS BEEN ADVISED OF THE POSSIBILITY
33 OF SUCH DAMAGES. DISTI'S ENTIRE LIABILITY AND YOUR EXCLUSIVE REMEDY SHALL NOT
34 EXCEED FIVE DOLLARS (US$5.00).
35 
36  The aforementioned terms and restrictions are governed by the laws of the
37 State of Florida and the United States of America.
38 
39 */
40 #ifndef GLS_MATRIX_H
41 #define GLS_MATRIX_H
42 
43 #include <memory>
44 #include <cstring>
45 #include <math.h>
46 #include <iostream>
47 
48 namespace disti
49 {
50 
51 //----------------------------------------------------------------------------
52 /**
53 * The GlsMatrix class provides support for an n x n square matrix of any
54 * numeric type. Most basic matrix operations are supported. Internally,
55 * the matrix terms are stored contiguously in column-major order so that the
56 * matrix data can be passed to OpenGL matrix operations. However, instances
57 * of this class can be treated as row-major matrices since the API performs
58 * the conversion to column-major ordering for the user.
59 */
60 //----------------------------------------------------------------------------
61 template <class Type, int DIM = 4>
62 class GlsMatrix
63 {
64 public:
65  typedef Type CStyleMatrix[DIM][DIM];
66 
67  //------------------------------------------------------------------------
68  /**
69  * Default constructor. The new matrix will be the identity matrix.
70  */
71  //------------------------------------------------------------------------
72  GlsMatrix();
73 
74  //------------------------------------------------------------------------
75  /**
76  * Constructor. This will transpose m so that the matrix is stored in
77  * column-major order, but a caller can pass one in that is in row-major
78  * order, which is more intuitive.
79  *
80  * \param m a row-major, two-dimensional array to initialize the matrix
81  * with.
82  */
83  //------------------------------------------------------------------------
84  GlsMatrix(const CStyleMatrix m);
85 
86  //------------------------------------------------------------------------
87  /**
88  * Constructor.
89  *
90  * \param m a column-major, one-dimensional array containing all values
91  * to initialize the matrix with.
92  */
93  //------------------------------------------------------------------------
94  GlsMatrix(const Type* m);
95 
96  //------------------------------------------------------------------------
97  /**
98  * Copy Constructor.
99  *
100  * \param m matrix to copy.
101  */
102  //------------------------------------------------------------------------
104 
105  //------------------------------------------------------------------------
106  /**
107  * Destructor.
108  */
109  //------------------------------------------------------------------------
110  virtual ~GlsMatrix();
111 
112  //------------------------------------------------------------------------
113  /**
114  * Dump the contents of the matrix to standard output.
115  */
116  //------------------------------------------------------------------------
117  void Dump() const;
118 
119  //------------------------------------------------------------------------
120  /**
121  * Zero out the matrix so that all terms are equal to zero.
122  */
123  //------------------------------------------------------------------------
124  inline void Clear() { memset(_data, 0, sizeof(Type)*DIM*DIM); }
125 
126  //------------------------------------------------------------------------
127  /**
128  * Provides access to the raw column-major matrix data as a one dimensional
129  * array in a format suitable for Open GL matrix operations.
130  */
131  //------------------------------------------------------------------------
132  inline Type* Data() { return _data; }
133 
134  //------------------------------------------------------------------------
135  /**
136  * Provides access to the raw column-major matrix data as a one dimensional
137  * array in a format suitable for Open GL matrix operations.
138  */
139  //------------------------------------------------------------------------
140  inline const Type* Data() const { return _data; }
141 
142  //------------------------------------------------------------------------
143  /**
144  * Set this matrix to the identity matrix. The identity matrix is
145  * I = [Aij], where Aii = 1 and Aij = 0 for i != j. Thus, for the identity
146  * matrix, the terms off the main diagonal are all zero, and the terms on
147  * the main diagonal are all one.
148  */
149  //------------------------------------------------------------------------
150  void MakeIdentity();
151 
152  //------------------------------------------------------------------------
153  /**
154  * Calculates the determinant of the matrix.
155  *
156  * \return the calculated value of the determinant.
157  */
158  //------------------------------------------------------------------------
159  Type Determinant() const;
160 
161  //------------------------------------------------------------------------
162  /**
163  * Calculates the inverse of this matrix. The inverse of matrix A is B if
164  * AB = BA = I, where I is the identity matrix. The inverse of a matrix is
165  * the notion corresponding to the reciprocal of a nonzero real number.
166  *
167  * \return the inverse of this matrix.
168  */
169  //------------------------------------------------------------------------
171 
172  //------------------------------------------------------------------------
173  /**
174  * Sets this matrix equal to its inverse.
175  */
176  //------------------------------------------------------------------------
177  void Invert();
178 
179  //------------------------------------------------------------------------
180  /**
181  * Calculates the transpose of this matrix. The transpose of a matrix
182  * is obtained by interchanging its rows and columns.
183  *
184  * \return the transpose of this matrix.
185  */
186  //------------------------------------------------------------------------
188 
189  //------------------------------------------------------------------------
190  /**
191  * Sets this matrix equal to its transpose.
192  */
193  //------------------------------------------------------------------------
194  void Transpose();
195 
196  //------------------------------------------------------------------------
197  /**
198  * Determines if this is a diagonal matrix. An n x n matrix A = [Aij] is
199  * called a diagonal matrix if Aij = 0 for i != j. Thus, for a diagonal
200  * matrix, the terms off the main diagonal are all zero.
201  *
202  * \return true if the matrix is a diagonal matrix, false otherwise.
203  */
204  //------------------------------------------------------------------------
205  bool IsDiagonal() const;
206 
207  //------------------------------------------------------------------------
208  /**
209  * Determines if this matrix is equal to the identity matrix. The
210  * identity matrix is I = [Aij], where Aii = 1 and Aij = 0 for i != j.
211  * Thus, for the identity matrix, the terms off the main diagonal are all
212  * zero, and the terms on the main diagonal are all one.
213  *
214  * \return true if the matrix is the identity matrix, false otherwise.
215  */
216  //------------------------------------------------------------------------
217  bool IsIdentity() const;
218 
219  //------------------------------------------------------------------------
220  /**
221  * Determines if this is a scalar matrix. A scalar matrix is a diagonal
222  * matrix whose diagonal terms are equal.
223  *
224  * \return true if the matrix is a scalar matrix, false otherwise.
225  */
226  //------------------------------------------------------------------------
227  bool IsScalar() const;
228 
229  //------------------------------------------------------------------------
230  /**
231  * Determines if this matrix is singular, or non-invertible. A singular
232  * matrix has no inverse.
233  *
234  * \return true if the matrix is singular, false otherwise.
235  */
236  //------------------------------------------------------------------------
237  bool IsSingular() const;
238 
239  //------------------------------------------------------------------------
240  /**
241  * Determines if this matrix is symmetric. A matrix is symmetric if it is
242  * equal to its transpose, i.e. A = A'.
243  *
244  * \return true if the matrix is symmetric, false otherwise.
245  */
246  //------------------------------------------------------------------------
247  bool IsSymmetric() const;
248 
249  //------------------------------------------------------------------------
250  /**
251  * Determines if this matrix is skew symmetric. A matrix is skew symmetric
252  * if its transpose is equal to its negative, i.e. -A = A'.
253  *
254  * \return true if the matrix is skew symmetric, false otherwise.
255  */
256  //------------------------------------------------------------------------
257  bool IsSkewSymmetric() const;
258 
259  //------------------------------------------------------------------------
260  /**
261  * Determines if this matrix is lower triangular. An n x n matrix A = [Aij]
262  * is lower triangular if Aij = 0 for i < j.
263  *
264  * \return true if the matrix is lower triangular, false otherwise.
265  */
266  //------------------------------------------------------------------------
267  bool IsLowerTriangular() const;
268 
269  //------------------------------------------------------------------------
270  /**
271  * Determines if this matrix is upper triangular. An n x n matrix A = [Aij]
272  * is upper triangular if Aij = 0 for i > j.
273  *
274  * \return true if the matrix is upper triangular, false otherwise.
275  */
276  //------------------------------------------------------------------------
277  bool IsUpperTriangular() const;
278 
279  //------------------------------------------------------------------------
280  // Operators
281  //------------------------------------------------------------------------
282  // Subscript operator (zero-based)
283  Type& operator () (unsigned row, unsigned col);
284  Type operator () (unsigned row, unsigned col) const;
285 
286  // Equality operators
287  bool operator == (const GlsMatrix<Type,DIM>& rhs) const;
288  bool operator != (const GlsMatrix<Type,DIM>& rhs) const;
289 
290  // Assignment operators
291  GlsMatrix<Type, DIM>& operator = (const GlsMatrix<Type,DIM>& m);
292  GlsMatrix<Type, DIM>& operator = (const CStyleMatrix m);
293 
294  // Unary operators
295  GlsMatrix<Type, DIM> operator + () const { return *this; }
296  GlsMatrix<Type, DIM> operator - () const;
297 
298  // Combined assignment - calculation operators
299  GlsMatrix<Type, DIM>& operator += (const GlsMatrix<Type,DIM>& rhs);
300  GlsMatrix<Type, DIM>& operator -= (const GlsMatrix<Type,DIM>& rhs);
301  GlsMatrix<Type, DIM>& operator *= (const GlsMatrix<Type,DIM>& rhs);
302  GlsMatrix<Type, DIM>& operator *= (Type scalar);
303  GlsMatrix<Type, DIM>& operator /= (Type scalar);
304 
305  // Mathematical operators
306  GlsMatrix<Type, DIM> operator + (const GlsMatrix<Type,DIM>& rhs) const;
307  GlsMatrix<Type, DIM> operator - (const GlsMatrix<Type,DIM>& rhs) const;
308  GlsMatrix<Type, DIM> operator * (const GlsMatrix<Type,DIM>& rhs) const;
309  GlsMatrix<Type, DIM> operator * (Type scalar) const;
310  GlsMatrix<Type, DIM> operator / (Type scalar) const;
311 
312 protected:
313  /** A very tiny number, close to zero. Used to compare floats */
314  static const double PRECISION;
315 
316  /**
317  * This is the actual matrix data stored in column-major ordering in
318  * a one-dimensional array of the appropriate size to store all matrix
319  * terms. The data is stored in this manner so that it can be passed
320  * to OpenGL matrix operations, which expect matrices to be ordered
321  * this way.
322  */
323  Type _data[DIM*DIM];
324 
325  /**
326  * A column index array. Each element in this array "points"
327  * to a column of the matrix within the above data. By using this index,
328  * we can address matrix terms using two dimensions, column and row,
329  * without incurring a multiplication. Eg. matrix[0] points to a column
330  * within data, which is the address of the first term in the column.
331  * We can further address into the column and access a particular row
332  * by adding another dimension, eg. matrix[0][1]. The indices must
333  * be set up at construction time.
334  */
335  Type* _matrix[DIM];
336 
337  //------------------------------------------------------------------------
338  /**
339  * This should be called from all constructors, as it initializes the
340  * matrix column index so that matrix elements can be addressed in two
341  * dimensions, but a multiplication is not incurred when doing so.
342  */
343  //------------------------------------------------------------------------
344  void Initialize();
345 
346  //------------------------------------------------------------------------
347  /**
348  * Pivoting is used in conjunction with Gauss-Jordan reduction to find
349  * the inverse of a matrix and in Gaussian Elimination to find the
350  * determinant of a matrix. It involves the elementary row operation of
351  * interchanging rows (or columns in our column-major matrix). Only the
352  * row passed in and rows below it are considered. The row passed in
353  * will be swapped with another row below it by selecting the desired
354  * pivot element. The pivot is the largest term (in magnitude) in
355  * the column equal to row for any of the considered rows. This will
356  * always put the largest (in magnitude) term from the column on the
357  * diagonal of the matrix.
358  *
359  * \param row is the current row to pivot about. Rows above this are not
360  * considered during pivoting, as these rows should already be in
361  * their proper form.
362  */
363  //------------------------------------------------------------------------
364  int Pivot(unsigned row);
365 
366  //------------------------------------------------------------------------
367  /**
368  * Decides if the two values are close together determined by the
369  * constant PRECISION. The formula is
370  * lv - PRECISION < rv < lv + PRECISION
371  *
372  * \param lv left value
373  * \param rv right value
374  */
375  //------------------------------------------------------------------------
376  bool closeValues(Type lv, Type rv) const;
377 };
378 
379 
380 
381 //============================================================================
382 //
383 // CLASS IMPLEMENTATION
384 //
385 //============================================================================
386 
387 //----------------------------------------------------------------------------
388 template<class Type, int DIM>
389 const double GlsMatrix<Type, DIM>::PRECISION = 1e-7;
390 
391 //----------------------------------------------------------------------------
392 template<class Type, int DIM>
394 {
395  Initialize();
396  MakeIdentity();
397 }
398 //----------------------------------------------------------------------------
399 template<class Type, int DIM>
400 GlsMatrix<Type, DIM>::GlsMatrix(const CStyleMatrix m)
401 {
402  Initialize();
403  for (int row = 0; row < DIM; ++row)
404  {
405  for (int col = 0; col < DIM; ++col)
406  {
407  _matrix[col][row] = m[row][col];
408  }
409  }
410 }
411 //----------------------------------------------------------------------------
412 template<class Type, int DIM>
414 {
415  Initialize();
416  memcpy(_data, m, sizeof(Type)*DIM*DIM);
417 }
418 //----------------------------------------------------------------------------
419 template<class Type, int DIM>
421 {
422  Initialize();
423  memcpy(_data, m._data, sizeof(Type)*DIM*DIM);
424 }
425 //----------------------------------------------------------------------------
426 template<class Type, int DIM>
428 {
429 }
430 //----------------------------------------------------------------------------
431 template<>
432 inline
435 {
436  GlsMatrix<double, 4> result;
437 
438  // Same as regular, just unroll the loop
439  result._matrix[0][0] = _matrix[0][0] * rhs._matrix[0][0] + _matrix[1][0] * rhs._matrix[0][1] + _matrix[2][0] * rhs._matrix[0][2] + _matrix[3][0] * rhs._matrix[0][3];
440  result._matrix[1][0] = _matrix[0][0] * rhs._matrix[1][0] + _matrix[1][0] * rhs._matrix[1][1] + _matrix[2][0] * rhs._matrix[1][2] + _matrix[3][0] * rhs._matrix[1][3];
441  result._matrix[2][0] = _matrix[0][0] * rhs._matrix[2][0] + _matrix[1][0] * rhs._matrix[2][1] + _matrix[2][0] * rhs._matrix[2][2] + _matrix[3][0] * rhs._matrix[2][3];
442  result._matrix[3][0] = _matrix[0][0] * rhs._matrix[3][0] + _matrix[1][0] * rhs._matrix[3][1] + _matrix[2][0] * rhs._matrix[3][2] + _matrix[3][0] * rhs._matrix[3][3];
443  result._matrix[0][1] = _matrix[0][1] * rhs._matrix[0][0] + _matrix[1][1] * rhs._matrix[0][1] + _matrix[2][1] * rhs._matrix[0][2] + _matrix[3][1] * rhs._matrix[0][3];
444  result._matrix[1][1] = _matrix[0][1] * rhs._matrix[1][0] + _matrix[1][1] * rhs._matrix[1][1] + _matrix[2][1] * rhs._matrix[1][2] + _matrix[3][1] * rhs._matrix[1][3];
445  result._matrix[2][1] = _matrix[0][1] * rhs._matrix[2][0] + _matrix[1][1] * rhs._matrix[2][1] + _matrix[2][1] * rhs._matrix[2][2] + _matrix[3][1] * rhs._matrix[2][3];
446  result._matrix[3][1] = _matrix[0][1] * rhs._matrix[3][0] + _matrix[1][1] * rhs._matrix[3][1] + _matrix[2][1] * rhs._matrix[3][2] + _matrix[3][1] * rhs._matrix[3][3];
447  result._matrix[0][2] = _matrix[0][2] * rhs._matrix[0][0] + _matrix[1][2] * rhs._matrix[0][1] + _matrix[2][2] * rhs._matrix[0][2] + _matrix[3][2] * rhs._matrix[0][3];
448  result._matrix[1][2] = _matrix[0][2] * rhs._matrix[1][0] + _matrix[1][2] * rhs._matrix[1][1] + _matrix[2][2] * rhs._matrix[1][2] + _matrix[3][2] * rhs._matrix[1][3];
449  result._matrix[2][2] = _matrix[0][2] * rhs._matrix[2][0] + _matrix[1][2] * rhs._matrix[2][1] + _matrix[2][2] * rhs._matrix[2][2] + _matrix[3][2] * rhs._matrix[2][3];
450  result._matrix[3][2] = _matrix[0][2] * rhs._matrix[3][0] + _matrix[1][2] * rhs._matrix[3][1] + _matrix[2][2] * rhs._matrix[3][2] + _matrix[3][2] * rhs._matrix[3][3];
451  result._matrix[0][3] = _matrix[0][3] * rhs._matrix[0][0] + _matrix[1][3] * rhs._matrix[0][1] + _matrix[2][3] * rhs._matrix[0][2] + _matrix[3][3] * rhs._matrix[0][3];
452  result._matrix[1][3] = _matrix[0][3] * rhs._matrix[1][0] + _matrix[1][3] * rhs._matrix[1][1] + _matrix[2][3] * rhs._matrix[1][2] + _matrix[3][3] * rhs._matrix[1][3];
453  result._matrix[2][3] = _matrix[0][3] * rhs._matrix[2][0] + _matrix[1][3] * rhs._matrix[2][1] + _matrix[2][3] * rhs._matrix[2][2] + _matrix[3][3] * rhs._matrix[2][3];
454  result._matrix[3][3] = _matrix[0][3] * rhs._matrix[3][0] + _matrix[1][3] * rhs._matrix[3][1] + _matrix[2][3] * rhs._matrix[3][2] + _matrix[3][3] * rhs._matrix[3][3];
455 
456  return result;
457 }
458 //----------------------------------------------------------------------------
459 template<>
460 inline
461 GlsMatrix<float, 4>
462 GlsMatrix<float, 4>::operator * (const GlsMatrix<float, 4>& rhs) const
463 {
464  GlsMatrix<float, 4> result;
465 
466  // Same as regular, just unroll the loop
467  result._matrix[0][0] = _matrix[0][0] * rhs._matrix[0][0] + _matrix[1][0] * rhs._matrix[0][1] + _matrix[2][0] * rhs._matrix[0][2] + _matrix[3][0] * rhs._matrix[0][3];
468  result._matrix[1][0] = _matrix[0][0] * rhs._matrix[1][0] + _matrix[1][0] * rhs._matrix[1][1] + _matrix[2][0] * rhs._matrix[1][2] + _matrix[3][0] * rhs._matrix[1][3];
469  result._matrix[2][0] = _matrix[0][0] * rhs._matrix[2][0] + _matrix[1][0] * rhs._matrix[2][1] + _matrix[2][0] * rhs._matrix[2][2] + _matrix[3][0] * rhs._matrix[2][3];
470  result._matrix[3][0] = _matrix[0][0] * rhs._matrix[3][0] + _matrix[1][0] * rhs._matrix[3][1] + _matrix[2][0] * rhs._matrix[3][2] + _matrix[3][0] * rhs._matrix[3][3];
471  result._matrix[0][1] = _matrix[0][1] * rhs._matrix[0][0] + _matrix[1][1] * rhs._matrix[0][1] + _matrix[2][1] * rhs._matrix[0][2] + _matrix[3][1] * rhs._matrix[0][3];
472  result._matrix[1][1] = _matrix[0][1] * rhs._matrix[1][0] + _matrix[1][1] * rhs._matrix[1][1] + _matrix[2][1] * rhs._matrix[1][2] + _matrix[3][1] * rhs._matrix[1][3];
473  result._matrix[2][1] = _matrix[0][1] * rhs._matrix[2][0] + _matrix[1][1] * rhs._matrix[2][1] + _matrix[2][1] * rhs._matrix[2][2] + _matrix[3][1] * rhs._matrix[2][3];
474  result._matrix[3][1] = _matrix[0][1] * rhs._matrix[3][0] + _matrix[1][1] * rhs._matrix[3][1] + _matrix[2][1] * rhs._matrix[3][2] + _matrix[3][1] * rhs._matrix[3][3];
475  result._matrix[0][2] = _matrix[0][2] * rhs._matrix[0][0] + _matrix[1][2] * rhs._matrix[0][1] + _matrix[2][2] * rhs._matrix[0][2] + _matrix[3][2] * rhs._matrix[0][3];
476  result._matrix[1][2] = _matrix[0][2] * rhs._matrix[1][0] + _matrix[1][2] * rhs._matrix[1][1] + _matrix[2][2] * rhs._matrix[1][2] + _matrix[3][2] * rhs._matrix[1][3];
477  result._matrix[2][2] = _matrix[0][2] * rhs._matrix[2][0] + _matrix[1][2] * rhs._matrix[2][1] + _matrix[2][2] * rhs._matrix[2][2] + _matrix[3][2] * rhs._matrix[2][3];
478  result._matrix[3][2] = _matrix[0][2] * rhs._matrix[3][0] + _matrix[1][2] * rhs._matrix[3][1] + _matrix[2][2] * rhs._matrix[3][2] + _matrix[3][2] * rhs._matrix[3][3];
479  result._matrix[0][3] = _matrix[0][3] * rhs._matrix[0][0] + _matrix[1][3] * rhs._matrix[0][1] + _matrix[2][3] * rhs._matrix[0][2] + _matrix[3][3] * rhs._matrix[0][3];
480  result._matrix[1][3] = _matrix[0][3] * rhs._matrix[1][0] + _matrix[1][3] * rhs._matrix[1][1] + _matrix[2][3] * rhs._matrix[1][2] + _matrix[3][3] * rhs._matrix[1][3];
481  result._matrix[2][3] = _matrix[0][3] * rhs._matrix[2][0] + _matrix[1][3] * rhs._matrix[2][1] + _matrix[2][3] * rhs._matrix[2][2] + _matrix[3][3] * rhs._matrix[2][3];
482  result._matrix[3][3] = _matrix[0][3] * rhs._matrix[3][0] + _matrix[1][3] * rhs._matrix[3][1] + _matrix[2][3] * rhs._matrix[3][2] + _matrix[3][3] * rhs._matrix[3][3];
483 
484  return result;
485 }
486 //----------------------------------------------------------------------------
487 template<class Type, int DIM>
488 inline
489 GlsMatrix<Type, DIM>
490 GlsMatrix<Type, DIM>::operator * (const GlsMatrix<Type, DIM>& rhs) const
491 {
492  GlsMatrix<Type,DIM> result;
493  memset(result._data, 0, sizeof(Type) * DIM * DIM);
494  for (int row = 0; row < DIM; ++row)
495  {
496  for (int col = 0; col < DIM; ++col)
497  {
498  for (int i = 0; i < DIM; ++i)
499  {
500  result._matrix[col][row] += _matrix[i][row] * rhs._matrix[col][i];
501  }
502  }
503  }
504  return result;
505 }
506 //----------------------------------------------------------------------------
507 template<class Type, int DIM>
508 inline
509 GlsMatrix<Type, DIM> GlsMatrix<Type, DIM>::operator * (Type scalar) const
510 {
511  GlsMatrix<Type, DIM> result;
512  for (int row = 0; row < DIM; ++row)
513  {
514  for (int col = 0; col < DIM; ++col)
515  {
516  result._matrix[col][row] = _matrix[col][row] * scalar;
517  }
518  }
519  return result;
520 }
521 //----------------------------------------------------------------------------
522 template<class Type, int DIM>
524 {
525  for (int row = 0; row < DIM; ++row)
526  {
527  for (int col = 0; col < DIM; ++col)
528  {
529  std::cout.width(11);
530  std::cout << _matrix[col][row] << ' ';
531  }
532  std::cout << std::endl;
533  }
534  std::cout << std::endl;
535 }
536 //----------------------------------------------------------------------------
537 template<class Type, int DIM>
538 inline
540 {
541  Clear();
542  for (int i = 0; i < DIM; ++i)
543  {
544  _matrix[i][i] = Type(1);
545  }
546 }
547 //----------------------------------------------------------------------------
548 template<class Type, int DIM>
550 {
551  // In this algorithm we use gaussian elimination with pivoting to reduce
552  // the matrix to an upper triangular form. The determinant of an
553  // upper triangular matrix is the product of the terms on the diagonal.
554  // To perform the elimination, we will use two types of elementary row
555  // operations on the matrix.
556  // 1) Interchanging rows of the matrix.
557  // 2) Add c times row i of the matrix to row j where i != j.
558  //
559  // The first operation of interchanging rows prevents numerical
560  // instability, and the second allows us to zero out terms below
561  // the diagonal by choosing c appropriately.
562 
563  Type pivotFactor;
564  Type det = Type(1);
565 
566  // Make a temporary copy of the matrix so the original is not destroyed
567  // during gaussian elimination and pivoting
568  GlsMatrix<Type,DIM> temp(*this);
569 
570  // Loop through each row in the matrix
571  for (int k = 0; k < DIM; ++k)
572  {
573  // Perform pivoting
574  int index = temp.Pivot(k);
575 
576  // If pivot returns a -1, then a zero exists on the diagonal
577  // so the determinant will be zero.
578  if (index == -1)
579  return 0;
580  // If pivot returns a number other than zero, rows have been
581  // interchanged, so we need to change the sign of the determinant
582  // due to the theorem that states "If matrix B results from A by
583  // interchanging two rows (columns) of A, then det(B) = - det(A).
584  if (index != 0)
585  det = -det;
586 
587  // The determinant will be the product of the diagonal terms. The
588  // row that the [k][k] term is in already has the proper form
589  // for an upper triangular matrix, so go ahead and use it in the det.
590  det *= temp._matrix[k][k];
591 
592  // Since we are using the diagonal element from row k, column k, we
593  // need all other terms below this element, in column k, to be
594  // zero. We do this by an elementary operation (2) above to each
595  // row below this diagonal element.
596  for (int i = k+1; i < DIM; ++i)
597  {
598  // Choose the pivot factor that would zero out the [i][k]term
599  // when multiplied by the kth row and subtracted from the
600  // ith row.
601  pivotFactor = temp._matrix[i][k] / temp._matrix[k][k];
602 
603  // Perform the operation on each term in the row to the right
604  // of the pivot. The terms to the left are assumed to be zero
605  // and we never reference them again so no need to waste time
606  // processing them.
607  for (int j = k+1; j < DIM; ++j)
608  {
609  temp._matrix[i][j] -= pivotFactor * temp._matrix[k][j];
610  }
611  }
612  }
613  return det;
614 }
615 //----------------------------------------------------------------------------
616 template<class Type, int DIM>
618 {
619  // In this algorithm we use Gauss-Jordan reduction with pivoting to
620  // transform the original matrix to the identity matrix, all the while
621  // performing the same operations on what started out as the identity
622  // matrix. What started out as the identity matrix will become the
623  // inverse of the original matrix. This is because A*Inv(A) = I and
624  // performing the same operations on either side of the equation to
625  // reduce A to the identity matrix, the equation becomes I*Inv(A) = Inv(A).
626  // To perform the elimination, we will use two types of elementary row
627  // operations on the matrix.
628  // 1) Interchanging rows of the matrix.
629  // 2) Multiply row i of the matrix by c, where c != 0.
630  // 2) Add c times row i of the matrix to row j where i != j.
631  //
632  // The first operation of interchanging rows prevents numerical
633  // instability. The second allows us to put 1's on the diagonal, by
634  // dividing the row by the value of the term on the diagonal.
635  // and the third to zero out terms that are not on the diagonal by
636  // choosing c appropriately.
637 
638  Type a1_inv, a2;
639 
640  // Make a temporary copy of the matrix so the original is not destroyed
641  // during Gauss-Jordan reduction and pivoting
642  GlsMatrix<Type,DIM> temp(*this);
643 
644  // This starts out as the identity matrix. Every operation we perform
645  // on temp, we will also do to this matrix to maintain the equality in
646  // the equation we are starting out with: A*Inv(A) = I
647  GlsMatrix<Type,DIM> inverse;
648 
649  // Loop through each row in the matrix
650  for (int k = 0; k < DIM; ++k)
651  {
652  // Perform pivoting
653  int index = temp.Pivot(k);
654 
655  // If pivot returns a -1, then the matrix is singular or
656  // non-invertible. TBD: WHAT SHOULD WE DO HERE?
657  if (index == -1)
658  return inverse;
659 
660  // If pivoting resulted in the swapping of rows, then
661  // we need to do the same thing to the inverse matrix
662  if (index != 0)
663  {
664  // Swap rows
665  Type rowptr[DIM];
666  size_t byteCount = sizeof(Type) * DIM;
667  memcpy(rowptr, inverse._matrix[k], byteCount);
668  memcpy(inverse._matrix[k], inverse._matrix[index], byteCount);
669  memcpy(inverse._matrix[index], rowptr, byteCount);
670  }
671 
672  // Divide the current row by the term on the diagonal so we
673  // get a 1 on the diagonal. Remember, do the same operation
674  // to the inverse matrix.
675  a1_inv = ((Type)1.0)/temp._matrix[k][k];
676  for (int j = 0; j < DIM; ++j)
677  {
678  temp._matrix[k][j] *= a1_inv;
679  inverse._matrix[k][j] *= a1_inv;
680  }
681 
682  // Now, loop through each row, skipping the current
683  // one (k).
684  // Choose the pivot factor (a2) that would zero out the [i][k]term
685  // when multiplied by the kth row and subtracted from the
686  // ith row. Since the kth row has a 1 in the diagonal term,
687  // the factor should be the [i][k] term itself. This loop results
688  // in zeros in the kth column, except for the diagonal term [k][k].
689  for (int i = 0; i < DIM; ++i)
690  {
691  if (i != k)
692  {
693  a2 = temp._matrix[i][k];
694  for (int j = 0; j < DIM; ++j)
695  {
696  temp._matrix[i][j] -= a2 * temp._matrix[k][j];
697  inverse._matrix[i][j] -= a2 * inverse._matrix[k][j];
698  }
699  }
700  }
701  }
702  return inverse;
703 }
704 //----------------------------------------------------------------------------
705 template<class Type, int DIM>
706 inline
708 {
709  *this = Inverse();
710 }
711 //----------------------------------------------------------------------------
712 template<class Type, int DIM>
713 inline
715 {
716  // Interchange rows with columns
717  GlsMatrix<Type, DIM> result;
718  for (int row = 0; row < DIM; ++row)
719  {
720  for (int col = 0; col < DIM; ++col)
721  {
722  result._matrix[col][row] = _matrix[row][col];
723  }
724  }
725  return result;
726 }
727 //----------------------------------------------------------------------------
728 template<class Type, int DIM>
729 inline
731 {
732  GlsMatrix<Type, DIM> result;
733  result = Transposition();
734  *this = result;
735 }
736 //----------------------------------------------------------------------------
737 template<class Type, int DIM>
738 inline
740 {
741  // Look for the first term off the diagonal (where row != column) that
742  // is not equal to zero. If we find one, the matrix is not a diagonal.
743  for (int row = 0; row < DIM; ++row)
744  {
745  for (int col = 0; col < DIM; ++col)
746  {
747  if (col != row && !closeValues(_matrix[col][row],Type(0)))
748  return false;
749  }
750  }
751  return true;
752 }
753 //----------------------------------------------------------------------------
754 template<class Type, int DIM>
755 inline
757 {
758  // First do a quick check to see if it is an un-touched identity matrix
759  // This allows for zero tolerences, but should be much faster than
760  // doing all the tolerance checking every time.
761  static const GlsMatrix referenceIdentity; // Defaults to identity.
762  if (0 == memcmp(_data, referenceIdentity._data, sizeof(Type) * DIM * DIM))
763  return true;
764 
765 
766  // If the matrix is scalar, it is diagonal and all terms on the diagonal
767  // are equal. Make sure they are equal to 1 to be the identity matrix.
768  if (IsScalar() && closeValues(_matrix[0][0],Type(1)))
769  return true;
770  else
771  return false;
772 }
773 //----------------------------------------------------------------------------
774 template<class Type, int DIM>
775 inline
777 {
778  // If the matrix is scalar, it is diagonal and all terms on the diagonal
779  // are equal.
780  if (!IsDiagonal())
781  return false;
782 
783  Type val = _matrix[0][0];
784  for (int i = 0; i < DIM; ++i)
785  {
786  if (!closeValues(_matrix[i][i],val))
787  return false;
788  }
789  return true;
790 }
791 //----------------------------------------------------------------------------
792 template<class Type, int DIM>
793 inline
795 {
796  return Determinant() == Type(0);
797 }
798 //----------------------------------------------------------------------------
799 template<class Type, int DIM>
800 inline
802 {
803  return Transposition() == *this;
804 }
805 //----------------------------------------------------------------------------
806 template<class Type, int DIM>
807 inline
809 {
810  return Transposition() == -(*this);
811 }
812 //----------------------------------------------------------------------------
813 template<class Type, int DIM>
814 inline
816 {
817  // An n x n matrix A = [Aij] is lower triangular if Aij = 0 for i < j.
818  for (int row = 0; row < DIM-1; ++row)
819  {
820  for (int col = row+1; col < DIM; ++col)
821  {
822  if (!closeValues(_matrix[col][row],Type(0)))
823  return false;
824  }
825  }
826  return true;
827 }
828 //----------------------------------------------------------------------------
829 template<class Type, int DIM>
830 inline
832 {
833  // An n x n matrix A = [Aij] is upper triangular if Aij = 0 for i > j.
834  for (int row = 1; row < DIM; ++row)
835  {
836  for (int col = 0; col < row; ++col)
837  {
838  if (!closeValues(_matrix[col][row],Type(0)))
839  return false;
840  }
841  }
842  return true;
843 }
844 //----------------------------------------------------------------------------
845 template<class Type, int DIM>
846 inline
847 Type& GlsMatrix<Type, DIM>::operator () (unsigned row, unsigned col)
848 {
849  // transpose the row and column since the matrix is in column
850  // major order but we want users to be able to use row-major ordering.
851  return _matrix[col][row];
852 }
853 //----------------------------------------------------------------------------
854 template<class Type, int DIM>
855 inline
856 Type GlsMatrix<Type, DIM>::operator () (unsigned row, unsigned col) const
857 {
858  // transpose the row and column since the matrix is in column
859  // major order but we want users to be able to use row-major ordering.
860  return _matrix[col][row];
861 }
862 //----------------------------------------------------------------------------
863 template<class Type, int DIM>
864 inline
865 bool GlsMatrix<Type, DIM>::operator == (const GlsMatrix<Type, DIM>& rhs) const
866 {
867  static const int SIZE = DIM*DIM;
868  for (int i = 0; i < SIZE; ++i)
869  {
870  if (!closeValues(_data[i],rhs._data[i]))
871  return false;
872  }
873  return true;
874 }
875 //----------------------------------------------------------------------------
876 template<class Type, int DIM>
877 inline
878 bool GlsMatrix<Type, DIM>::operator != (const GlsMatrix<Type, DIM>& rhs) const
879 {
880  return !(*this == rhs);
881 }
882 //----------------------------------------------------------------------------
883 template<class Type, int DIM>
884 inline GlsMatrix<Type, DIM>&
885 GlsMatrix<Type, DIM>::operator = (const GlsMatrix<Type, DIM>& m)
886 {
887  if (this == &m) return *this;
888 
889  memcpy(_data, m._data, sizeof(Type)*DIM*DIM);
890 
891  return *this;
892 }
893 //----------------------------------------------------------------------------
894 template<class Type, int DIM>
895 inline GlsMatrix<Type, DIM>&
896 GlsMatrix<Type, DIM>::operator = (const CStyleMatrix m)
897 {
898  for (int row = 0; row < DIM; ++row)
899  {
900  for (int col = 0; col < DIM; ++col)
901  {
902  _matrix[col][row] = m[row][col];
903  }
904  }
905 
906  return *this;
907 }
908 //----------------------------------------------------------------------------
909 template<class Type, int DIM>
910 inline
911 GlsMatrix<Type, DIM> GlsMatrix<Type, DIM>::operator - () const
912 {
913  GlsMatrix<Type,DIM> temp;
914 
915  for (int row = 0; row < DIM; ++row)
916  {
917  for (int col = 0; col < DIM; ++col)
918  {
919  temp._matrix[col][row] = -_matrix[col][row];
920  }
921  }
922 
923  return temp;
924 }
925 //----------------------------------------------------------------------------
926 template<class Type, int DIM>
927 inline
928 GlsMatrix<Type, DIM>&
929 GlsMatrix<Type, DIM>::operator += (const GlsMatrix<Type, DIM>& rhs)
930 {
931  for (int row = 0; row < DIM; ++row)
932  {
933  for (int col = 0; col < DIM; ++col)
934  {
935  _matrix[col][row] += rhs._matrix[col][row];
936  }
937  }
938  return *this;
939 }
940 //----------------------------------------------------------------------------
941 template<class Type, int DIM>
942 inline
943 GlsMatrix<Type, DIM>&
944 GlsMatrix<Type, DIM>::operator -= (const GlsMatrix<Type, DIM>& rhs)
945 {
946  for (int row = 0; row < DIM; ++row)
947  {
948  for (int col = 0; col < DIM; ++col)
949  {
950  _matrix[col][row] -= rhs._matrix[col][row];
951  }
952  }
953  return *this;
954 }
955 //----------------------------------------------------------------------------
956 template<>
957 inline
958 GlsMatrix<double, 4>&
959 GlsMatrix<double, 4>::operator *= (const GlsMatrix<double,4>& rhs)
960 {
961  return *this = *this * rhs; // faster because it calls the specialized operator*
962 }
963 //----------------------------------------------------------------------------
964 template<>
965 inline
966 GlsMatrix<float, 4>&
967 GlsMatrix<float, 4>::operator *= (const GlsMatrix<float,4>& rhs)
968 {
969  return *this = *this * rhs; // faster because it calls the specialized operator*
970 }
971 //----------------------------------------------------------------------------
972 template<class Type, int DIM>
973 inline
974 GlsMatrix<Type, DIM>&
975 GlsMatrix<Type, DIM>::operator *= (const GlsMatrix<Type, DIM>& rhs)
976 {
977  GlsMatrix<Type,DIM> result;
978  memset(result._data, 0, sizeof(Type) * DIM * DIM);
979  for (int row = 0; row < DIM; ++row)
980  {
981  for (int col = 0; col < DIM; ++col)
982  {
983  for (int i = 0; i < DIM; ++i)
984  {
985  result._matrix[col][row] += _matrix[i][row] * rhs._matrix[col][i];
986  }
987  }
988  }
989  *this = result;
990  return *this;
991 }
992 //----------------------------------------------------------------------------
993 template<class Type, int DIM>
994 inline
995 GlsMatrix<Type, DIM>&
996 GlsMatrix<Type, DIM>::operator *= (Type scalar)
997 {
998  for (int row = 0; row < DIM; ++row)
999  {
1000  for (int col = 0; col < DIM; ++col)
1001  {
1002  _matrix[col][row] *= scalar;
1003  }
1004  }
1005  return *this;
1006 }
1007 //----------------------------------------------------------------------------
1008 template<class Type, int DIM>
1009 inline
1010 GlsMatrix<Type, DIM>&
1011 GlsMatrix<Type, DIM>::operator /= (Type scalar)
1012 {
1013  for (int row = 0; row < DIM; ++row)
1014  {
1015  for (int col = 0; col < DIM; ++col)
1016  {
1017  _matrix[col][row] /= scalar;
1018  }
1019  }
1020  return *this;
1021 }
1022 //----------------------------------------------------------------------------
1023 template<class Type, int DIM>
1024 inline
1025 GlsMatrix<Type, DIM>
1026 GlsMatrix<Type, DIM>::operator + (const GlsMatrix<Type, DIM>& rhs) const
1027 {
1028  GlsMatrix<Type,DIM> result;
1029  for (int row = 0; row < DIM; ++row)
1030  {
1031  for (int col = 0; col < DIM; ++col)
1032  {
1033  result._matrix[col][row] = _matrix[col][row] + rhs._matrix[col][row];
1034  }
1035  }
1036  return result;
1037 }
1038 //----------------------------------------------------------------------------
1039 template<class Type, int DIM>
1040 inline
1041 GlsMatrix<Type, DIM>
1042 GlsMatrix<Type, DIM>::operator - (const GlsMatrix<Type, DIM>& rhs) const
1043 {
1044  GlsMatrix<Type,DIM> result;
1045  for (int row = 0; row < DIM; ++row)
1046  {
1047  for (int col = 0; col < DIM; ++col)
1048  {
1049  result._matrix[col][row] = _matrix[col][row] - rhs._matrix[col][row];
1050  }
1051  }
1052  return result;
1053 }
1054 //----------------------------------------------------------------------------
1055 template<class Type, int DIM>
1056 inline
1057 GlsMatrix<Type, DIM> GlsMatrix<Type, DIM>::operator / (Type scalar) const
1058 {
1059  GlsMatrix<Type, DIM> result;
1060  for (int row = 0; row < DIM; ++row)
1061  {
1062  for (int col = 0; col < DIM; ++col)
1063  {
1064  result._matrix[col][row] = _matrix[col][row] / scalar;
1065  }
1066  }
1067  return result;
1068 }
1069 //----------------------------------------------------------------------------
1070 template <class Type, int DIM>
1071 inline
1072 std::ostream& operator << (std::ostream& ostrm, const GlsMatrix<Type, DIM>& m)
1073 {
1074  for (int row = 0; row < DIM; ++row)
1075  {
1076  for (int col = 0; col < DIM; ++col)
1077  {
1078  ostrm.width(11);
1079  ostrm << m(row,col) << ' ';
1080  }
1081  }
1082  return ostrm;
1083 }
1084 //----------------------------------------------------------------------------
1085 template <class Type, int DIM>
1086 inline
1087 std::istream& operator >> (std::istream& istrm, GlsMatrix<Type, DIM>& m)
1088 {
1089  Type x;
1090  for (int row = 0; row < DIM; ++row)
1091  {
1092  for (int col = 0; col < DIM; ++col)
1093  {
1094  istrm >> x;
1095  m(row,col) = x;
1096  }
1097  }
1098  return istrm;
1099 }
1100 //----------------------------------------------------------------------------
1101 template<class Type, int DIM>
1102 inline
1104 {
1105  // Set each element in the matrix index to point to a column of the
1106  // _matrix data.
1107  for (int i = 0, j = 0; i < DIM; ++i,j+=DIM)
1108  {
1109  _matrix[i] = &(_data[j]);
1110  }
1111 }
1112 //----------------------------------------------------------------------------
1113 template<class Type, int DIM>
1115 {
1116  int pivotRow;
1117  int k = int(row);
1118  double amax = -1;
1119  double temp;
1120 
1121  // Go through each element in the column below the diagonal element
1122  // [row][row] to find the largest term (in magnitude). Save which row
1123  // has the largest term in the column.
1124  for (unsigned i = row; i < unsigned(DIM); ++i)
1125  {
1126  if ((temp = fabs(_matrix[i][row])) > amax && temp != 0.0)
1127  {
1128  amax = temp;
1129  k = i;
1130  }
1131  }
1132 
1133  if (_matrix[k][row] == Type(0))
1134  {
1135  // If the largest term is zero, then return a -1 so the caller knows
1136  // we cannot pivot.
1137  pivotRow = -1;
1138  }
1139  else if (k != int(row))
1140  {
1141  // If k is not equal to the passed in row, it means another row
1142  // has the largest term in it, so lets interchange rows.
1143  // Return the row that was interchanged to let the caller know.
1144  Type rowptr[DIM];
1145  size_t byteCount = sizeof(Type) * DIM;
1146  memcpy(rowptr, _matrix[k], byteCount);
1147  memcpy(_matrix[k], _matrix[row], byteCount);
1148  memcpy(_matrix[row], rowptr, byteCount);
1149  pivotRow = k;
1150  }
1151  else
1152  {
1153  // If k is equal to the passed in row, it means current row
1154  // has the largest term in it, so lets not interchange any rows.
1155  // return 0 to let the caller know.
1156  pivotRow = 0;
1157  }
1158 
1159  return pivotRow;
1160 }
1161 //----------------------------------------------------------------------------
1162 template<class Type, int DIM>
1163 inline
1164 bool GlsMatrix<Type, DIM>::closeValues(Type lv, Type rv) const
1165 {
1166  return (lv - PRECISION) <= rv && rv <= (lv + PRECISION);
1167 }
1168 
1169 
1170 } // namespace disti
1171 
1172 #endif
1173 
bool IsScalar() const
Definition: gls_matrix.h:776
bool IsDiagonal() const
Definition: gls_matrix.h:739
GlsMatrix< Type, DIM > Transposition() const
Definition: gls_matrix.h:714
Definition: gls_matrix.h:62
bool IsLowerTriangular() const
Definition: gls_matrix.h:815
void Initialize()
Definition: gls_matrix.h:1103
static const double PRECISION
Definition: gls_matrix.h:314
GlsMatrix< Type, DIM > Inverse() const
Definition: gls_matrix.h:617
Type * _matrix[DIM]
Definition: gls_matrix.h:335
bool IsSkewSymmetric() const
Definition: gls_matrix.h:808
GlsMatrix()
Definition: gls_matrix.h:393
Type _data[DIM *DIM]
Definition: gls_matrix.h:323
Type Determinant() const
Definition: gls_matrix.h:549
bool IsIdentity() const
Definition: gls_matrix.h:756
void Clear()
Definition: gls_matrix.h:124
Type * Data()
Definition: gls_matrix.h:132
bool closeValues(Type lv, Type rv) const
Definition: gls_matrix.h:1164
const Type * Data() const
Definition: gls_matrix.h:140
void Dump() const
Definition: gls_matrix.h:523
bool IsSingular() const
Definition: gls_matrix.h:794
void Invert()
Definition: gls_matrix.h:707
int Pivot(unsigned row)
Definition: gls_matrix.h:1114
void MakeIdentity()
Definition: gls_matrix.h:539
void Transpose()
Definition: gls_matrix.h:730
bool IsUpperTriangular() const
Definition: gls_matrix.h:831
Definition: bmpimage.h:46
virtual ~GlsMatrix()
Definition: gls_matrix.h:427
bool IsSymmetric() const
Definition: gls_matrix.h:801