0027919: Visualization - support multiple transformation persistence groups within...
[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 <Aspect_TypeOfTriedronPosition.hxx>
20 #include <Bnd_Box.hxx>
21 #include <BVH_Box.hxx>
22 #include <Graphic3d_Camera.hxx>
23 #include <Graphic3d_TransformUtils.hxx>
24 #include <Graphic3d_TransModeFlags.hxx>
25 #include <Graphic3d_Vec.hxx>
26 #include <NCollection_Mat4.hxx>
27
28 DEFINE_STANDARD_HANDLE(Graphic3d_TransformPers, Standard_Transient)
29
30 //! Transformation Persistence definition.
31 //!
32 //! Transformation Persistence defines a mutable Local Coordinate system which depends on camera position,
33 //! so that visual appearance of the object becomes partially immutable while camera moves.
34 //! Object visually preserves particular property such as size, placement, rotation or their combination.
35 //!
36 //! Graphic3d_TMF_ZoomPers, Graphic3d_TMF_RotatePers and Graphic3d_TMF_ZoomRotatePers define Local Coordinate system
37 //! having origin in specified anchor point defined in World Coordinate system,
38 //! while Graphic3d_TMF_TriedronPers and Graphic3d_TMF_2d define origin as 2D offset from screen corner in pixels.
39 //!
40 //! Graphic3d_TMF_2d, Graphic3d_TMF_TriedronPers and Graphic3d_TMF_ZoomPers defines Local Coordinate system where length units are pixels.
41 //! Beware that Graphic3d_RenderingParams::ResolutionRatio() will be ignored!
42 //! For other Persistence flags, normal (world) length units will apply.
43 //!
44 //! WARNING: Graphic3d_TMF_None is not permitted for defining instance of this class - NULL handle should be used for this purpose!
45 class Graphic3d_TransformPers : public Standard_Transient
46 {
47   DEFINE_STANDARD_RTTIEXT(Graphic3d_TransformPers, Standard_Transient)
48 public:
49
50   //! Return true if specified mode is zoom/rotate transformation persistence.
51   static Standard_Boolean IsZoomOrRotate (Graphic3d_TransModeFlags theMode)
52   {
53     return (theMode & (Graphic3d_TMF_ZoomPers | Graphic3d_TMF_RotatePers)) != 0;
54   }
55
56   //! Return true if specified mode is 2d/trihedron transformation persistence.
57   static Standard_Boolean IsTrihedronOr2d (Graphic3d_TransModeFlags theMode)
58   {
59     return (theMode & (Graphic3d_TMF_TriedronPers | Graphic3d_TMF_2d)) != 0;
60   }
61
62 public:
63
64   //! Set transformation persistence.
65   Graphic3d_TransformPers (const Graphic3d_TransModeFlags theMode)
66   : myMode (theMode)
67   {
68     if (IsZoomOrRotate (theMode))
69     {
70       SetPersistence (theMode, gp_Pnt(0.0, 0.0, 0.0));
71     }
72     else if (IsTrihedronOr2d (theMode))
73     {
74       SetPersistence (theMode, Aspect_TOTP_LEFT_LOWER, Graphic3d_Vec2i (0, 0));
75     }
76     else if (theMode == Graphic3d_TMF_CameraPers)
77     {
78       myMode = theMode;
79     }
80     else
81     {
82       throw Standard_ProgramError("Graphic3d_TransformPers::SetPersistence(), wrong persistence mode.");
83     }
84   }
85
86   //! Set Zoom/Rotate transformation persistence with an anchor 3D point.
87   //! Anchor point defines the origin of Local Coordinate system within World Coordinate system.
88   //! Throws an exception if persistence mode is not Graphic3d_TMF_ZoomPers, Graphic3d_TMF_ZoomRotatePers or Graphic3d_TMF_RotatePers.
89   Graphic3d_TransformPers (const Graphic3d_TransModeFlags theMode,
90                            const gp_Pnt& thePnt)
91   : myMode (Graphic3d_TMF_None)
92   {
93     SetPersistence (theMode, thePnt);
94   }
95
96   //! Set 2d/trihedron transformation persistence with a corner and 2D offset.
97   //! 2D offset defines the origin of Local Coordinate system as projection of 2D point on screen plane into World Coordinate system.
98   //! Throws an exception if persistence mode is not Graphic3d_TMF_TriedronPers or Graphic3d_TMF_2d.
99   //! The offset is a positive displacement from the view corner in pixels.
100   Graphic3d_TransformPers (const Graphic3d_TransModeFlags theMode,
101                            const Aspect_TypeOfTriedronPosition theCorner,
102                            const Graphic3d_Vec2i& theOffset = Graphic3d_Vec2i (0, 0))
103   : myMode (Graphic3d_TMF_None)
104   {
105     SetPersistence (theMode, theCorner, theOffset);
106   }
107
108   //! Return true for Graphic3d_TMF_ZoomPers, Graphic3d_TMF_ZoomRotatePers or Graphic3d_TMF_RotatePers modes.
109   Standard_Boolean IsZoomOrRotate() const { return IsZoomOrRotate (myMode); }
110
111   //! Return true for Graphic3d_TMF_TriedronPers and Graphic3d_TMF_2d modes.
112   Standard_Boolean IsTrihedronOr2d() const { return IsTrihedronOr2d (myMode); }
113
114   //! Transformation persistence mode flags.
115   Graphic3d_TransModeFlags Mode() const { return myMode; }
116
117   //! Transformation persistence mode flags.
118   Graphic3d_TransModeFlags Flags() const { return myMode; }
119
120   //! Set Zoom/Rotate transformation persistence with an anchor 3D point.
121   //! Throws an exception if persistence mode is not Graphic3d_TMF_ZoomPers, Graphic3d_TMF_ZoomRotatePers or Graphic3d_TMF_RotatePers.
122   void SetPersistence (const Graphic3d_TransModeFlags theMode,
123                        const gp_Pnt& thePnt)
124   {
125     if (!IsZoomOrRotate (theMode))
126     {
127       throw Standard_ProgramError("Graphic3d_TransformPers::SetPersistence(), wrong persistence mode.");
128     }
129
130     myMode = theMode;
131     myParams.Params3d.PntX = thePnt.X();
132     myParams.Params3d.PntY = thePnt.Y();
133     myParams.Params3d.PntZ = thePnt.Z();
134   }
135
136   //! Set 2d/trihedron transformation persistence with a corner and 2D offset.
137   //! Throws an exception if persistence mode is not Graphic3d_TMF_TriedronPers or Graphic3d_TMF_2d.
138   void SetPersistence (const Graphic3d_TransModeFlags theMode,
139                        const Aspect_TypeOfTriedronPosition theCorner,
140                        const Graphic3d_Vec2i& theOffset)
141   {
142     if (!IsTrihedronOr2d (theMode))
143     {
144       throw Standard_ProgramError("Graphic3d_TransformPers::SetPersistence(), wrong persistence mode.");
145     }
146
147     myMode = theMode;
148     myParams.Params2d.Corner  = theCorner;
149     myParams.Params2d.OffsetX = theOffset.x();
150     myParams.Params2d.OffsetY = theOffset.y();
151   }
152
153 public:
154
155   //! Return the anchor point for zoom/rotate transformation persistence.
156   gp_Pnt AnchorPoint() const
157   {
158     if (!IsZoomOrRotate())
159     {
160       throw Standard_ProgramError("Graphic3d_TransformPers::AnchorPoint(), wrong persistence mode.");
161     }
162
163     return gp_Pnt (myParams.Params3d.PntX, myParams.Params3d.PntY, myParams.Params3d.PntZ);
164   }
165
166   //! Set the anchor point for zoom/rotate transformation persistence.
167   void SetAnchorPoint (const gp_Pnt& thePnt)
168   {
169     if (!IsZoomOrRotate())
170     {
171       throw Standard_ProgramError("Graphic3d_TransformPers::SetAnchorPoint(), wrong persistence mode.");
172     }
173
174     myParams.Params3d.PntX = thePnt.X();
175     myParams.Params3d.PntY = thePnt.Y();
176     myParams.Params3d.PntZ = thePnt.Z();
177   }
178
179   //! Return the corner for 2d/trihedron transformation persistence.
180   Aspect_TypeOfTriedronPosition Corner2d() const
181   {
182     if (!IsTrihedronOr2d())
183     {
184       throw Standard_ProgramError("Graphic3d_TransformPers::Corner2d(), wrong persistence mode.");
185     }
186
187     return myParams.Params2d.Corner;
188   }
189
190   //! Set the corner for 2d/trihedron transformation persistence.
191   void SetCorner2d (const Aspect_TypeOfTriedronPosition thePos)
192   {
193     if (!IsTrihedronOr2d())
194     {
195       throw Standard_ProgramError("Graphic3d_TransformPers::SetCorner2d(), wrong persistence mode.");
196     }
197
198     myParams.Params2d.Corner = thePos;
199   }
200
201   //! Return the offset from the corner for 2d/trihedron transformation persistence.
202   Graphic3d_Vec2i Offset2d() const
203   {
204     if (!IsTrihedronOr2d())
205     {
206       throw Standard_ProgramError("Graphic3d_TransformPers::Offset2d(), wrong persistence mode.");
207     }
208
209     return Graphic3d_Vec2i (myParams.Params2d.OffsetX, myParams.Params2d.OffsetY);
210   }
211
212   //! Set the offset from the corner for 2d/trihedron transformation persistence.
213   void SetOffset2d (const Graphic3d_Vec2i& theOffset)
214   {
215     if (!IsTrihedronOr2d())
216     {
217       throw Standard_ProgramError("Graphic3d_TransformPers::SetOffset2d(), wrong persistence mode.");
218     }
219
220     myParams.Params2d.OffsetX = theOffset.x();
221     myParams.Params2d.OffsetY = theOffset.y();
222   }
223
224 public:
225
226   //! Find scale value based on the camera position and view dimensions
227   //! @param theCamera [in] camera definition
228   //! @param theViewportWidth [in] the width of viewport.
229   //! @param theViewportHeight [in] the height of viewport.
230   virtual Standard_Real persistentScale (const Handle(Graphic3d_Camera)& theCamera,
231                                          const Standard_Integer /*theViewportWidth*/,
232                                          const Standard_Integer theViewportHeight) const
233   {
234     // use total size when tiling is active
235     const Standard_Integer aVPSizeY = theCamera->Tile().IsValid() ? theCamera->Tile().TotalSize.y() : theViewportHeight;
236
237     gp_Vec aVecToEye (theCamera->Direction());
238     gp_Vec aVecToObj (theCamera->Eye(), gp_Pnt (myParams.Params3d.PntX, myParams.Params3d.PntY, myParams.Params3d.PntZ));
239     const Standard_Real aFocus = aVecToObj.Dot (aVecToEye);
240     const gp_XYZ aViewDim = theCamera->ViewDimensions (aFocus);
241     return Abs(aViewDim.Y()) / Standard_Real(aVPSizeY);
242   }
243
244   //! Apply transformation to bounding box of presentation.
245   //! @param theCamera [in] camera definition
246   //! @param theProjection [in] the projection transformation matrix.
247   //! @param theWorldView [in] the world view transformation matrix.
248   //! @param theViewportWidth [in] the width of viewport (for 2d persistence).
249   //! @param theViewportHeight [in] the height of viewport (for 2d persistence).
250   //! @param theBoundingBox [in/out] the bounding box to transform.
251   template<class T>
252   void Apply (const Handle(Graphic3d_Camera)& theCamera,
253               const NCollection_Mat4<T>& theProjection,
254               const NCollection_Mat4<T>& theWorldView,
255               const Standard_Integer theViewportWidth,
256               const Standard_Integer theViewportHeight,
257               Bnd_Box& theBoundingBox) const;
258
259   //! Apply transformation to bounding box of presentation
260   //! @param theCamera [in] camera definition
261   //! @param theProjection [in] the projection transformation matrix.
262   //! @param theWorldView [in] the world view transformation matrix.
263   //! @param theViewportWidth [in] the width of viewport (for 2d persistence).
264   //! @param theViewportHeight [in] the height of viewport (for 2d persistence).
265   //! @param theBoundingBox [in/out] the bounding box to transform.
266   template<class T>
267   void Apply (const Handle(Graphic3d_Camera)& theCamera,
268               const NCollection_Mat4<T>& theProjection,
269               const NCollection_Mat4<T>& theWorldView,
270               const Standard_Integer theViewportWidth,
271               const Standard_Integer theViewportHeight,
272               BVH_Box<T, 3>& theBoundingBox) const;
273
274   //! Compute transformation.
275   //! Computed matrix can be applied to model world transformation
276   //! of an object to implement effect of transformation persistence.
277   //! @param theCamera [in] camera definition
278   //! @param theProjection [in] the projection transformation matrix.
279   //! @param theWorldView [in] the world view transformation matrix.
280   //! @param theViewportWidth [in] the width of viewport (for 2d persistence).
281   //! @param theViewportHeight [in] the height of viewport (for 2d persistence).
282   //! @return transformation matrix to be applied to model world transformation of an object.
283   template<class T>
284   NCollection_Mat4<T> Compute (const Handle(Graphic3d_Camera)& theCamera,
285                                const NCollection_Mat4<T>& theProjection,
286                                const NCollection_Mat4<T>& theWorldView,
287                                const Standard_Integer theViewportWidth,
288                                const Standard_Integer theViewportHeight) const;
289
290   //! Apply transformation persistence on specified matrices.
291   //! @param theCamera camera definition
292   //! @param theProjection projection matrix to modify
293   //! @param theWorldView  world-view matrix to modify
294   //! @param theViewportWidth  viewport width
295   //! @param theViewportHeight viewport height
296   //! @param theAnchor if not NULL, overrides anchor point
297   template<class T>
298   void Apply (const Handle(Graphic3d_Camera)& theCamera,
299               const NCollection_Mat4<T>& theProjection,
300               NCollection_Mat4<T>& theWorldView,
301               const Standard_Integer theViewportWidth,
302               const Standard_Integer theViewportHeight,
303               const gp_Pnt* theAnchor = NULL) const;
304
305   //! Dumps the content of me into the stream
306   Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
307
308 private:
309
310   //! 3D anchor point for zoom/rotate transformation persistence.
311   struct PersParams3d
312   {
313     Standard_Real PntX;
314     Standard_Real PntY;
315     Standard_Real PntZ;
316
317     //! Dumps the content of me into the stream
318     Standard_EXPORT void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
319   };
320
321   //! 2d/trihedron transformation persistence parameters.
322   struct PersParams2d
323   {
324     Standard_Integer OffsetX;
325     Standard_Integer OffsetY;
326     Aspect_TypeOfTriedronPosition Corner;
327
328     //! Dumps the content of me into the stream
329     Standard_EXPORT void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
330   };
331
332 private:
333
334   Graphic3d_TransModeFlags myMode;  //!< Transformation persistence mode flags
335   union
336   {
337     PersParams3d Params3d;
338     PersParams2d Params2d;
339   } myParams;
340
341 };
342
343 // =======================================================================
344 // function : Apply
345 // purpose  : Apply transformation to world view and projection matrices.
346 // =======================================================================
347 template<class T>
348 void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
349                                      const NCollection_Mat4<T>& theProjection,
350                                      NCollection_Mat4<T>& theWorldView,
351                                      const Standard_Integer theViewportWidth,
352                                      const Standard_Integer theViewportHeight,
353                                      const gp_Pnt* theAnchor) const
354 {
355   (void )theViewportWidth;
356   (void )theProjection;
357   if (myMode == Graphic3d_TMF_None
358    || theViewportHeight == 0)
359   {
360     return;
361   }
362
363   // use total size when tiling is active
364   const Standard_Integer aVPSizeY = theCamera->Tile().IsValid() ? theCamera->Tile().TotalSize.y() : theViewportHeight;
365
366   // a small enough jitter compensation offset
367   // to avoid image dragging within single pixel in corner cases
368   const Standard_Real aJitterComp = 0.001;
369   if (myMode == Graphic3d_TMF_TriedronPers)
370   {
371     // reset Z focus for trihedron persistence
372     const Standard_Real aFocus = theCamera->IsOrthographic()
373                                ? theCamera->Distance()
374                                : (theCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative
375                                 ? Standard_Real(theCamera->ZFocus() * theCamera->Distance())
376                                 : Standard_Real(theCamera->ZFocus()));
377
378     // scale factor to pixels
379     const gp_XYZ aViewDim = theCamera->ViewDimensions (aFocus);
380     const Standard_Real aScale = Abs(aViewDim.Y()) / Standard_Real(aVPSizeY);
381     const gp_Dir aForward = theCamera->Direction();
382     gp_XYZ aCenter = theCamera->Center().XYZ() + aForward.XYZ() * (aFocus - theCamera->Distance());
383     if ((myParams.Params2d.Corner & (Aspect_TOTP_LEFT | Aspect_TOTP_RIGHT)) != 0)
384     {
385       const Standard_Real anOffsetX = (Standard_Real(myParams.Params2d.OffsetX) + aJitterComp) * aScale;
386       const gp_Dir aSide   = aForward.Crossed (theCamera->Up());
387       const gp_XYZ aDeltaX = aSide.XYZ() * (Abs(aViewDim.X()) * theCamera->NDC2dOffsetX() - anOffsetX);
388       if ((myParams.Params2d.Corner & Aspect_TOTP_RIGHT) != 0)
389       {
390         aCenter += aDeltaX;
391       }
392       else
393       {
394         aCenter -= aDeltaX;
395       }
396     }
397     if ((myParams.Params2d.Corner & (Aspect_TOTP_TOP | Aspect_TOTP_BOTTOM)) != 0)
398     {
399       const Standard_Real anOffsetY = (Standard_Real(myParams.Params2d.OffsetY) + aJitterComp) * aScale;
400       const gp_XYZ aDeltaY = theCamera->Up().XYZ() * (Abs(aViewDim.Y()) * theCamera->NDC2dOffsetY() - anOffsetY);
401       if ((myParams.Params2d.Corner & Aspect_TOTP_TOP) != 0)
402       {
403         aCenter += aDeltaY;
404       }
405       else
406       {
407         aCenter -= aDeltaY;
408       }
409     }
410
411     NCollection_Mat4<Standard_Real> aWorldView = theCamera->OrientationMatrix();
412     Graphic3d_TransformUtils::Translate (aWorldView, aCenter.X(), aCenter.Y(), aCenter.Z());
413     Graphic3d_TransformUtils::Scale     (aWorldView, aScale,      aScale,      aScale);
414     theWorldView.ConvertFrom (aWorldView);
415     return;
416   }
417   else if (myMode == Graphic3d_TMF_2d)
418   {
419     const Standard_Real aFocus = theCamera->IsOrthographic()
420                                ? theCamera->Distance()
421                                : (theCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative
422                                 ? Standard_Real(theCamera->ZFocus() * theCamera->Distance())
423                                 : Standard_Real(theCamera->ZFocus()));
424
425     // scale factor to pixels
426     const gp_XYZ        aViewDim = theCamera->ViewDimensions (aFocus);
427     const Standard_Real aScale   = Abs(aViewDim.Y()) / Standard_Real(aVPSizeY);
428     gp_XYZ aCenter (0.0, 0.0, -aFocus);
429     if ((myParams.Params2d.Corner & (Aspect_TOTP_LEFT | Aspect_TOTP_RIGHT)) != 0)
430     {
431       aCenter.SetX (-aViewDim.X() * theCamera->NDC2dOffsetX() + (Standard_Real(myParams.Params2d.OffsetX) + aJitterComp) * aScale);
432       if ((myParams.Params2d.Corner & Aspect_TOTP_RIGHT) != 0)
433       {
434         aCenter.SetX (-aCenter.X());
435       }
436     }
437     if ((myParams.Params2d.Corner & (Aspect_TOTP_TOP | Aspect_TOTP_BOTTOM)) != 0)
438     {
439       aCenter.SetY (-aViewDim.Y() * theCamera->NDC2dOffsetY() + (Standard_Real(myParams.Params2d.OffsetY) + aJitterComp) * aScale);
440       if ((myParams.Params2d.Corner & Aspect_TOTP_TOP) != 0)
441       {
442         aCenter.SetY (-aCenter.Y());
443       }
444     }
445
446     theWorldView.InitIdentity();
447     Graphic3d_TransformUtils::Translate (theWorldView, T(aCenter.X()), T(aCenter.Y()), T(aCenter.Z()));
448     Graphic3d_TransformUtils::Scale     (theWorldView, T(aScale),      T(aScale),      T(aScale));
449     return;
450   }
451   else if ((myMode & Graphic3d_TMF_CameraPers) != 0)
452   {
453     theWorldView.InitIdentity();
454   }
455   else
456   {
457     // Compute reference point for transformation in untransformed projection space.
458     NCollection_Mat4<Standard_Real> aWorldView = theCamera->OrientationMatrix();
459     if (theAnchor != NULL)
460     {
461       Graphic3d_TransformUtils::Translate (aWorldView, theAnchor->X(), theAnchor->Y(), theAnchor->Z());
462     }
463     else
464     {
465       Graphic3d_TransformUtils::Translate (aWorldView, myParams.Params3d.PntX, myParams.Params3d.PntY, myParams.Params3d.PntZ);
466     }
467
468     if ((myMode & Graphic3d_TMF_RotatePers) != 0)
469     {
470       // lock rotation by nullifying rotation component
471       aWorldView.SetValue (0, 0, 1.0);
472       aWorldView.SetValue (1, 0, 0.0);
473       aWorldView.SetValue (2, 0, 0.0);
474
475       aWorldView.SetValue (0, 1, 0.0);
476       aWorldView.SetValue (1, 1, 1.0);
477       aWorldView.SetValue (2, 1, 0.0);
478
479       aWorldView.SetValue (0, 2, 0.0);
480       aWorldView.SetValue (1, 2, 0.0);
481       aWorldView.SetValue (2, 2, 1.0);
482     }
483
484     if ((myMode & Graphic3d_TMF_ZoomPers) != 0)
485     {
486       // lock zooming
487       Standard_Real aScale = persistentScale (theCamera, theViewportWidth, theViewportHeight);
488       Graphic3d_TransformUtils::Scale (aWorldView, aScale, aScale, aScale);
489     }
490     theWorldView.ConvertFrom (aWorldView);
491     return;
492   }
493 }
494
495 // =======================================================================
496 // function : Apply
497 // purpose  : Apply transformation to bounding box of presentation.
498 // =======================================================================
499 template<class T>
500 void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
501                                      const NCollection_Mat4<T>& theProjection,
502                                      const NCollection_Mat4<T>& theWorldView,
503                                      const Standard_Integer theViewportWidth,
504                                      const Standard_Integer theViewportHeight,
505                                      Bnd_Box& theBoundingBox) const
506 {
507   if (theBoundingBox.IsVoid())
508   {
509     return;
510   }
511
512   T aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
513
514   theBoundingBox.Get (aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
515
516   typename BVH_Box<T, 3>::BVH_VecNt aMin (aXmin, aYmin, aZmin);
517   typename BVH_Box<T, 3>::BVH_VecNt aMax (aXmax, aYmax, aZmax);
518   BVH_Box<T, 3> aBBox (aMin, aMax);
519
520   Apply (theCamera, theProjection, theWorldView, theViewportWidth, theViewportHeight, aBBox);
521
522   theBoundingBox = Bnd_Box();
523   theBoundingBox.Update (aBBox.CornerMin().x(), aBBox.CornerMin().y(), aBBox.CornerMin().z(),
524                          aBBox.CornerMax().x(), aBBox.CornerMax().y(), aBBox.CornerMax().z());
525 }
526
527 // =======================================================================
528 // function : Apply
529 // purpose  : Apply transformation to bounding box of presentation.
530 // =======================================================================
531 template<class T>
532 void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
533                                      const NCollection_Mat4<T>& theProjection,
534                                      const NCollection_Mat4<T>& theWorldView,
535                                      const Standard_Integer theViewportWidth,
536                                      const Standard_Integer theViewportHeight,
537                                      BVH_Box<T, 3>& theBoundingBox) const
538 {
539   NCollection_Mat4<T> aTPers = Compute (theCamera, theProjection, theWorldView, theViewportWidth, theViewportHeight);
540   if (aTPers.IsIdentity()
541   || !theBoundingBox.IsValid())
542   {
543     return;
544   }
545
546   const typename BVH_Box<T, 3>::BVH_VecNt& aMin = theBoundingBox.CornerMin();
547   const typename BVH_Box<T, 3>::BVH_VecNt& aMax = theBoundingBox.CornerMax();
548
549   typename BVH_Box<T, 4>::BVH_VecNt anArrayOfCorners[8];
550   anArrayOfCorners[0] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMin.z(), static_cast<T> (1.0));
551   anArrayOfCorners[1] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMax.z(), static_cast<T> (1.0));
552   anArrayOfCorners[2] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMin.z(), static_cast<T> (1.0));
553   anArrayOfCorners[3] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMax.z(), static_cast<T> (1.0));
554   anArrayOfCorners[4] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMin.z(), static_cast<T> (1.0));
555   anArrayOfCorners[5] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMax.z(), static_cast<T> (1.0));
556   anArrayOfCorners[6] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMin.z(), static_cast<T> (1.0));
557   anArrayOfCorners[7] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMax.z(), static_cast<T> (1.0));
558
559   theBoundingBox.Clear();
560   for (Standard_Integer anIt = 0; anIt < 8; ++anIt)
561   {
562     typename BVH_Box<T, 4>::BVH_VecNt& aCorner = anArrayOfCorners[anIt];
563     aCorner  = aTPers * aCorner;
564     aCorner = aCorner / aCorner.w();
565     theBoundingBox.Add (typename BVH_Box<T, 3>::BVH_VecNt (aCorner.x(), aCorner.y(), aCorner.z()));
566   }
567 }
568
569 // =======================================================================
570 // function : Compute
571 // purpose  : Compute transformation.
572 // =======================================================================
573 template<class T>
574 NCollection_Mat4<T> Graphic3d_TransformPers::Compute (const Handle(Graphic3d_Camera)& theCamera,
575                                                       const NCollection_Mat4<T>& theProjection,
576                                                       const NCollection_Mat4<T>& theWorldView,
577                                                       const Standard_Integer theViewportWidth,
578                                                       const Standard_Integer theViewportHeight) const
579 {
580   if (myMode == Graphic3d_TMF_None)
581   {
582     return NCollection_Mat4<T>();
583   }
584
585   NCollection_Mat4<T> aWorldView (theWorldView);
586   NCollection_Mat4<T> anUnviewMat;
587   if (!theWorldView.Inverted (anUnviewMat))
588   {
589     return NCollection_Mat4<T>();
590   }
591
592   // compute only world-view matrix difference to avoid floating point instability
593   // caused by projection matrix modifications outside of this algorithm (e.g. by Z-fit)
594   Apply (theCamera, theProjection, aWorldView, theViewportWidth, theViewportHeight);
595   return anUnviewMat * aWorldView;
596 }
597
598 #endif // _Graphic3d_TransformPers_HeaderFile