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