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