0031004: Coding - eliminate warnings issued by gcc 9.1.0
[occt.git] / src / Graphic3d / Graphic3d_TransformUtils.hxx
1 // Created on: 2015-06-18
2 // Copyright (c) 2015 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #ifndef _Graphic3d_TransformUtils_HeaderFile
16 #define _Graphic3d_TransformUtils_HeaderFile
17
18 #include <gp_Trsf.hxx>
19 #include <Graphic3d_Vec.hxx>
20 #include <Standard_math.hxx> // M_PI
21
22 //! Helper class that implements transformation matrix functionality.
23 namespace Graphic3d_TransformUtils
24 {
25   template<class T> struct MatrixType {};
26
27   template<> struct MatrixType<Standard_Real> { typedef Graphic3d_Mat4d Mat4; };
28
29   template<> struct MatrixType<Standard_ShortReal> { typedef Graphic3d_Mat4 Mat4; };
30
31   template<class T> struct VectorType {};
32
33   template<> struct VectorType<Standard_Real> {
34     typedef Graphic3d_Vec2d Vec2;
35     typedef Graphic3d_Vec3d Vec3;
36     typedef Graphic3d_Vec4d Vec4;
37   };
38
39   template<> struct VectorType<Standard_ShortReal> {
40     typedef Graphic3d_Vec2 Vec2;
41     typedef Graphic3d_Vec3 Vec3;
42     typedef Graphic3d_Vec4 Vec4;
43   };
44
45   //! Converts gp_Trsf to Graphic3d_Mat4.
46   template<class T>
47   static void Convert (const gp_Trsf&                theTransformation,
48                        typename MatrixType<T>::Mat4& theOut);
49
50   //! Constructs a 3D orthographic projection matrix.
51   template<class T>
52   static void Ortho (typename MatrixType<T>::Mat4& theOut,
53                      const T                       theLeft,
54                      const T                       theRight,
55                      const T                       theBottom,
56                      const T                       theTop,
57                      const T                       theZNear,
58                      const T                       theZFar);
59
60   //! Constructs a 2D orthographic projection matrix.
61   template<class T>
62   static void Ortho2D (typename MatrixType<T>::Mat4& theOut,
63                        const T                       theLeft,
64                        const T                       theRight,
65                        const T                       theBottom,
66                        const T                       theTop);
67
68   //! Maps object coordinates to window coordinates.
69   template<class T>
70   static Standard_Boolean Project (const T                             theObjX,
71                                    const T                             theObjY,
72                                    const T                             theObjZ,
73                                    const typename MatrixType<T>::Mat4& theModViewMat,
74                                    const typename MatrixType<T>::Mat4& theProjectMat,
75                                    const Standard_Integer              theViewport[4],
76                                    T&                                  theWinX,
77                                    T&                                  theWinY,
78                                    T&                                  theWinZ);
79
80   //! Maps window coordinates to object coordinates.
81   template<class T>
82   static Standard_Boolean UnProject (const T                             theWinX,
83                                      const T                             theWinY,
84                                      const T                             theWinZ,
85                                      const typename MatrixType<T>::Mat4& theModViewMat,
86                                      const typename MatrixType<T>::Mat4& theProjectMat,
87                                      const Standard_Integer              theViewport[4],
88                                      T&                                  theObjX,
89                                      T&                                  theObjY,
90                                      T&                                  theObjZ);
91
92   //! Constructs a 4x4 rotation matrix.
93   template<class T>
94   static void ConstructRotate (typename MatrixType<T>::Mat4& theOut,
95                                T                             theA,
96                                T                             theX,
97                                T                             theY,
98                                T                             theZ);
99
100   //! Constructs a 4x4 rotation matrix.
101   template<class T>
102   static void Rotate (typename MatrixType<T>::Mat4& theOut,
103                       T                             theA,
104                       T                             theX,
105                       T                             theY,
106                       T                             theZ);
107
108   //! Constructs a 4x4 scaling matrix.
109   template<class T>
110   static void Scale (typename MatrixType<T>::Mat4& theOut,
111                      T                             theX,
112                      T                             theY,
113                      T                             theZ);
114
115   //! Constructs a 4x4 translation matrix.
116   template<class T>
117   static void Translate (typename MatrixType<T>::Mat4& theOut,
118                          T                             theX,
119                          T                             theY,
120                          T                             theZ);
121
122   //! Returns scaling factor from 3x3 affine matrix.
123   template<class T>
124   static Standard_Real ScaleFactor (const typename MatrixType<T>::Mat4& theMatrix);
125 }
126
127 // =======================================================================
128 // function : Convert
129 // purpose  :
130 // =======================================================================
131 template<class T>
132 void Graphic3d_TransformUtils::Convert (const gp_Trsf&                theTransformation,
133                                         typename MatrixType<T>::Mat4& theOut)
134 {
135   theOut.InitIdentity();
136
137   // Copy a 3x3 submatrix.
138   theOut.ChangeValue (0, 0) = theTransformation.Value (1, 1);
139   theOut.ChangeValue (0, 1) = theTransformation.Value (1, 2);
140   theOut.ChangeValue (0, 2) = theTransformation.Value (1, 3);
141   theOut.ChangeValue (1, 0) = theTransformation.Value (2, 1);
142   theOut.ChangeValue (1, 1) = theTransformation.Value (2, 2);
143   theOut.ChangeValue (1, 2) = theTransformation.Value (2, 3);
144   theOut.ChangeValue (2, 0) = theTransformation.Value (3, 1);
145   theOut.ChangeValue (2, 1) = theTransformation.Value (3, 2);
146   theOut.ChangeValue (2, 2) = theTransformation.Value (3, 3);
147
148   // Add a translate component.
149   theOut.ChangeValue (0, 3) = theTransformation.TranslationPart().X();
150   theOut.ChangeValue (1, 3) = theTransformation.TranslationPart().Y();
151   theOut.ChangeValue (2, 3) = theTransformation.TranslationPart().Z();
152 }
153
154 // =======================================================================
155 // function : Rotate
156 // purpose  : Constructs a 4x4 rotation matrix
157 // =======================================================================
158 template<class T>
159 void Graphic3d_TransformUtils::Rotate (typename MatrixType<T>::Mat4& theOut,
160                                        T                             theA,
161                                        T                             theX,
162                                        T                             theY,
163                                        T                             theZ)
164 {
165   typename MatrixType<T>::Mat4 aMat;
166   ConstructRotate (aMat, theA, theX, theY, theZ);
167   theOut = theOut * aMat;
168 }
169
170 // =======================================================================
171 // function : Translate
172 // purpose  : Constructs a 4x4 translation matrix
173 // =======================================================================
174 template<class T>
175 void Graphic3d_TransformUtils::Translate (typename MatrixType<T>::Mat4& theOut,
176                                           T                             theX,
177                                           T                             theY,
178                                           T                             theZ)
179 {
180   theOut.ChangeValue (0, 3) = theOut.GetValue (0, 0) * theX +
181                               theOut.GetValue (0, 1) * theY +
182                               theOut.GetValue (0, 2) * theZ +
183                               theOut.GetValue (0, 3);
184
185   theOut.ChangeValue (1, 3) = theOut.GetValue (1, 0) * theX +
186                               theOut.GetValue (1, 1) * theY +
187                               theOut.GetValue (1, 2) * theZ +
188                               theOut.GetValue (1, 3);
189
190   theOut.ChangeValue (2, 3) = theOut.GetValue (2, 0) * theX +
191                               theOut.GetValue (2, 1) * theY +
192                               theOut.GetValue (2, 2) * theZ +
193                               theOut.GetValue (2, 3);
194
195   theOut.ChangeValue (3, 3) = theOut.GetValue (3, 0) * theX +
196                               theOut.GetValue (3, 1) * theY +
197                               theOut.GetValue (3, 2) * theZ +
198                               theOut.GetValue (3, 3);
199 }
200
201 // =======================================================================
202 // function : Scale
203 // purpose  : Constructs a 4x4 scaling matrix
204 // =======================================================================
205 template<class T>
206 void Graphic3d_TransformUtils::Scale (typename MatrixType<T>::Mat4& theOut,
207                                       T                             theX,
208                                       T                             theY,
209                                       T                             theZ)
210 {
211   theOut.ChangeValue (0, 0) *= theX;
212   theOut.ChangeValue (1, 0) *= theX;
213   theOut.ChangeValue (2, 0) *= theX;
214   theOut.ChangeValue (3, 0) *= theX;
215
216   theOut.ChangeValue (0, 1) *= theY;
217   theOut.ChangeValue (1, 1) *= theY;
218   theOut.ChangeValue (2, 1) *= theY;
219   theOut.ChangeValue (3, 1) *= theY;
220
221   theOut.ChangeValue (0, 2) *= theZ;
222   theOut.ChangeValue (1, 2) *= theZ;
223   theOut.ChangeValue (2, 2) *= theZ;
224   theOut.ChangeValue (3, 2) *= theZ;
225 }
226
227 // =======================================================================
228 // function : ConstructRotate
229 // purpose  : Constructs a 4x4 rotation matrix
230 // =======================================================================
231 template<class T>
232 void Graphic3d_TransformUtils::ConstructRotate (typename MatrixType<T>::Mat4& theOut,
233                                                 T                             theA,
234                                                 T                             theX,
235                                                 T                             theY,
236                                                 T                             theZ)
237 {
238   const T aSin = std::sin (theA * static_cast<T> (M_PI / 180.0));
239   const T aCos = std::cos (theA * static_cast<T> (M_PI / 180.0));
240
241   const Standard_Boolean isOnlyX = (theX != static_cast<T> (0.0))
242                                 && (theY == static_cast<T> (0.0))
243                                 && (theZ == static_cast<T> (0.0));
244
245   const Standard_Boolean isOnlyY = (theX == static_cast<T> (0.0))
246                                 && (theY != static_cast<T> (0.0))
247                                 && (theZ == static_cast<T> (0.0));
248
249   const Standard_Boolean isOnlyZ = (theX == static_cast<T> (0.0))
250                                 && (theY == static_cast<T> (0.0))
251                                 && (theZ != static_cast<T> (0.0));
252
253   if (isOnlyX) // Rotation only around X.
254   {
255     theOut.SetValue (1, 1, aCos);
256     theOut.SetValue (2, 2, aCos);
257
258     if (theX < static_cast<T> (0.0))
259     {
260       theOut.SetValue (1, 2,  aSin);
261       theOut.SetValue (2, 1, -aSin);
262     }
263     else
264     {
265       theOut.SetValue (1, 2, -aSin);
266       theOut.SetValue (2, 1,  aSin);
267     }
268
269     return;
270   }
271   else if (isOnlyY) // Rotation only around Y.
272   {
273     theOut.SetValue (0, 0, aCos);
274     theOut.SetValue (2, 2, aCos);
275
276     if (theY < static_cast<T> (0.0))
277     {
278       theOut.SetValue (0, 2, -aSin);
279       theOut.SetValue (2, 0,  aSin);
280     }
281     else
282     {
283       theOut.SetValue (0, 2,  aSin);
284       theOut.SetValue (2, 0, -aSin);
285     }
286
287     return;
288   }
289   else if (isOnlyZ) // Rotation only around Z.
290   {
291     theOut.SetValue (0, 0, aCos);
292     theOut.SetValue (1, 1, aCos);
293
294     if (theZ < static_cast<T> (0.0))
295     {
296       theOut.SetValue (0, 1,  aSin);
297       theOut.SetValue (1, 0, -aSin);
298     }
299     else
300     {
301       theOut.SetValue (0, 1, -aSin);
302       theOut.SetValue (1, 0,  aSin);
303     }
304
305     return;
306   }
307
308   T aNorm = std::sqrt (theX * theX + theY * theY + theZ * theZ);
309
310   if (aNorm <= static_cast<T> (1.0e-4))
311   {
312     return; // Negligible rotation.
313   }
314
315   aNorm = static_cast<T> (1.0) / aNorm;
316
317   theX *= aNorm;
318   theY *= aNorm;
319   theZ *= aNorm;
320
321   const T aXX = theX * theX;
322   const T aYY = theY * theY;
323   const T aZZ = theZ * theZ;
324   const T aXY = theX * theY;
325   const T aYZ = theY * theZ;
326   const T aZX = theZ * theX;
327   const T aSinX = theX * aSin;
328   const T aSinY = theY * aSin;
329   const T aSinZ = theZ * aSin;
330
331   const T aOneMinusCos = static_cast<T> (1.0) - aCos;
332
333   theOut.SetValue (0, 0, aOneMinusCos * aXX + aCos);
334   theOut.SetValue (0, 1, aOneMinusCos * aXY - aSinZ);
335   theOut.SetValue (0, 2, aOneMinusCos * aZX + aSinY);
336
337   theOut.SetValue (1, 0, aOneMinusCos * aXY + aSinZ);
338   theOut.SetValue (1, 1, aOneMinusCos * aYY + aCos);
339   theOut.SetValue (1, 2, aOneMinusCos * aYZ - aSinX);
340
341   theOut.SetValue (2, 0, aOneMinusCos * aZX - aSinY);
342   theOut.SetValue (2, 1, aOneMinusCos * aYZ + aSinX);
343   theOut.SetValue (2, 2, aOneMinusCos * aZZ + aCos);
344 }
345
346 // =======================================================================
347 // function : Ortho
348 // purpose  : Constructs a 3D orthographic projection matrix
349 // =======================================================================
350 template<class T>
351 void Graphic3d_TransformUtils::Ortho (typename MatrixType<T>::Mat4& theOut,
352                                       const T                       theLeft,
353                                       const T                       theRight,
354                                       const T                       theBottom,
355                                       const T                       theTop,
356                                       const T                       theZNear,
357                                       const T                       theZFar)
358 {
359   theOut.InitIdentity();
360
361   T* aData = theOut.ChangeData();
362
363   const T anInvDx = static_cast<T> (1.0) / (theRight - theLeft);
364   const T anInvDy = static_cast<T> (1.0) / (theTop - theBottom);
365   const T anInvDz = static_cast<T> (1.0) / (theZFar - theZNear);
366
367   aData[0]  = static_cast<T> ( 2.0) * anInvDx;
368   aData[5]  = static_cast<T> ( 2.0) * anInvDy;
369   aData[10] = static_cast<T> (-2.0) * anInvDz;
370
371   aData[12] = -(theRight + theLeft) * anInvDx;
372   aData[13] = -(theTop + theBottom) * anInvDy;
373   aData[14] = -(theZFar + theZNear) * anInvDz;
374 }
375
376 // =======================================================================
377 // function : Ortho2D
378 // purpose  : Constructs a 2D orthographic projection matrix
379 // =======================================================================
380 template<class T>
381 void Graphic3d_TransformUtils::Ortho2D (typename MatrixType<T>::Mat4& theOut,
382                                         const T                       theLeft,
383                                         const T                       theRight,
384                                         const T                       theBottom,
385                                         const T                       theTop)
386 {
387   Ortho (theOut, theLeft, theRight, theBottom, theTop, static_cast<T> (-1.0), static_cast<T> (1.0));
388 }
389
390 // =======================================================================
391 // function : Project
392 // purpose  : Maps object coordinates to window coordinates
393 // =======================================================================
394 template<class T>
395 static Standard_Boolean Graphic3d_TransformUtils::Project (const T                             theObjX,
396                                                            const T                             theObjY,
397                                                            const T                             theObjZ,
398                                                            const typename MatrixType<T>::Mat4& theModViewMat,
399                                                            const typename MatrixType<T>::Mat4& theProjectMat,
400                                                            const Standard_Integer              theViewport[4],
401                                                            T&                                  theWinX,
402                                                            T&                                  theWinY,
403                                                            T&                                  theWinZ)
404 {
405   typename VectorType<T>::Vec4 anIn (theObjX, theObjY, theObjZ, static_cast<T> (1.0));
406
407   typename VectorType<T>::Vec4 anOut = theProjectMat * (theModViewMat * anIn);
408
409   if (anOut.w() == static_cast<T> (0.0))
410   {
411     return Standard_False;
412   }
413
414   anOut.w() = static_cast<T> (1.0) / anOut.w();
415
416   anOut.x() *= anOut.w();
417   anOut.y() *= anOut.w();
418   anOut.z() *= anOut.w();
419
420   // Map x, y and z to range 0-1.
421   anOut.x() = anOut.x() * static_cast<T> (0.5) + static_cast<T> (0.5);
422   anOut.y() = anOut.y() * static_cast<T> (0.5) + static_cast<T> (0.5);
423   anOut.z() = anOut.z() * static_cast<T> (0.5) + static_cast<T> (0.5);
424
425   // Map x,y to viewport.
426   anOut.x() = anOut.x() * theViewport[2] + theViewport[0];
427   anOut.y() = anOut.y() * theViewport[3] + theViewport[1];
428
429   theWinX = anOut.x();
430   theWinY = anOut.y();
431   theWinZ = anOut.z();
432
433   return Standard_True;
434 }
435
436 // =======================================================================
437 // function : UnProject
438 // purpose  : Maps window coordinates to object coordinates
439 // =======================================================================
440 template<class T>
441 static Standard_Boolean Graphic3d_TransformUtils::UnProject (const T                             theWinX,
442                                                              const T                             theWinY,
443                                                              const T                             theWinZ,
444                                                              const typename MatrixType<T>::Mat4& theModViewMat,
445                                                              const typename MatrixType<T>::Mat4& theProjectMat,
446                                                              const Standard_Integer              theViewport[4],
447                                                              T&                                  theObjX,
448                                                              T&                                  theObjY,
449                                                              T&                                  theObjZ)
450 {
451   typename MatrixType<T>::Mat4 anUnviewMat;
452
453   if (!(theProjectMat * theModViewMat).Inverted (anUnviewMat))
454   {
455     return Standard_False;
456   }
457
458   typename VectorType<T>::Vec4 anIn (theWinX, theWinY, theWinZ, static_cast<T> (1.0));
459
460   // Map x and y from window coordinates.
461   anIn.x() = (anIn.x() - theViewport[0]) / theViewport[2];
462   anIn.y() = (anIn.y() - theViewport[1]) / theViewport[3];
463
464   // Map to range -1 to 1.
465   anIn.x() = anIn.x() * static_cast<T> (2.0) - static_cast<T> (1.0);
466   anIn.y() = anIn.y() * static_cast<T> (2.0) - static_cast<T> (1.0);
467   anIn.z() = anIn.z() * static_cast<T> (2.0) - static_cast<T> (1.0);
468
469   typename VectorType<T>::Vec4 anOut = anUnviewMat * anIn;
470
471   if (anOut.w() == static_cast<T> (0.0))
472   {
473     return Standard_False;
474   }
475
476   anOut.w() = static_cast<T> (1.0) / anOut.w();
477
478   anOut.x() *= anOut.w();
479   anOut.y() *= anOut.w();
480   anOut.z() *= anOut.w();
481
482   theObjX = anOut.x();
483   theObjY = anOut.y();
484   theObjZ = anOut.z();
485
486   return Standard_True;
487 }
488
489 // =======================================================================
490 // function : ScaleFactor
491 // purpose  :
492 // =======================================================================
493 template<class T>
494 static Standard_Real Graphic3d_TransformUtils::ScaleFactor (const typename MatrixType<T>::Mat4& theMatrix)
495 {
496   // The determinant of the matrix should give the scale factor (cubed).
497   const T aDeterminant = (theMatrix.GetValue (0, 0) * theMatrix.GetValue (1, 1) * theMatrix.GetValue (2, 2) +
498                           theMatrix.GetValue (0, 1) * theMatrix.GetValue (1, 2) * theMatrix.GetValue (2, 0) +
499                           theMatrix.GetValue (0, 2) * theMatrix.GetValue (1, 0) * theMatrix.GetValue (2, 1))
500                        - (theMatrix.GetValue (0, 2) * theMatrix.GetValue (1, 1) * theMatrix.GetValue (2, 0) +
501                           theMatrix.GetValue (0, 0) * theMatrix.GetValue (1, 2) * theMatrix.GetValue (2, 1) +
502                           theMatrix.GetValue (0, 1) * theMatrix.GetValue (1, 0) * theMatrix.GetValue (2, 2));
503
504   return Pow (static_cast<Standard_Real> (aDeterminant), 1.0 / 3.0);
505 }
506
507 #endif // _Graphic3d_TransformUtils_HeaderFile