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