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