0026885: Visualization - drop redundant aspects from structure level
[occt.git] / src / Graphic3d / Graphic3d_TransformPers.hxx
1 // Created on: 2015-06-18
2 // Created by: Anton POLETAEV
3 // Copyright (c) 2015 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 _Graphic3d_TransformPers_HeaderFile
17 #define _Graphic3d_TransformPers_HeaderFile
18
19 #include <Bnd_Box.hxx>
20 #include <BVH_Box.hxx>
21 #include <Graphic3d_TransformUtils.hxx>
22 #include <Graphic3d_TransModeFlags.hxx>
23 #include <NCollection_Mat4.hxx>
24 #include <NCollection_Vec4.hxx>
25
26 //! Class for keeping and computing transformation persistence.
27 class Graphic3d_TransformPers
28 {
29 public:
30
31   DEFINE_STANDARD_ALLOC
32
33   //! Default constructor.
34   Graphic3d_TransformPers()
35   : Flags (Graphic3d_TMF_None),
36     Point (0.0, 0.0, 0.0) {}
37
38   //! Transformation persistence mode flags.
39   Graphic3d_TransModeFlags Flags;
40
41   //! Reference point for transformation.
42   Graphic3d_Vec3d Point;
43
44 public:
45
46   //! Apply transformation to bounding box of presentation.
47   //! @param theProjection [in] the projection transformation matrix.
48   //! @param theWorldView [in] the world view transformation matrix.
49   //! @param theViewportWidth [in] the width of viewport (for 2d persistence).
50   //! @param theViewportHeight [in] the height of viewport (for 2d persistence).
51   //! @param theBoundingBox [in/out] the bounding box to transform.
52   template<class T>
53   void Apply (const NCollection_Mat4<T>& theProjection,
54               const NCollection_Mat4<T>& theWorldView,
55               const Standard_Integer theViewportWidth,
56               const Standard_Integer theViewportHeight,
57               Bnd_Box& theBoundingBox) const;
58
59   //! Apply transformation to bounding box of presentation
60   //! @param theProjection [in] the projection transformation matrix.
61   //! @param theWorldView [in] the world view transformation matrix.
62   //! @param theViewportWidth [in] the width of viewport (for 2d persistence).
63   //! @param theViewportHeight [in] the height of viewport (for 2d persistence).
64   //! @param theBoundingBox [in/out] the bounding box to transform.
65   template<class T>
66   void Apply (const NCollection_Mat4<T>& theProjection,
67               const NCollection_Mat4<T>& theWorldView,
68               const Standard_Integer theViewportWidth,
69               const Standard_Integer theViewportHeight,
70               BVH_Box<T, 4>& theBoundingBox) const;
71
72   //! Compute transformation.
73   //! Computed matrix can be applied to model world transformation
74   //! of an object to implement effect of transformation persistence.
75   //! @param theProjection [in] the projection transformation matrix.
76   //! @param theWorldView [in] the world view transformation matrix.
77   //! @param theViewportWidth [in] the width of viewport (for 2d persistence).
78   //! @param theViewportHeight [in] the height of viewport (for 2d persistence).
79   //! @return transformation matrix to be applied to model world transformation of an object.
80   template<class T>
81   NCollection_Mat4<T> Compute (const NCollection_Mat4<T>& theProjection,
82                                const NCollection_Mat4<T>& theWorldView,
83                                const Standard_Integer theViewportWidth,
84                                const Standard_Integer theViewportHeight) const;
85
86   template<class T>
87   void Apply (NCollection_Mat4<T>& theProjection,
88               NCollection_Mat4<T>& theWorldView,
89               const Standard_Integer theViewportWidth,
90               const Standard_Integer theViewportHeight) const;
91 };
92
93 // =======================================================================
94 // function : Apply
95 // purpose  : Apply transformation to world view and projection matrices.
96 // =======================================================================
97 template<class T>
98 void Graphic3d_TransformPers::Apply (NCollection_Mat4<T>& theProjection,
99                                      NCollection_Mat4<T>& theWorldView,
100                                      const Standard_Integer theViewportWidth,
101                                      const Standard_Integer theViewportHeight) const
102 {
103   if (!Flags)
104   {
105     return;
106   }
107
108   if (Flags & Graphic3d_TMF_2d)
109   {
110     T aLeft   = -static_cast<T> (theViewportWidth  / 2);
111     T aRight  =  static_cast<T> (theViewportWidth  / 2);
112     T aBottom = -static_cast<T> (theViewportHeight / 2);
113     T aTop    =  static_cast<T> (theViewportHeight / 2);
114     T aGap    =  static_cast<T> (Point.z());
115     if (Point.x() > 0)
116     {
117       aLeft  -= static_cast<T> (theViewportWidth / 2) - aGap;
118       aRight -= static_cast<T> (theViewportWidth / 2) - aGap;
119     }
120     else if (Point.x() < 0)
121     {
122       aLeft  += static_cast<T> (theViewportWidth / 2) - aGap;
123       aRight += static_cast<T> (theViewportWidth / 2) - aGap;
124     }
125     if (Point.y() > 0)
126     {
127       aBottom -= static_cast<T> (theViewportHeight / 2) - aGap;
128       aTop    -= static_cast<T> (theViewportHeight / 2) - aGap;
129     }
130     else if (Point.y() < 0)
131     {
132       aBottom += static_cast<T> (theViewportHeight / 2) - aGap;
133       aTop    += static_cast<T> (theViewportHeight / 2) - aGap;
134     }
135     if (Flags == Graphic3d_TMF_2d_IsTopDown)
136     {
137       const T aTemp = aTop;
138       aTop    = aBottom;
139       aBottom = aTemp;
140     }
141
142     Graphic3d_TransformUtils::Ortho2D<T> (theProjection, aLeft, aRight, aBottom, aTop);
143
144     theWorldView.InitIdentity();
145   }
146   else
147   {
148     // Compute reference point for transformation in untransformed projection space.
149     NCollection_Vec4<T> aRefPoint (static_cast<T> (Point.x()),
150                                    static_cast<T> (Point.y()),
151                                    static_cast<T> (Point.z()),
152                                    static_cast<T> (1.0));
153     NCollection_Vec4<T> aRefPointProj;
154     if ((Flags & Graphic3d_TMF_PanPers) != Graphic3d_TMF_PanPers)
155     {
156       aRefPointProj  = theProjection * (theWorldView * aRefPoint);
157       aRefPointProj /= aRefPointProj.w();
158     }
159
160     // Prevent zooming.
161     if (Flags & Graphic3d_TMF_ZoomPers)
162     {
163       const T aDet00 = (2.0f / theViewportWidth) / theProjection.GetValue(0, 0);
164       const T aDet11 = (2.0f / theViewportHeight) / theProjection.GetValue(1, 1);
165       const T aDet2 = Max (aDet00, aDet11);
166
167       theProjection.ChangeValue(0, 0) *= aDet00;
168       theProjection.ChangeValue(1, 1) *= aDet11;
169       theProjection.ChangeValue(2, 2) *= aDet2;
170     }
171
172     if (Flags == Graphic3d_TMF_TriedronPers)
173     {
174       // Compute fixed-zoom multiplier. Actually function works ugly with TelPerspective!
175       const T aDet2 = static_cast<T> (0.002) / Max (theProjection.GetValue (1, 1), theProjection.GetValue (0, 0));
176
177       theProjection.ChangeValue (0, 0) *= aDet2;
178       theProjection.ChangeValue (1, 1) *= aDet2;
179       theProjection.ChangeValue (2, 2) *= aDet2;
180     }
181
182     // Prevent translation by nullifying translation component.
183     if ((Flags & Graphic3d_TMF_PanPers) || Flags == Graphic3d_TMF_TriedronPers)
184     {
185       theWorldView .SetValue (0, 3, static_cast<T> (0.0));
186       theWorldView .SetValue (1, 3, static_cast<T> (0.0));
187       theWorldView .SetValue (2, 3, static_cast<T> (0.0));
188       theProjection.SetValue (0, 3, static_cast<T> (0.0));
189       theProjection.SetValue (1, 3, static_cast<T> (0.0));
190       theProjection.SetValue (2, 3, static_cast<T> (0.0));
191     }
192
193     // Prevent scaling-on-axis.
194     if (Flags & Graphic3d_TMF_ZoomPers)
195     {
196       NCollection_Vec3<T> aVecX = theWorldView.GetColumn (0).xyz();
197       NCollection_Vec3<T> aVecY = theWorldView.GetColumn (1).xyz();
198       NCollection_Vec3<T> aVecZ = theWorldView.GetColumn (2).xyz();
199       T aScaleX = aVecX.Modulus();
200       T aScaleY = aVecY.Modulus();
201       T aScaleZ = aVecZ.Modulus();
202       for (Standard_Integer anI = 0; anI < 3; ++anI)
203       {
204         theWorldView.ChangeValue (0, anI) /= aScaleX;
205         theWorldView.ChangeValue (1, anI) /= aScaleY;
206         theWorldView.ChangeValue (2, anI) /= aScaleZ;
207       }
208     }
209
210     // Prevent rotation by nullifying rotation component.
211     if (Flags & Graphic3d_TMF_RotatePers)
212     {
213       theWorldView.SetValue (0, 0, static_cast<T> (1.0));
214       theWorldView.SetValue (1, 0, static_cast<T> (0.0));
215       theWorldView.SetValue (2, 0, static_cast<T> (0.0));
216
217       theWorldView.SetValue (0, 1, static_cast<T> (0.0));
218       theWorldView.SetValue (1, 1, static_cast<T> (1.0));
219       theWorldView.SetValue (2, 1, static_cast<T> (0.0));
220
221       theWorldView.SetValue (0, 2, static_cast<T> (0.0));
222       theWorldView.SetValue (1, 2, static_cast<T> (0.0));
223       theWorldView.SetValue (2, 2, static_cast<T> (1.0));
224     }
225
226     if (Flags == Graphic3d_TMF_TriedronPers)
227     {
228       if (Point.x() != 0.0 && Point.y() != 0.0)
229       {
230         NCollection_Mat4<T> anUnviewMat;
231
232         if (!(theProjection).Inverted (anUnviewMat))
233         {
234           Standard_ProgramError::Raise ("Graphic3d_TransformPers::Apply, can not inverse projection matrix.");
235         }
236
237         NCollection_Vec4<T> aProjMax (static_cast<T> ( 1.0), static_cast<T> ( 1.0), static_cast<T> (0.0), static_cast<T> (1.0));
238         NCollection_Vec4<T> aProjMin (static_cast<T> (-1.0), static_cast<T> (-1.0), static_cast<T> (0.0), static_cast<T> (1.0));
239         NCollection_Vec4<T> aViewMax = anUnviewMat * aProjMax;
240         NCollection_Vec4<T> aViewMin = anUnviewMat * aProjMin;
241
242         aViewMax /= aViewMax.w();
243         aViewMin /= aViewMin.w();
244
245         T aMoveX = static_cast<T> (0.5) * (aViewMax.x() - aViewMin.x() - static_cast<T> (Point.z()));
246         T aMoveY = static_cast<T> (0.5) * (aViewMax.y() - aViewMin.y() - static_cast<T> (Point.z()));
247
248         aMoveX = (Point.x() > 0.0) ? aMoveX : -aMoveX;
249         aMoveY = (Point.y() > 0.0) ? aMoveY : -aMoveY;
250
251         Graphic3d_TransformUtils::Translate<T> (theProjection, aMoveX, aMoveY, static_cast<T> (0.0));
252       }
253     }
254     else if ((Flags & Graphic3d_TMF_PanPers) != Graphic3d_TMF_PanPers)
255     {
256       NCollection_Mat4<T> anUnviewMat;
257
258       if (!(theProjection * theWorldView).Inverted (anUnviewMat))
259       {
260         Standard_ProgramError::Raise ("Graphic3d_TransformPers::Apply, can not inverse world view projection matrix.");
261       }
262
263       // Move to reference point location in transformed view projection space.
264       aRefPoint  = anUnviewMat * aRefPointProj;
265       aRefPoint /= aRefPoint.w();
266
267       Graphic3d_TransformUtils::Translate<T> (theWorldView, aRefPoint.x(), aRefPoint.y(), aRefPoint.z());
268     }
269   }
270 }
271
272 // =======================================================================
273 // function : Apply
274 // purpose  : Apply transformation to bounding box of presentation.
275 // =======================================================================
276 template<class T>
277 void Graphic3d_TransformPers::Apply (const NCollection_Mat4<T>& theProjection,
278                                      const NCollection_Mat4<T>& theWorldView,
279                                      const Standard_Integer theViewportWidth,
280                                      const Standard_Integer theViewportHeight,
281                                      Bnd_Box& theBoundingBox) const
282 {
283   T aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
284
285   theBoundingBox.Get (aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
286
287   typename BVH_Box<T, 4>::BVH_VecNt aMin (aXmin, aYmin, aZmin, static_cast<T> (1.0));
288   typename BVH_Box<T, 4>::BVH_VecNt aMax (aXmax, aYmax, aZmax, static_cast<T> (1.0));
289   BVH_Box<T, 4> aBBox (aMin, aMax);
290
291   Apply (theProjection, theWorldView, theViewportWidth, theViewportHeight, aBBox);
292
293   theBoundingBox = Bnd_Box();
294   theBoundingBox.Update (aBBox.CornerMin().x(), aBBox.CornerMin().y(), aBBox.CornerMin().z(),
295                          aBBox.CornerMax().x(), aBBox.CornerMax().y(), aBBox.CornerMax().z());
296 }
297
298 // =======================================================================
299 // function : Apply
300 // purpose  : Apply transformation to bounding box of presentation.
301 // =======================================================================
302 template<class T>
303 void Graphic3d_TransformPers::Apply (const NCollection_Mat4<T>& theProjection,
304                                      const NCollection_Mat4<T>& theWorldView,
305                                      const Standard_Integer theViewportWidth,
306                                      const Standard_Integer theViewportHeight,
307                                      BVH_Box<T, 4>& theBoundingBox) const
308 {
309   NCollection_Mat4<T> aTPers = Compute (theProjection, theWorldView, theViewportWidth, theViewportHeight);
310
311   if (aTPers.IsIdentity())
312   {
313     return;
314   }
315
316   const typename BVH_Box<T, 4>::BVH_VecNt& aMin = theBoundingBox.CornerMin();
317   const typename BVH_Box<T, 4>::BVH_VecNt& aMax = theBoundingBox.CornerMax();
318
319   typename BVH_Box<T, 4>::BVH_VecNt anArrayOfCorners[8];
320   anArrayOfCorners[0] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMin.z(), static_cast<T> (1.0));
321   anArrayOfCorners[1] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMax.z(), static_cast<T> (1.0));
322   anArrayOfCorners[2] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMin.z(), static_cast<T> (1.0));
323   anArrayOfCorners[3] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMax.z(), static_cast<T> (1.0));
324   anArrayOfCorners[4] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMin.z(), static_cast<T> (1.0));
325   anArrayOfCorners[5] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMax.z(), static_cast<T> (1.0));
326   anArrayOfCorners[6] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMin.z(), static_cast<T> (1.0));
327   anArrayOfCorners[7] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMax.z(), static_cast<T> (1.0));
328
329   theBoundingBox.Clear();
330   for (Standard_Integer anIt = 0; anIt < 8; ++anIt)
331   {
332     typename BVH_Box<T, 4>::BVH_VecNt& aCorner = anArrayOfCorners[anIt];
333     aCorner  = aTPers * aCorner;
334     aCorner /= aCorner.w();
335     theBoundingBox.Add (aCorner);
336   }
337 }
338
339 // =======================================================================
340 // function : Compute
341 // purpose  : Compute transformation.
342 // =======================================================================
343 template<class T>
344 NCollection_Mat4<T> Graphic3d_TransformPers::Compute (const NCollection_Mat4<T>& theProjection,
345                                                       const NCollection_Mat4<T>& theWorldView,
346                                                       const Standard_Integer theViewportWidth,
347                                                       const Standard_Integer theViewportHeight) const
348 {
349   if (Flags == Graphic3d_TMF_None)
350   {
351     return NCollection_Mat4<T>();
352   }
353
354   NCollection_Mat4<T> anUnviewMat;
355
356   if (!(theProjection * theWorldView).Inverted (anUnviewMat))
357   {
358     return NCollection_Mat4<T>();
359   }
360
361   NCollection_Mat4<T> aProjection (theProjection);
362   NCollection_Mat4<T> aWorldView (theWorldView);
363
364   Apply (aProjection, aWorldView, theViewportWidth, theViewportHeight);
365
366   return anUnviewMat * (aProjection * aWorldView);
367 }
368
369 #endif // _Graphic3d_TransformPers_HeaderFile