0030623: Draw Harness - support hex color codes within ViewerTest::ParseColor()
[occt.git] / src / NCollection / NCollection_Mat4.hxx
1 // Created on: 2013-05-30
2 // Created by: Anton POLETAEV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #ifndef _NCollection_Mat4_HeaderFile
17 #define _NCollection_Mat4_HeaderFile
18
19 #include <NCollection_Vec4.hxx>
20
21 //! Generic matrix of 4 x 4 elements.
22 //! To be used in conjunction with NCollection_Vec4 entities.
23 //! Originally introduced for 3D space projection and orientation
24 //! operations.
25 template<typename Element_t>
26 class NCollection_Mat4
27 {
28
29 public:
30
31   //! Get number of rows.
32   //! @return number of rows.
33   static size_t Rows()
34   {
35     return 4;
36   }
37
38   //! Get number of columns.
39   //! @retur number of columns.
40   static size_t Cols()
41   {
42     return 4;
43   }
44
45   //! Empty constructor.
46   //! Construct the zero matrix.
47   NCollection_Mat4()
48   {
49     InitIdentity();
50   }
51
52   //! Conversion constructor (explicitly converts some 4 x 4 matrix with other element type
53   //! to a new 4 x 4 matrix with the element type Element_t,
54   //! whose elements are static_cast'ed corresponding elements of theOtherMat4 matrix)
55   //! @tparam OtherElement_t the element type of the other 4 x 4 matrix theOtherVec4
56   //! @param theOtherMat4 the 4 x 4 matrix that needs to be converted
57   template <typename OtherElement_t>
58   explicit NCollection_Mat4 (const NCollection_Mat4<OtherElement_t>& theOtherMat4)
59   {
60     ConvertFrom (theOtherMat4);
61   }
62
63   //! Get element at the specified row and column.
64   //! @param theRow [in] the row.to address.
65   //! @param theCol [in] the column to address.
66   //! @return the value of the addressed element.
67   Element_t GetValue (const size_t theRow, const size_t theCol) const
68   {
69     return myMat[theCol * 4 + theRow];
70   }
71
72   //! Access element at the specified row and column.
73   //! @param theRow [in] the row.to access.
74   //! @param theCol [in] the column to access.
75   //! @return reference on the matrix element.
76   Element_t& ChangeValue (const size_t theRow, const size_t theCol)
77   {
78     return myMat[theCol * 4 + theRow];
79   }
80
81   //! Set value for the element specified by row and columns.
82   //! @param theRow   [in] the row to change.
83   //! @param theCol   [in] the column to change.
84   //! @param theValue [in] the value to set.s
85   void SetValue (const size_t    theRow,
86                  const size_t    theCol,
87                  const Element_t theValue)
88   {
89     myMat[theCol * 4 + theRow] = theValue;
90   }
91
92   //! Get vector of elements for the specified row.
93   //! @param theRow [in] the row to access.
94   //! @return vector of elements.
95   NCollection_Vec4<Element_t> GetRow (const size_t theRow) const
96   {
97     return NCollection_Vec4<Element_t> (GetValue (theRow, 0),
98                                         GetValue (theRow, 1),
99                                         GetValue (theRow, 2),
100                                         GetValue (theRow, 3));
101   }
102
103   //! Change first 3 row values by the passed vector.
104   //! @param theRow [in] the row to change.
105   //! @param theVec [in] the vector of values.
106   void SetRow (const size_t theRow, const NCollection_Vec3<Element_t>& theVec)
107   {
108     SetValue (theRow, 0, theVec.x());
109     SetValue (theRow, 1, theVec.y());
110     SetValue (theRow, 2, theVec.z());
111   }
112
113   //! Set row values by the passed 4 element vector.
114   //! @param theRow [in] the row to change.
115   //! @param theVec [in] the vector of values.
116   void SetRow (const size_t theRow, const NCollection_Vec4<Element_t>& theVec)
117   {
118     SetValue (theRow, 0, theVec.x());
119     SetValue (theRow, 1, theVec.y());
120     SetValue (theRow, 2, theVec.z());
121     SetValue (theRow, 3, theVec.w());
122   }
123
124   //! Get vector of elements for the specified column.
125   //! @param theCol [in] the column to access.
126   //! @return vector of elements.
127   NCollection_Vec4<Element_t> GetColumn (const size_t theCol) const
128   {
129     return NCollection_Vec4<Element_t> (GetValue (0, theCol),
130                                         GetValue (1, theCol),
131                                         GetValue (2, theCol),
132                                         GetValue (3, theCol));
133   }
134
135   //! Change first 3 column values by the passed vector.
136   //! @param theCol [in] the column to change.
137   //! @param theVec [in] the vector of values.
138   void SetColumn (const size_t theCol,
139                   const NCollection_Vec3<Element_t>& theVec)
140   {
141     SetValue (0, theCol, theVec.x());
142     SetValue (1, theCol, theVec.y());
143     SetValue (2, theCol, theVec.z());
144   }
145
146   //! Set column values by the passed 4 element vector.
147   //! @param theCol [in] the column to change.
148   //! @param theVec [in] the vector of values.
149   void SetColumn (const size_t theCol,
150                   const NCollection_Vec4<Element_t>& theVec)
151   {
152     SetValue (0, theCol, theVec.x());
153     SetValue (1, theCol, theVec.y());
154     SetValue (2, theCol, theVec.z());
155     SetValue (3, theCol, theVec.w());
156   }
157
158   //! Get vector of diagonal elements.
159   //! \return vector of diagonal elements.
160   NCollection_Vec4<Element_t> GetDiagonal() const
161   {
162     return NCollection_Vec4<Element_t> (GetValue (0, 0),
163                                         GetValue (1, 1),
164                                         GetValue (2, 2),
165                                         GetValue (3, 3));
166   }
167
168   //! Change first 3 elements of the diagonal matrix.
169   //! @param theVec the vector of values.
170   void SetDiagonal (const NCollection_Vec3<Element_t>& theVec)
171   {
172     SetValue (0, 0, theVec.x());
173     SetValue (1, 1, theVec.y());
174     SetValue (2, 2, theVec.z());
175   }
176
177   //! Set diagonal elements of the matrix by the passed vector.
178   //! @param theVec [in] the vector of values.
179   void SetDiagonal (const NCollection_Vec4<Element_t>& theVec)
180   {
181     SetValue (0, 0, theVec.x());
182     SetValue (1, 1, theVec.y());
183     SetValue (2, 2, theVec.z());
184     SetValue (3, 3, theVec.w());
185   }
186
187   //! Initialize the identity matrix.
188   void InitIdentity()
189   {
190     std::memcpy (this, myIdentityArray, sizeof (NCollection_Mat4));
191   }
192
193   //! Checks the matrix for identity.
194   bool IsIdentity() const
195   {
196     return std::memcmp (this, myIdentityArray, sizeof (NCollection_Mat4)) == 0;
197   }
198
199   //! Check this matrix for equality with another matrix (without tolerance!).
200   bool IsEqual (const NCollection_Mat4& theOther) const
201   {
202     return std::memcmp (this, &theOther, sizeof(NCollection_Mat4)) == 0;
203   }
204
205   //! Check this matrix for equality with another matrix (without tolerance!).
206   bool operator== (const NCollection_Mat4& theOther)       { return IsEqual (theOther); }
207   bool operator== (const NCollection_Mat4& theOther) const { return IsEqual (theOther); }
208
209   //! Check this matrix for non-equality with another matrix (without tolerance!).
210   bool operator!= (const NCollection_Mat4& theOther)       { return !IsEqual (theOther); }
211   bool operator!= (const NCollection_Mat4& theOther) const { return !IsEqual (theOther); }
212
213   //! Raw access to the data (for OpenGL exchange).
214   const Element_t* GetData()    const { return myMat; }
215   Element_t*       ChangeData()       { return myMat; }
216   operator const   Element_t*() const { return myMat; }
217   operator         Element_t*()       { return myMat; }
218
219   //! Multiply by the vector (M * V).
220   //! @param theVec [in] the vector to multiply.
221   NCollection_Vec4<Element_t> operator* (const NCollection_Vec4<Element_t>& theVec) const
222   {
223     return NCollection_Vec4<Element_t> (
224       GetValue (0, 0) * theVec.x() + GetValue (0, 1) * theVec.y() + GetValue (0, 2) * theVec.z() + GetValue (0, 3) * theVec.w(),
225       GetValue (1, 0) * theVec.x() + GetValue (1, 1) * theVec.y() + GetValue (1, 2) * theVec.z() + GetValue (1, 3) * theVec.w(),
226       GetValue (2, 0) * theVec.x() + GetValue (2, 1) * theVec.y() + GetValue (2, 2) * theVec.z() + GetValue (2, 3) * theVec.w(),
227       GetValue (3, 0) * theVec.x() + GetValue (3, 1) * theVec.y() + GetValue (3, 2) * theVec.z() + GetValue (3, 3) * theVec.w());
228   }
229
230   //! Compute matrix multiplication product: A * B.
231   //! @param theMatA [in] the matrix "A".
232   //! @param theMatB [in] the matrix "B".
233   NCollection_Mat4 Multiply (const NCollection_Mat4& theMatA,
234                              const NCollection_Mat4& theMatB)
235   {
236     NCollection_Mat4 aMatRes;
237
238     size_t aInputElem;
239     for (size_t aResElem = 0; aResElem < 16; ++aResElem)
240     {
241       aMatRes[aResElem] = (Element_t )0;
242       for (aInputElem = 0; aInputElem < 4; ++aInputElem)
243       {
244         aMatRes[aResElem] += theMatA.GetValue(aResElem % 4, aInputElem)
245                            * theMatB.GetValue(aInputElem, aResElem / 4);
246       }
247     }
248
249     return aMatRes;
250   }
251
252   //! Compute matrix multiplication.
253   //! @param theMat [in] the matrix to multiply.
254   void Multiply (const NCollection_Mat4& theMat)
255   {
256     *this = Multiply(*this, theMat);
257   }
258
259   //! Multiply by the another matrix.
260   //! @param theMat [in] the other matrix.
261   NCollection_Mat4& operator*= (const NCollection_Mat4& theMat)
262   {
263     Multiply (theMat);
264     return *this;
265   }
266
267   //! Compute matrix multiplication product.
268   //! @param theMat [in] the other matrix.
269   //! @return result of multiplication.
270   NCollection_Mat4 operator* (const NCollection_Mat4& theMat) const
271   {
272     return Multiplied (theMat);
273   }
274
275   //! Compute matrix multiplication product.
276   //! @param theMat [in] the other matrix.
277   //! @return result of multiplication.
278   NCollection_Mat4 Multiplied (const NCollection_Mat4& theMat) const
279   {
280     NCollection_Mat4 aTempMat (*this);
281     aTempMat *= theMat;
282     return aTempMat;
283   }
284
285   //! Compute per-component multiplication.
286   //! @param theFactor [in] the scale factor.
287   void Multiply (const Element_t theFactor)
288   {
289     for (size_t i = 0; i < 16; ++i)
290     {
291       myMat[i] *= theFactor;
292     }
293   }
294
295   //! Compute per-element multiplication.
296   //! @param theFactor [in] the scale factor.
297   NCollection_Mat4& operator*=(const Element_t theFactor)
298   {
299     Multiply (theFactor);
300     return *this;
301   }
302
303   //! Compute per-element multiplication.
304   //! @param theFactor [in] the scale factor.
305   //! @return the result of multiplicaton.
306   NCollection_Mat4 operator* (const Element_t theFactor) const
307   {
308     return Multiplied (theFactor);
309   }
310
311   //! Compute per-element multiplication.
312   //! @param theFactor [in] the scale factor.
313   //! @return the result of multiplicaton.
314   NCollection_Mat4 Multiplied (const Element_t theFactor) const
315   {
316     NCollection_Mat4 aTempMat (*this);
317     aTempMat *= theFactor;
318     return aTempMat;
319   }
320
321   //! Translate the matrix on the passed vector.
322   //! @param theVec [in] the translation vector.
323   void Translate (const NCollection_Vec3<Element_t>& theVec)
324   {
325     NCollection_Mat4 aTempMat;
326     aTempMat.SetColumn (3, theVec);
327     this->Multiply (aTempMat);
328   }
329
330   //! Transpose the matrix.
331   //! @return transposed copy of the matrix.
332   NCollection_Mat4 Transposed() const
333   {
334     NCollection_Mat4 aTempMat;
335     aTempMat.SetRow (0, GetColumn (0));
336     aTempMat.SetRow (1, GetColumn (1));
337     aTempMat.SetRow (2, GetColumn (2));
338     aTempMat.SetRow (3, GetColumn (3));
339     return aTempMat;
340   }
341
342   //! Transpose the matrix.
343   void Transpose()
344   {
345     *this = Transposed();
346   }
347
348   //! Compute inverted matrix.
349   //! @param theOutMx [out] the inverted matrix.
350   //! @return true if reversion success.
351   bool Inverted (NCollection_Mat4<Element_t>& theOutMx) const
352   {
353     Element_t* inv = theOutMx.myMat;
354
355     // use short-cut for better readability
356     const Element_t* m = myMat;
357
358     inv[ 0] = m[ 5] * (m[10] * m[15] - m[11] * m[14]) -
359               m[ 9] * (m[ 6] * m[15] - m[ 7] * m[14]) -
360               m[13] * (m[ 7] * m[10] - m[ 6] * m[11]);
361
362     inv[ 1] = m[ 1] * (m[11] * m[14] - m[10] * m[15]) -
363               m[ 9] * (m[ 3] * m[14] - m[ 2] * m[15]) -
364               m[13] * (m[ 2] * m[11] - m[ 3] * m[10]);
365
366     inv[ 2] = m[ 1] * (m[ 6] * m[15] - m[ 7] * m[14]) -
367               m[ 5] * (m[ 2] * m[15] - m[ 3] * m[14]) -
368               m[13] * (m[ 3] * m[ 6] - m[ 2] * m[ 7]);
369
370     inv[ 3] = m[ 1] * (m[ 7] * m[10] - m[ 6] * m[11]) -
371               m[ 5] * (m[ 3] * m[10] - m[ 2] * m[11]) -
372               m[ 9] * (m[ 2] * m[ 7] - m[ 3] * m[ 6]);
373
374     inv[ 4] = m[ 4] * (m[11] * m[14] - m[10] * m[15]) -
375               m[ 8] * (m[ 7] * m[14] - m[ 6] * m[15]) -
376               m[12] * (m[ 6] * m[11] - m[ 7] * m[10]);
377
378     inv[ 5] = m[ 0] * (m[10] * m[15] - m[11] * m[14]) -
379               m[ 8] * (m[ 2] * m[15] - m[ 3] * m[14]) -
380               m[12] * (m[ 3] * m[10] - m[ 2] * m[11]);
381
382     inv[ 6] = m[ 0] * (m[ 7] * m[14] - m[ 6] * m[15]) -
383               m[ 4] * (m[ 3] * m[14] - m[ 2] * m[15]) -
384               m[12] * (m[ 2] * m[ 7] - m[ 3] * m[ 6]);
385
386     inv[ 7] = m[ 0] * (m[ 6] * m[11] - m[ 7] * m[10]) -
387               m[ 4] * (m[ 2] * m[11] - m[ 3] * m[10]) -
388               m[ 8] * (m[ 3] * m[ 6] - m[ 2] * m[ 7]);
389
390     inv[ 8] = m[ 4] * (m[ 9] * m[15] - m[11] * m[13]) -
391               m[ 8] * (m[ 5] * m[15] - m[ 7] * m[13]) -
392               m[12] * (m[ 7] * m[ 9] - m[ 5] * m[11]);
393
394     inv[ 9] = m[ 0] * (m[11] * m[13] - m[ 9] * m[15]) -
395               m[ 8] * (m[ 3] * m[13] - m[ 1] * m[15]) -
396               m[12] * (m[ 1] * m[11] - m[ 3] * m[ 9]);
397
398     inv[10] = m[ 0] * (m[ 5] * m[15] - m[ 7] * m[13]) -
399               m[ 4] * (m[ 1] * m[15] - m[ 3] * m[13]) -
400               m[12] * (m[ 3] * m[ 5] - m[ 1] * m[ 7]);
401
402     inv[11] = m[ 0] * (m[ 7] * m[ 9] - m[ 5] * m[11]) -
403               m[ 4] * (m[ 3] * m[ 9] - m[ 1] * m[11]) -
404               m[ 8] * (m[ 1] * m[ 7] - m[ 3] * m[ 5]);
405
406     inv[12] = m[ 4] * (m[10] * m[13] - m[ 9] * m[14]) -
407               m[ 8] * (m[ 6] * m[13] - m[ 5] * m[14]) -
408               m[12] * (m[ 5] * m[10] - m[ 6] * m[ 9]);
409
410     inv[13] = m[ 0] * (m[ 9] * m[14] - m[10] * m[13]) -
411               m[ 8] * (m[ 1] * m[14] - m[ 2] * m[13]) -
412               m[12] * (m[ 2] * m[ 9] - m[ 1] * m[10]);
413
414     inv[14] = m[ 0] * (m[ 6] * m[13] - m[ 5] * m[14]) -
415               m[ 4] * (m[ 2] * m[13] - m[ 1] * m[14]) -
416               m[12] * (m[ 1] * m[ 6] - m[ 2] * m[ 5]);
417
418     inv[15] = m[ 0] * (m[ 5] * m[10] - m[ 6] * m[ 9]) -
419               m[ 4] * (m[ 1] * m[10] - m[ 2] * m[ 9]) -
420               m[ 8] * (m[ 2] * m[ 5] - m[ 1] * m[ 6]);
421
422     Element_t aDet = m[0] * inv[ 0] +
423                      m[1] * inv[ 4] +
424                      m[2] * inv[ 8] +
425                      m[3] * inv[12];
426
427     if (aDet == 0)
428       return false;
429
430     aDet = (Element_t) 1. / aDet;
431
432     for (int i = 0; i < 16; ++i)
433       inv[i] *= aDet;
434
435     return true;
436   }
437
438   //! Take values from NCollection_Mat4 with a different element type with type conversion.
439   template <typename Other_t>
440   void ConvertFrom (const NCollection_Mat4<Other_t>& theFrom)
441   {
442     for (int anIdx = 0; anIdx < 16; ++anIdx)
443     {
444       myMat[anIdx] = static_cast<Element_t> (theFrom.myMat[anIdx]);
445     }
446   }
447
448   //! Take values from NCollection_Mat4 with a different element type with type conversion.
449   template <typename Other_t>
450   void Convert (const NCollection_Mat4<Other_t>& theFrom) { ConvertFrom (theFrom); }
451
452   //! Maps plain C array to matrix type.
453   static NCollection_Mat4<Element_t>& Map (Element_t* theData)
454   {
455     return *reinterpret_cast<NCollection_Mat4<Element_t>*> (theData);
456   }
457
458   //! Maps plain C array to matrix type.
459   static const NCollection_Mat4<Element_t>& Map (const Element_t* theData)
460   {
461     return *reinterpret_cast<const NCollection_Mat4<Element_t>*> (theData);
462   }
463
464 private:
465
466   Element_t myMat[16];
467
468 private:
469
470   static Element_t myIdentityArray[16];
471
472   // All instantiations are friend to each other
473   template<class OtherType> friend class NCollection_Mat4;
474
475 };
476
477 template<typename Element_t>
478 Element_t NCollection_Mat4<Element_t>::myIdentityArray[] =
479   {1, 0, 0, 0,
480    0, 1, 0, 0,
481    0, 0, 1, 0,
482    0, 0, 0, 1};
483
484 #if defined(_MSC_VER) && (_MSC_VER >= 1900)
485   #include <type_traits>
486
487   static_assert(std::is_trivially_copyable<NCollection_Mat4<float>>::value, "NCollection_Mat4 is not is_trivially_copyable() structure!");
488   static_assert(std::is_standard_layout   <NCollection_Mat4<float>>::value, "NCollection_Mat4 is not is_standard_layout() structure!");
489 #endif
490
491 #endif // _NCollection_Mat4_HeaderFile