0027919: Visualization - support multiple transformation persistence groups within...
[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 <NCollection_Mat3.hxx>
21
22 //! Generic matrix of 4 x 4 elements.
23 //! To be used in conjunction with NCollection_Vec4 entities.
24 //! Originally introduced for 3D space projection and orientation operations.
25 //! Warning, empty constructor returns an identity matrix.
26 template<typename Element_t>
27 class NCollection_Mat4
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   //! Return identity matrix.
46   static NCollection_Mat4 Identity()
47   {
48     return NCollection_Mat4();
49   }
50
51   //! Return zero matrix.
52   static NCollection_Mat4 Zero()
53   {
54     NCollection_Mat4 aMat; aMat.InitZero();
55     return aMat;
56   }
57
58 public:
59
60   //! Empty constructor.
61   //! Construct the identity matrix.
62   NCollection_Mat4()
63   {
64     InitIdentity();
65   }
66
67   //! Conversion constructor (explicitly converts some 4 x 4 matrix with other element type
68   //! to a new 4 x 4 matrix with the element type Element_t,
69   //! whose elements are static_cast'ed corresponding elements of theOtherMat4 matrix)
70   //! @tparam OtherElement_t the element type of the other 4 x 4 matrix theOtherVec4
71   //! @param theOtherMat4 the 4 x 4 matrix that needs to be converted
72   template <typename OtherElement_t>
73   explicit NCollection_Mat4 (const NCollection_Mat4<OtherElement_t>& theOtherMat4)
74   {
75     ConvertFrom (theOtherMat4);
76   }
77
78   //! Get element at the specified row and column.
79   //! @param theRow [in] the row to address.
80   //! @param theCol [in] the column to address.
81   //! @return the value of the addressed element.
82   Element_t GetValue (const size_t theRow, const size_t theCol) const
83   {
84     return myMat[theCol * 4 + theRow];
85   }
86
87   //! Access element at the specified row and column.
88   //! @param theRow [in] the row to access.
89   //! @param theCol [in] the column to access.
90   //! @return reference on the matrix element.
91   Element_t& ChangeValue (const size_t theRow, const size_t theCol)
92   {
93     return myMat[theCol * 4 + theRow];
94   }
95
96   //! Set value for the element specified by row and columns.
97   //! @param theRow   [in] the row to change.
98   //! @param theCol   [in] the column to change.
99   //! @param theValue [in] the value to set.
100   void SetValue (const size_t    theRow,
101                  const size_t    theCol,
102                  const Element_t theValue)
103   {
104     myMat[theCol * 4 + theRow] = theValue;
105   }
106
107   //! Return value.
108   Element_t& operator() (const size_t theRow, const size_t theCol) { return ChangeValue (theRow, theCol); }
109
110   //! Return value.
111   Element_t  operator() (const size_t theRow, const size_t theCol) const { return GetValue (theRow, theCol); }
112
113   //! Get vector of elements for the specified row.
114   //! @param theRow [in] the row to access.
115   //! @return vector of elements.
116   NCollection_Vec4<Element_t> GetRow (const size_t theRow) const
117   {
118     return NCollection_Vec4<Element_t> (GetValue (theRow, 0),
119                                         GetValue (theRow, 1),
120                                         GetValue (theRow, 2),
121                                         GetValue (theRow, 3));
122   }
123
124   //! Change first 3 row values by the passed vector.
125   //! @param theRow [in] the row to change.
126   //! @param theVec [in] the vector of values.
127   void SetRow (const size_t theRow, const NCollection_Vec3<Element_t>& theVec)
128   {
129     SetValue (theRow, 0, theVec.x());
130     SetValue (theRow, 1, theVec.y());
131     SetValue (theRow, 2, theVec.z());
132   }
133
134   //! Set row values by the passed 4 element vector.
135   //! @param theRow [in] the row to change.
136   //! @param theVec [in] the vector of values.
137   void SetRow (const size_t theRow, const NCollection_Vec4<Element_t>& theVec)
138   {
139     SetValue (theRow, 0, theVec.x());
140     SetValue (theRow, 1, theVec.y());
141     SetValue (theRow, 2, theVec.z());
142     SetValue (theRow, 3, theVec.w());
143   }
144
145   //! Get vector of elements for the specified column.
146   //! @param theCol [in] the column to access.
147   //! @return vector of elements.
148   NCollection_Vec4<Element_t> GetColumn (const size_t theCol) const
149   {
150     return NCollection_Vec4<Element_t> (GetValue (0, theCol),
151                                         GetValue (1, theCol),
152                                         GetValue (2, theCol),
153                                         GetValue (3, theCol));
154   }
155
156   //! Change first 3 column values by the passed vector.
157   //! @param theCol [in] the column to change.
158   //! @param theVec [in] the vector of values.
159   void SetColumn (const size_t theCol,
160                   const NCollection_Vec3<Element_t>& theVec)
161   {
162     SetValue (0, theCol, theVec.x());
163     SetValue (1, theCol, theVec.y());
164     SetValue (2, theCol, theVec.z());
165   }
166
167   //! Set column values by the passed 4 element vector.
168   //! @param theCol [in] the column to change.
169   //! @param theVec [in] the vector of values.
170   void SetColumn (const size_t theCol,
171                   const NCollection_Vec4<Element_t>& theVec)
172   {
173     SetValue (0, theCol, theVec.x());
174     SetValue (1, theCol, theVec.y());
175     SetValue (2, theCol, theVec.z());
176     SetValue (3, theCol, theVec.w());
177   }
178
179   //! Get vector of diagonal elements.
180   //! @return vector of diagonal elements.
181   NCollection_Vec4<Element_t> GetDiagonal() const
182   {
183     return NCollection_Vec4<Element_t> (GetValue (0, 0),
184                                         GetValue (1, 1),
185                                         GetValue (2, 2),
186                                         GetValue (3, 3));
187   }
188
189   //! Change first 3 elements of the diagonal matrix.
190   //! @param theVec the vector of values.
191   void SetDiagonal (const NCollection_Vec3<Element_t>& theVec)
192   {
193     SetValue (0, 0, theVec.x());
194     SetValue (1, 1, theVec.y());
195     SetValue (2, 2, theVec.z());
196   }
197
198   //! Set diagonal elements of the matrix by the passed vector.
199   //! @param theVec [in] the vector of values.
200   void SetDiagonal (const NCollection_Vec4<Element_t>& theVec)
201   {
202     SetValue (0, 0, theVec.x());
203     SetValue (1, 1, theVec.y());
204     SetValue (2, 2, theVec.z());
205     SetValue (3, 3, theVec.w());
206   }
207
208   //! Return 3x3 sub-matrix.
209   NCollection_Mat3<Element_t> GetMat3() const
210   {
211     NCollection_Mat3<Element_t> aMat;
212     aMat.SetColumn (0, GetColumn (0).xyz());
213     aMat.SetColumn (1, GetColumn (1).xyz());
214     aMat.SetColumn (2, GetColumn (2).xyz());
215     return aMat;
216   }
217
218   //! Initialize the zero matrix.
219   void InitZero()
220   {
221     std::memcpy (this, MyZeroArray, sizeof (NCollection_Mat4));
222   }
223
224   //! Checks the matrix for zero (without tolerance).
225   bool IsZero() const
226   {
227     return std::memcmp (this, MyZeroArray, sizeof (NCollection_Mat4)) == 0;
228   }
229
230   //! Initialize the identity matrix.
231   void InitIdentity()
232   {
233     std::memcpy (this, MyIdentityArray, sizeof (NCollection_Mat4));
234   }
235
236   //! Checks the matrix for identity (without tolerance).
237   bool IsIdentity() const
238   {
239     return std::memcmp (this, MyIdentityArray, sizeof (NCollection_Mat4)) == 0;
240   }
241
242   //! Check this matrix for equality with another matrix (without tolerance!).
243   bool IsEqual (const NCollection_Mat4& theOther) const
244   {
245     return std::memcmp (this, &theOther, sizeof(NCollection_Mat4)) == 0;
246   }
247
248   //! Check this matrix for equality with another matrix (without tolerance!).
249   bool operator== (const NCollection_Mat4& theOther) const { return IsEqual (theOther); }
250
251   //! Check this matrix for non-equality with another matrix (without tolerance!).
252   bool operator!= (const NCollection_Mat4& theOther) const { return !IsEqual (theOther); }
253
254   //! Raw access to the data (for OpenGL exchange);
255   //! the data is returned in column-major order.
256   const Element_t* GetData()    const { return myMat; }
257   Element_t*       ChangeData()       { return myMat; }
258
259   //! Multiply by the vector (M * V).
260   //! @param theVec [in] the vector to multiply.
261   NCollection_Vec4<Element_t> operator* (const NCollection_Vec4<Element_t>& theVec) const
262   {
263     return NCollection_Vec4<Element_t> (
264       GetValue (0, 0) * theVec.x() + GetValue (0, 1) * theVec.y() + GetValue (0, 2) * theVec.z() + GetValue (0, 3) * theVec.w(),
265       GetValue (1, 0) * theVec.x() + GetValue (1, 1) * theVec.y() + GetValue (1, 2) * theVec.z() + GetValue (1, 3) * theVec.w(),
266       GetValue (2, 0) * theVec.x() + GetValue (2, 1) * theVec.y() + GetValue (2, 2) * theVec.z() + GetValue (2, 3) * theVec.w(),
267       GetValue (3, 0) * theVec.x() + GetValue (3, 1) * theVec.y() + GetValue (3, 2) * theVec.z() + GetValue (3, 3) * theVec.w());
268   }
269
270   //! Compute matrix multiplication product: A * B.
271   //! @param theMatA [in] the matrix "A".
272   //! @param theMatB [in] the matrix "B".
273   static NCollection_Mat4 Multiply (const NCollection_Mat4& theMatA,
274                                     const NCollection_Mat4& theMatB)
275   {
276     NCollection_Mat4 aMatRes;
277
278     size_t aInputElem;
279     for (size_t aResElem = 0; aResElem < 16; ++aResElem)
280     {
281       aMatRes.myMat[aResElem] = (Element_t )0;
282       for (aInputElem = 0; aInputElem < 4; ++aInputElem)
283       {
284         aMatRes.myMat[aResElem] += theMatA.GetValue(aResElem % 4, aInputElem)
285                                  * theMatB.GetValue(aInputElem, aResElem / 4);
286       }
287     }
288
289     return aMatRes;
290   }
291
292   //! Compute matrix multiplication.
293   //! @param theMat [in] the matrix to multiply.
294   void Multiply (const NCollection_Mat4& theMat)
295   {
296     *this = Multiply(*this, theMat);
297   }
298
299   //! Multiply by the another matrix.
300   //! @param theMat [in] the other matrix.
301   NCollection_Mat4& operator*= (const NCollection_Mat4& theMat)
302   {
303     Multiply (theMat);
304     return *this;
305   }
306
307   //! Compute matrix multiplication product.
308   //! @param theMat [in] the other matrix.
309   //! @return result of multiplication.
310   Standard_NODISCARD NCollection_Mat4 operator* (const NCollection_Mat4& theMat) const
311   {
312     return Multiplied (theMat);
313   }
314
315   //! Compute matrix multiplication product.
316   //! @param theMat [in] the other matrix.
317   //! @return result of multiplication.
318   Standard_NODISCARD NCollection_Mat4 Multiplied (const NCollection_Mat4& theMat) const
319   {
320     NCollection_Mat4 aTempMat (*this);
321     aTempMat *= theMat;
322     return aTempMat;
323   }
324
325   //! Compute per-component multiplication.
326   //! @param theFactor [in] the scale factor.
327   void Multiply (const Element_t theFactor)
328   {
329     for (size_t i = 0; i < 16; ++i)
330     {
331       myMat[i] *= theFactor;
332     }
333   }
334
335   //! Compute per-element multiplication.
336   //! @param theFactor [in] the scale factor.
337   NCollection_Mat4& operator*= (const Element_t theFactor)
338   {
339     Multiply (theFactor);
340     return *this;
341   }
342
343   //! Compute per-element multiplication.
344   //! @param theFactor [in] the scale factor.
345   //! @return the result of multiplication.
346   Standard_NODISCARD NCollection_Mat4 operator* (const Element_t theFactor) const
347   {
348     return Multiplied (theFactor);
349   }
350
351   //! Compute per-element multiplication.
352   //! @param theFactor [in] the scale factor.
353   //! @return the result of multiplication.
354   Standard_NODISCARD NCollection_Mat4 Multiplied (const Element_t theFactor) const
355   {
356     NCollection_Mat4 aTempMat (*this);
357     aTempMat *= theFactor;
358     return aTempMat;
359   }
360
361   //! Compute per-component division.
362   //! @param theFactor [in] the scale factor.
363   void Divide (const Element_t theFactor)
364   {
365     for (size_t i = 0; i < 16; ++i)
366     {
367       myMat[i] /= theFactor;
368     }
369   }
370
371   //! Per-component division.
372   //! @param theScalar [in] the scale factor.
373   NCollection_Mat4& operator/= (const Element_t theScalar)
374   {
375     Divide (theScalar);
376     return *this;
377   }
378
379   //! Divides all the coefficients of the matrix by scalar.
380   Standard_NODISCARD NCollection_Mat4 Divided (const Element_t theScalar) const
381   {
382     NCollection_Mat4 aTempMat (*this);
383     aTempMat /= theScalar;
384     return aTempMat;
385   }
386
387   //! Divides all the coefficients of the matrix by scalar.
388   Standard_NODISCARD NCollection_Mat4 operator/ (const Element_t theScalar) const
389   {
390     return Divided (theScalar);
391   }
392
393   //! Per-component addition of another matrix.
394   void Add (const NCollection_Mat4& theMat)
395   {
396     for (size_t i = 0; i < 16; ++i)
397     {
398       myMat[i] += theMat.myMat[i];
399     }
400   }
401
402   //! Per-component addition of another matrix.
403   NCollection_Mat4& operator+= (const NCollection_Mat4& theMat)
404   {
405     Add (theMat);
406     return *this;
407   }
408
409   //! Per-component subtraction of another matrix.
410   void Subtract (const NCollection_Mat4& theMat)
411   {
412     for (size_t i = 0; i < 16; ++i)
413     {
414       myMat[i] -= theMat.myMat[i];
415     }
416   }
417
418   //! Per-component subtraction of another matrix.
419   NCollection_Mat4& operator-= (const NCollection_Mat4& theMat)
420   {
421     Subtract (theMat);
422     return *this;
423   }
424
425   //! Per-component addition of another matrix.
426   Standard_NODISCARD NCollection_Mat4 Added (const NCollection_Mat4& theMat) const
427   {
428     NCollection_Mat4 aMat (*this);
429     aMat += theMat;
430     return aMat;
431   }
432
433   //! Per-component addition of another matrix.
434   Standard_NODISCARD NCollection_Mat4 operator+ (const NCollection_Mat4& theMat) const { return Added (theMat); }
435
436   //! Per-component subtraction of another matrix.
437   Standard_NODISCARD NCollection_Mat4 Subtracted (const NCollection_Mat4& theMat) const
438   {
439     NCollection_Mat4 aMat (*this);
440     aMat -= theMat;
441     return aMat;
442   }
443
444   //! Per-component subtraction of another matrix.
445   Standard_NODISCARD NCollection_Mat4 operator- (const NCollection_Mat4& theMat) const { return Subtracted (theMat); }
446
447   //! Returns matrix with all components negated.
448   Standard_NODISCARD NCollection_Mat4 Negated() const
449   {
450     NCollection_Mat4 aMat;
451     for (size_t i = 0; i < 16; ++i)
452     {
453       aMat.myMat[i] = -myMat[i];
454     }
455     return aMat;
456   }
457
458   //! Returns matrix with all components negated.
459   Standard_NODISCARD NCollection_Mat4 operator-() const { return Negated(); }
460
461   //! Translate the matrix on the passed vector.
462   //! @param theVec [in] the translation vector.
463   void Translate (const NCollection_Vec3<Element_t>& theVec)
464   {
465     NCollection_Mat4 aTempMat;
466     aTempMat.SetColumn (3, theVec);
467     this->Multiply (aTempMat);
468   }
469
470   //! Transpose the matrix.
471   //! @return transposed copy of the matrix.
472   Standard_NODISCARD NCollection_Mat4 Transposed() const
473   {
474     NCollection_Mat4 aTempMat;
475     aTempMat.SetRow (0, GetColumn (0));
476     aTempMat.SetRow (1, GetColumn (1));
477     aTempMat.SetRow (2, GetColumn (2));
478     aTempMat.SetRow (3, GetColumn (3));
479     return aTempMat;
480   }
481
482   //! Transpose the matrix.
483   void Transpose()
484   {
485     *this = Transposed();
486   }
487
488   //! Compute inverted matrix.
489   //! @param theOutMx [out] the inverted matrix
490   //! @param theDet   [out] determinant of matrix
491   //! @return true if reversion success
492   bool Inverted (NCollection_Mat4<Element_t>& theOutMx, Element_t& theDet) const
493   {
494     Element_t* inv = theOutMx.myMat;
495
496     // use short-cut for better readability
497     const Element_t* m = myMat;
498
499     inv[ 0] = m[ 5] * (m[10] * m[15] - m[11] * m[14]) -
500               m[ 9] * (m[ 6] * m[15] - m[ 7] * m[14]) -
501               m[13] * (m[ 7] * m[10] - m[ 6] * m[11]);
502
503     inv[ 1] = m[ 1] * (m[11] * m[14] - m[10] * m[15]) -
504               m[ 9] * (m[ 3] * m[14] - m[ 2] * m[15]) -
505               m[13] * (m[ 2] * m[11] - m[ 3] * m[10]);
506
507     inv[ 2] = m[ 1] * (m[ 6] * m[15] - m[ 7] * m[14]) -
508               m[ 5] * (m[ 2] * m[15] - m[ 3] * m[14]) -
509               m[13] * (m[ 3] * m[ 6] - m[ 2] * m[ 7]);
510
511     inv[ 3] = m[ 1] * (m[ 7] * m[10] - m[ 6] * m[11]) -
512               m[ 5] * (m[ 3] * m[10] - m[ 2] * m[11]) -
513               m[ 9] * (m[ 2] * m[ 7] - m[ 3] * m[ 6]);
514
515     inv[ 4] = m[ 4] * (m[11] * m[14] - m[10] * m[15]) -
516               m[ 8] * (m[ 7] * m[14] - m[ 6] * m[15]) -
517               m[12] * (m[ 6] * m[11] - m[ 7] * m[10]);
518
519     inv[ 5] = m[ 0] * (m[10] * m[15] - m[11] * m[14]) -
520               m[ 8] * (m[ 2] * m[15] - m[ 3] * m[14]) -
521               m[12] * (m[ 3] * m[10] - m[ 2] * m[11]);
522
523     inv[ 6] = m[ 0] * (m[ 7] * m[14] - m[ 6] * m[15]) -
524               m[ 4] * (m[ 3] * m[14] - m[ 2] * m[15]) -
525               m[12] * (m[ 2] * m[ 7] - m[ 3] * m[ 6]);
526
527     inv[ 7] = m[ 0] * (m[ 6] * m[11] - m[ 7] * m[10]) -
528               m[ 4] * (m[ 2] * m[11] - m[ 3] * m[10]) -
529               m[ 8] * (m[ 3] * m[ 6] - m[ 2] * m[ 7]);
530
531     inv[ 8] = m[ 4] * (m[ 9] * m[15] - m[11] * m[13]) -
532               m[ 8] * (m[ 5] * m[15] - m[ 7] * m[13]) -
533               m[12] * (m[ 7] * m[ 9] - m[ 5] * m[11]);
534
535     inv[ 9] = m[ 0] * (m[11] * m[13] - m[ 9] * m[15]) -
536               m[ 8] * (m[ 3] * m[13] - m[ 1] * m[15]) -
537               m[12] * (m[ 1] * m[11] - m[ 3] * m[ 9]);
538
539     inv[10] = m[ 0] * (m[ 5] * m[15] - m[ 7] * m[13]) -
540               m[ 4] * (m[ 1] * m[15] - m[ 3] * m[13]) -
541               m[12] * (m[ 3] * m[ 5] - m[ 1] * m[ 7]);
542
543     inv[11] = m[ 0] * (m[ 7] * m[ 9] - m[ 5] * m[11]) -
544               m[ 4] * (m[ 3] * m[ 9] - m[ 1] * m[11]) -
545               m[ 8] * (m[ 1] * m[ 7] - m[ 3] * m[ 5]);
546
547     inv[12] = m[ 4] * (m[10] * m[13] - m[ 9] * m[14]) -
548               m[ 8] * (m[ 6] * m[13] - m[ 5] * m[14]) -
549               m[12] * (m[ 5] * m[10] - m[ 6] * m[ 9]);
550
551     inv[13] = m[ 0] * (m[ 9] * m[14] - m[10] * m[13]) -
552               m[ 8] * (m[ 1] * m[14] - m[ 2] * m[13]) -
553               m[12] * (m[ 2] * m[ 9] - m[ 1] * m[10]);
554
555     inv[14] = m[ 0] * (m[ 6] * m[13] - m[ 5] * m[14]) -
556               m[ 4] * (m[ 2] * m[13] - m[ 1] * m[14]) -
557               m[12] * (m[ 1] * m[ 6] - m[ 2] * m[ 5]);
558
559     inv[15] = m[ 0] * (m[ 5] * m[10] - m[ 6] * m[ 9]) -
560               m[ 4] * (m[ 1] * m[10] - m[ 2] * m[ 9]) -
561               m[ 8] * (m[ 2] * m[ 5] - m[ 1] * m[ 6]);
562
563     theDet = m[0] * inv[ 0] +
564              m[1] * inv[ 4] +
565              m[2] * inv[ 8] +
566              m[3] * inv[12];
567     if (theDet == 0)
568     {
569       return false;
570     }
571
572     const Element_t aDiv = (Element_t) 1. / theDet;
573     for (int i = 0; i < 16; ++i)
574     {
575       inv[i] *= aDiv;
576     }
577     return true;
578   }
579
580   //! Compute inverted matrix.
581   //! @param theOutMx [out] the inverted matrix
582   //! @return true if reversion success
583   bool Inverted (NCollection_Mat4<Element_t>& theOutMx) const
584   {
585     Element_t aDet;
586     return Inverted (theOutMx, aDet);
587   }
588
589   //! Return inverted matrix.
590   NCollection_Mat4 Inverted() const
591   {
592     NCollection_Mat4 anInv;
593     if (!Inverted (anInv))
594     {
595       throw Standard_ConstructionError ("NCollection_Mat4::Inverted() - matrix has zero determinant");
596     }
597     return anInv;
598   }
599
600   //! Return determinant of the 3x3 sub-matrix.
601   Element_t DeterminantMat3() const
602   {
603     return (GetValue (0, 0) * GetValue (1, 1) * GetValue (2, 2)
604           + GetValue (0, 1) * GetValue (1, 2) * GetValue (2, 0)
605           + GetValue (0, 2) * GetValue (1, 0) * GetValue (2, 1))
606          - (GetValue (0, 2) * GetValue (1, 1) * GetValue (2, 0)
607           + GetValue (0, 0) * GetValue (1, 2) * GetValue (2, 1)
608           + GetValue (0, 1) * GetValue (1, 0) * GetValue (2, 2));
609   }
610
611   //! Return adjoint (adjugate matrix, e.g. conjugate transpose).
612   Standard_NODISCARD NCollection_Mat4<Element_t> Adjoint() const
613   {
614     NCollection_Mat4<Element_t> aMat;
615     aMat.SetRow (0, crossVec4 ( GetRow (1), GetRow (2), GetRow (3)));
616     aMat.SetRow (1, crossVec4 (-GetRow (0), GetRow (2), GetRow (3)));
617     aMat.SetRow (2, crossVec4 ( GetRow (0), GetRow (1), GetRow (3)));
618     aMat.SetRow (3, crossVec4 (-GetRow (0), GetRow (1), GetRow (2)));
619     return aMat;
620   }
621
622   //! Take values from NCollection_Mat4 with a different element type with type conversion.
623   template <typename Other_t>
624   void ConvertFrom (const NCollection_Mat4<Other_t>& theFrom)
625   {
626     for (int anIdx = 0; anIdx < 16; ++anIdx)
627     {
628       myMat[anIdx] = static_cast<Element_t> (theFrom.myMat[anIdx]);
629     }
630   }
631
632   //! Take values from NCollection_Mat4 with a different element type with type conversion.
633   template <typename Other_t>
634   void Convert (const NCollection_Mat4<Other_t>& theFrom) { ConvertFrom (theFrom); }
635
636   //! Maps plain C array to matrix type.
637   static NCollection_Mat4<Element_t>& Map (Element_t* theData)
638   {
639     return *reinterpret_cast<NCollection_Mat4<Element_t>*> (theData);
640   }
641
642   //! Maps plain C array to matrix type.
643   static const NCollection_Mat4<Element_t>& Map (const Element_t* theData)
644   {
645     return *reinterpret_cast<const NCollection_Mat4<Element_t>*> (theData);
646   }
647
648   //! Dumps the content of me into the stream
649   void DumpJson (Standard_OStream& theOStream, Standard_Integer) const
650   {
651     OCCT_DUMP_FIELD_VALUES_NUMERICAL (theOStream, "NCollection_Mat4", 16,
652       GetValue (0, 0),  GetValue (0, 1), GetValue (0, 2),  GetValue (0, 3),
653       GetValue (1, 0),  GetValue (1, 1), GetValue (1, 2),  GetValue (1, 3),
654       GetValue (2, 0),  GetValue (2, 1), GetValue (2, 2),  GetValue (2, 3),
655       GetValue (3, 0),  GetValue (3, 1), GetValue (3, 2),  GetValue (3, 3))
656   }
657
658 private:
659
660   //! Cross-product has no direct meaning in 4D space - provided for local usage.
661   static NCollection_Vec4<Element_t> crossVec4 (const NCollection_Vec4<Element_t>& theA,
662                                                 const NCollection_Vec4<Element_t>& theB,
663                                                 const NCollection_Vec4<Element_t>& theC)
664   {
665     const Element_t aD1 = (theB.z() * theC.w()) - (theB.w() * theC.z());
666     const Element_t aD2 = (theB.y() * theC.w()) - (theB.w() * theC.y());
667     const Element_t aD3 = (theB.y() * theC.z()) - (theB.z() * theC.y());
668     const Element_t aD4 = (theB.x() * theC.w()) - (theB.w() * theC.x());
669     const Element_t aD5 = (theB.x() * theC.z()) - (theB.z() * theC.x());
670     const Element_t aD6 = (theB.x() * theC.y()) - (theB.y() * theC.x());
671
672     NCollection_Vec4<Element_t> aVec;
673     aVec.x() = -theA.y() * aD1 + theA.z() * aD2 - theA.w() * aD3;
674     aVec.y() =  theA.x() * aD1 - theA.z() * aD4 + theA.w() * aD5;
675     aVec.z() = -theA.x() * aD2 + theA.y() * aD4 - theA.w() * aD6;
676     aVec.w() =  theA.x() * aD3 - theA.y() * aD5 + theA.z() * aD6;
677     return aVec;
678   }
679
680 private:
681
682   Element_t myMat[16];
683
684 private:
685
686   static const Element_t MyZeroArray[16];
687   static const Element_t MyIdentityArray[16];
688
689   // All instantiations are friend to each other
690   template<class OtherType> friend class NCollection_Mat4;
691
692 };
693
694 template<typename Element_t>
695 const Element_t NCollection_Mat4<Element_t>::MyZeroArray[] =
696   {0, 0, 0, 0,
697    0, 0, 0, 0,
698    0, 0, 0, 0,
699    0, 0, 0, 0};
700
701 template<typename Element_t>
702 const Element_t NCollection_Mat4<Element_t>::MyIdentityArray[] =
703   {1, 0, 0, 0,
704    0, 1, 0, 0,
705    0, 0, 1, 0,
706    0, 0, 0, 1};
707
708 #if defined(_MSC_VER) && (_MSC_VER >= 1900)
709   #include <type_traits>
710
711   static_assert(std::is_trivially_copyable<NCollection_Mat4<float>>::value, "NCollection_Mat4 is not is_trivially_copyable() structure!");
712   static_assert(std::is_standard_layout   <NCollection_Mat4<float>>::value, "NCollection_Mat4 is not is_standard_layout() structure!");
713   static_assert(sizeof(NCollection_Mat4<float>) == sizeof(float)*16,        "NCollection_Mat4 is not packed/aligned!");
714 #endif
715
716 #endif // _NCollection_Mat4_HeaderFile