]> OCCT Git - occt.git/commitdiff
0033551: Visualization - Add new transform persistence mode to force orthographic... IR-2023-12-22
authorrodrlyra <rodrlyra@opencascade.com>
Mon, 11 Dec 2023 16:37:36 +0000 (16:37 +0000)
committerrodrlyra <rodrlyra@opencascade.com>
Fri, 5 Jan 2024 18:36:54 +0000 (18:36 +0000)
The new transform persistence mode, with flag `Graphic3d_TMF_OrthoPers`, can be combined (bitwise OR operation) with the other persistence modes (2D, Trihedron or Zoom/Rotate Persistence) to make objects be rendered with orthographic projection when it is on a view with perspective projection.

If the view already uses orthographic projection, there will be no difference.

This feature was implemented to fix ViewCube being distorted when view with perspective projection changes size.

20 files changed:
src/Graphic3d/Graphic3d_TransModeFlags.hxx
src/Graphic3d/Graphic3d_TransformPers.hxx
src/SelectMgr/SelectMgr_AxisIntersector.cxx
src/SelectMgr/SelectMgr_AxisIntersector.hxx
src/SelectMgr/SelectMgr_BaseIntersector.hxx
src/SelectMgr/SelectMgr_RectangularFrustum.cxx
src/SelectMgr/SelectMgr_RectangularFrustum.hxx
src/SelectMgr/SelectMgr_SelectableObjectSet.cxx
src/SelectMgr/SelectMgr_SelectableObjectSet.hxx
src/SelectMgr/SelectMgr_SelectingVolumeManager.cxx
src/SelectMgr/SelectMgr_SelectingVolumeManager.hxx
src/SelectMgr/SelectMgr_TriangularFrustum.cxx
src/SelectMgr/SelectMgr_TriangularFrustum.hxx
src/SelectMgr/SelectMgr_TriangularFrustumSet.cxx
src/SelectMgr/SelectMgr_TriangularFrustumSet.hxx
src/SelectMgr/SelectMgr_ViewerSelector.cxx
src/SelectMgr/SelectMgr_ViewerSelector.hxx
src/ViewerTest/ViewerTest.cxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
tests/v3d/viewcube/orthopers [new file with mode: 0644]

index 2246541d8f1f69c50d7e16c3d5939b7998572afb..0c9f329362ee0720b99ba1eb753746365490811d 100644 (file)
@@ -25,8 +25,15 @@ enum Graphic3d_TransModeFlags
   Graphic3d_TMF_TriedronPers   = 0x0020,                  //!< object behaves like trihedron - it is fixed at the corner of view and does not resizing (but rotating)
   Graphic3d_TMF_2d             = 0x0040,                  //!< object is defined in 2D screen coordinates (pixels) and does not resize, pan and rotate
   Graphic3d_TMF_CameraPers     = 0x0080,                  //!< object is in front of the camera
+  Graphic3d_TMF_OrthoPers      = 0x0100,                  //!< object is forced to be rendered with orthographic projection.
   Graphic3d_TMF_ZoomRotatePers = Graphic3d_TMF_ZoomPers
                                | Graphic3d_TMF_RotatePers //!< object doesn't resize and rotate
 };
 
+//! Bitwise OR operator for transform persistence mode flags. Be aware that some flags combinations are not valid.
+inline Graphic3d_TransModeFlags operator| (Graphic3d_TransModeFlags a, Graphic3d_TransModeFlags b)
+{
+  return static_cast<Graphic3d_TransModeFlags> (static_cast<uint32_t> (a) | static_cast<uint32_t> (b));
+}
+
 #endif
index f9d9b60940b452d8ae38d30fbe3fce725742a92f..d0f70ba64c2d55af14f495b4e598e06171fec968 100644 (file)
@@ -58,6 +58,12 @@ public:
     return (theMode & (Graphic3d_TMF_TriedronPers | Graphic3d_TMF_2d)) != 0;
   }
 
+  //! Return true if specified mode is orthographic projection transformation persistence.
+  static Standard_Boolean IsOrthoPers (Graphic3d_TransModeFlags theMode)
+  {
+    return (theMode & Graphic3d_TMF_OrthoPers) != 0;
+  }
+
 public:
 
   //! Set transformation persistence.
@@ -110,6 +116,9 @@ public:
   //! Return true for Graphic3d_TMF_TriedronPers and Graphic3d_TMF_2d modes.
   Standard_Boolean IsTrihedronOr2d() const { return IsTrihedronOr2d (myMode); }
 
+  //! Return true for Graphic3d_TMF_OrthoPers mode.
+  Standard_Boolean IsOrthoPers () const { return IsOrthoPers (myMode); }
+
   //! Transformation persistence mode flags.
   Graphic3d_TransModeFlags Mode() const { return myMode; }
 
@@ -297,28 +306,32 @@ public:
   //! @param theWorldView [in] the world view transformation matrix.
   //! @param theViewportWidth [in] the width of viewport (for 2d persistence).
   //! @param theViewportHeight [in] the height of viewport (for 2d persistence).
+  //! @param theToApplyProjPers [in] if should apply projection persistence to matrix (for orthographic persistence).
   //! @return transformation matrix to be applied to model world transformation of an object.
   template<class T>
   NCollection_Mat4<T> Compute (const Handle(Graphic3d_Camera)& theCamera,
                                const NCollection_Mat4<T>& theProjection,
                                const NCollection_Mat4<T>& theWorldView,
                                const Standard_Integer theViewportWidth,
-                               const Standard_Integer theViewportHeight) const;
+                               const Standard_Integer theViewportHeight,
+                               const Standard_Boolean theToApplyProjPers = false) const;
 
   //! Apply transformation persistence on specified matrices.
-  //! @param theCamera camera definition
-  //! @param theProjection projection matrix to modify
-  //! @param theWorldView  world-view matrix to modify
-  //! @param theViewportWidth  viewport width
-  //! @param theViewportHeight viewport height
-  //! @param theAnchor if not NULL, overrides anchor point
+  //! @param theCamera [in] camera definition
+  //! @param theProjection [in] projection matrix to modify
+  //! @param theWorldView [in/out]  world-view matrix to modify
+  //! @param theViewportWidth [in]  viewport width
+  //! @param theViewportHeight [in] viewport height
+  //! @param theAnchor [in] if not NULL, overrides anchor point
+  //! @param theToApplyProjPers [in] if should apply projection persistence to matrix (for orthographic persistence).
   template<class T>
   void Apply (const Handle(Graphic3d_Camera)& theCamera,
               const NCollection_Mat4<T>& theProjection,
               NCollection_Mat4<T>& theWorldView,
               const Standard_Integer theViewportWidth,
               const Standard_Integer theViewportHeight,
-              const gp_Pnt* theAnchor = NULL) const;
+              const gp_Pnt* theAnchor = NULL,
+              const Standard_Boolean theToApplyProjPers = true) const;
 
   //! Dumps the content of me into the stream
   Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
@@ -368,41 +381,50 @@ void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
                                      NCollection_Mat4<T>& theWorldView,
                                      const Standard_Integer theViewportWidth,
                                      const Standard_Integer theViewportHeight,
-                                     const gp_Pnt* theAnchor) const
+                                     const gp_Pnt* theAnchor,
+                                     const Standard_Boolean theToApplyProjPers) const
 {
   (void )theViewportWidth;
-  (void )theProjection;
   if (myMode == Graphic3d_TMF_None
    || theViewportHeight == 0)
   {
     return;
   }
 
+  Handle(Graphic3d_Camera) aCamera = theCamera;
+  if (IsOrthoPers() && !aCamera->IsOrthographic())
+  {
+    aCamera = new Graphic3d_Camera(*theCamera); // If OrthoPers, copy camera and set to orthographic projection
+    aCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
+  }
+
+  NCollection_Mat4<Standard_Real> aWorldView = aCamera->OrientationMatrix();
+
   // use total size when tiling is active
-  const Standard_Integer aVPSizeY = theCamera->Tile().IsValid() ? theCamera->Tile().TotalSize.y() : theViewportHeight;
+  const Standard_Integer aVPSizeY = aCamera->Tile().IsValid() ? aCamera->Tile().TotalSize.y() : theViewportHeight;
 
   // a small enough jitter compensation offset
   // to avoid image dragging within single pixel in corner cases
   const Standard_Real aJitterComp = 0.001;
-  if (myMode == Graphic3d_TMF_TriedronPers)
+  if ((myMode & Graphic3d_TMF_TriedronPers) != 0)
   {
     // reset Z focus for trihedron persistence
-    const Standard_Real aFocus = theCamera->IsOrthographic()
-                               ? theCamera->Distance()
-                               : (theCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative
-                                ? Standard_Real(theCamera->ZFocus() * theCamera->Distance())
-                                : Standard_Real(theCamera->ZFocus()));
+    const Standard_Real aFocus = aCamera->IsOrthographic()
+                               ? aCamera->Distance()
+                               : (aCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative
+                                ? Standard_Real(aCamera->ZFocus() * aCamera->Distance())
+                                : Standard_Real(aCamera->ZFocus()));
 
     // scale factor to pixels
-    const gp_XYZ aViewDim = theCamera->ViewDimensions (aFocus);
+    const gp_XYZ aViewDim = aCamera->ViewDimensions (aFocus);
     const Standard_Real aScale = Abs(aViewDim.Y()) / Standard_Real(aVPSizeY);
-    const gp_Dir aForward = theCamera->Direction();
-    gp_XYZ aCenter = theCamera->Center().XYZ() + aForward.XYZ() * (aFocus - theCamera->Distance());
+    const gp_Dir aForward = aCamera->Direction();
+    gp_XYZ aCenter = aCamera->Center().XYZ() + aForward.XYZ() * (aFocus - aCamera->Distance());
     if ((myParams.Params2d.Corner & (Aspect_TOTP_LEFT | Aspect_TOTP_RIGHT)) != 0)
     {
       const Standard_Real anOffsetX = (Standard_Real(myParams.Params2d.OffsetX) + aJitterComp) * aScale;
-      const gp_Dir aSide   = aForward.Crossed (theCamera->Up());
-      const gp_XYZ aDeltaX = aSide.XYZ() * (Abs(aViewDim.X()) * theCamera->NDC2dOffsetX() - anOffsetX);
+      const gp_Dir aSide   = aForward.Crossed (aCamera->Up());
+      const gp_XYZ aDeltaX = aSide.XYZ() * (Abs(aViewDim.X()) * aCamera->NDC2dOffsetX() - anOffsetX);
       if ((myParams.Params2d.Corner & Aspect_TOTP_RIGHT) != 0)
       {
         aCenter += aDeltaX;
@@ -415,7 +437,7 @@ void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
     if ((myParams.Params2d.Corner & (Aspect_TOTP_TOP | Aspect_TOTP_BOTTOM)) != 0)
     {
       const Standard_Real anOffsetY = (Standard_Real(myParams.Params2d.OffsetY) + aJitterComp) * aScale;
-      const gp_XYZ aDeltaY = theCamera->Up().XYZ() * (Abs(aViewDim.Y()) * theCamera->NDC2dOffsetY() - anOffsetY);
+      const gp_XYZ aDeltaY = aCamera->Up().XYZ() * (Abs(aViewDim.Y()) * aCamera->NDC2dOffsetY() - anOffsetY);
       if ((myParams.Params2d.Corner & Aspect_TOTP_TOP) != 0)
       {
         aCenter += aDeltaY;
@@ -426,27 +448,24 @@ void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
       }
     }
 
-    NCollection_Mat4<Standard_Real> aWorldView = theCamera->OrientationMatrix();
     Graphic3d_TransformUtils::Translate (aWorldView, aCenter.X(), aCenter.Y(), aCenter.Z());
     Graphic3d_TransformUtils::Scale     (aWorldView, aScale,      aScale,      aScale);
-    theWorldView.ConvertFrom (aWorldView);
-    return;
   }
-  else if (myMode == Graphic3d_TMF_2d)
+  else if ((myMode & Graphic3d_TMF_2d) != 0)
   {
-    const Standard_Real aFocus = theCamera->IsOrthographic()
-                               ? theCamera->Distance()
-                               : (theCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative
-                                ? Standard_Real(theCamera->ZFocus() * theCamera->Distance())
-                                : Standard_Real(theCamera->ZFocus()));
+    const Standard_Real aFocus = aCamera->IsOrthographic()
+                               ? aCamera->Distance()
+                               : (aCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative
+                                ? Standard_Real(aCamera->ZFocus() * aCamera->Distance())
+                                : Standard_Real(aCamera->ZFocus()));
 
     // scale factor to pixels
-    const gp_XYZ        aViewDim = theCamera->ViewDimensions (aFocus);
+    const gp_XYZ        aViewDim = aCamera->ViewDimensions (aFocus);
     const Standard_Real aScale   = Abs(aViewDim.Y()) / Standard_Real(aVPSizeY);
     gp_XYZ aCenter (0.0, 0.0, -aFocus);
     if ((myParams.Params2d.Corner & (Aspect_TOTP_LEFT | Aspect_TOTP_RIGHT)) != 0)
     {
-      aCenter.SetX (-aViewDim.X() * theCamera->NDC2dOffsetX() + (Standard_Real(myParams.Params2d.OffsetX) + aJitterComp) * aScale);
+      aCenter.SetX (-aViewDim.X() * aCamera->NDC2dOffsetX() + (Standard_Real(myParams.Params2d.OffsetX) + aJitterComp) * aScale);
       if ((myParams.Params2d.Corner & Aspect_TOTP_RIGHT) != 0)
       {
         aCenter.SetX (-aCenter.X());
@@ -454,26 +473,24 @@ void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
     }
     if ((myParams.Params2d.Corner & (Aspect_TOTP_TOP | Aspect_TOTP_BOTTOM)) != 0)
     {
-      aCenter.SetY (-aViewDim.Y() * theCamera->NDC2dOffsetY() + (Standard_Real(myParams.Params2d.OffsetY) + aJitterComp) * aScale);
+      aCenter.SetY (-aViewDim.Y() * aCamera->NDC2dOffsetY() + (Standard_Real(myParams.Params2d.OffsetY) + aJitterComp) * aScale);
       if ((myParams.Params2d.Corner & Aspect_TOTP_TOP) != 0)
       {
         aCenter.SetY (-aCenter.Y());
       }
     }
 
-    theWorldView.InitIdentity();
-    Graphic3d_TransformUtils::Translate (theWorldView, T(aCenter.X()), T(aCenter.Y()), T(aCenter.Z()));
-    Graphic3d_TransformUtils::Scale     (theWorldView, T(aScale),      T(aScale),      T(aScale));
-    return;
+    aWorldView.InitIdentity();
+    Graphic3d_TransformUtils::Translate (aWorldView, aCenter.X(), aCenter.Y(), aCenter.Z());
+    Graphic3d_TransformUtils::Scale     (aWorldView, aScale,      aScale,      aScale);
   }
   else if ((myMode & Graphic3d_TMF_CameraPers) != 0)
   {
-    theWorldView.InitIdentity();
+    aWorldView.InitIdentity();
   }
   else
   {
     // Compute reference point for transformation in untransformed projection space.
-    NCollection_Mat4<Standard_Real> aWorldView = theCamera->OrientationMatrix();
     if (theAnchor != NULL)
     {
       Graphic3d_TransformUtils::Translate (aWorldView, theAnchor->X(), theAnchor->Y(), theAnchor->Z());
@@ -503,12 +520,19 @@ void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
     if ((myMode & Graphic3d_TMF_ZoomPers) != 0)
     {
       // lock zooming
-      Standard_Real aScale = persistentScale (theCamera, theViewportWidth, theViewportHeight);
+      Standard_Real aScale = persistentScale (aCamera, theViewportWidth, theViewportHeight);
       Graphic3d_TransformUtils::Scale (aWorldView, aScale, aScale, aScale);
     }
-    theWorldView.ConvertFrom (aWorldView);
-    return;
   }
+
+  if (!theCamera->IsOrthographic() && IsOrthoPers() && theToApplyProjPers)
+  {
+    Graphic3d_Mat4d aProjInv;
+    aProjInv.ConvertFrom (theProjection.Inverted());
+    aWorldView = (aProjInv * aCamera->ProjectionMatrix()) * aWorldView;
+  }
+
+  theWorldView.ConvertFrom (aWorldView);
 }
 
 // =======================================================================
@@ -555,7 +579,7 @@ void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera,
                                      const Standard_Integer theViewportHeight,
                                      BVH_Box<T, 3>& theBoundingBox) const
 {
-  NCollection_Mat4<T> aTPers = Compute (theCamera, theProjection, theWorldView, theViewportWidth, theViewportHeight);
+  NCollection_Mat4<T> aTPers = Compute (theCamera, theProjection, theWorldView, theViewportWidth, theViewportHeight, false);
   if (aTPers.IsIdentity()
   || !theBoundingBox.IsValid())
   {
@@ -594,7 +618,8 @@ NCollection_Mat4<T> Graphic3d_TransformPers::Compute (const Handle(Graphic3d_Cam
                                                       const NCollection_Mat4<T>& theProjection,
                                                       const NCollection_Mat4<T>& theWorldView,
                                                       const Standard_Integer theViewportWidth,
-                                                      const Standard_Integer theViewportHeight) const
+                                                      const Standard_Integer theViewportHeight,
+                                                      const Standard_Boolean theToApplyProjPers) const
 {
   if (myMode == Graphic3d_TMF_None)
   {
@@ -610,7 +635,7 @@ NCollection_Mat4<T> Graphic3d_TransformPers::Compute (const Handle(Graphic3d_Cam
 
   // compute only world-view matrix difference to avoid floating point instability
   // caused by projection matrix modifications outside of this algorithm (e.g. by Z-fit)
-  Apply (theCamera, theProjection, aWorldView, theViewportWidth, theViewportHeight);
+  Apply (theCamera, theProjection, aWorldView, theViewportWidth, theViewportHeight, NULL, theToApplyProjPers);
   return anUnviewMat * aWorldView;
 }
 
index 44ff25b75231d91eae4e53f376a90ee3f74acbdb..0fc6438345a00c45279fc8604f0f683cf695b11f 100644 (file)
@@ -93,6 +93,24 @@ Handle(SelectMgr_BaseIntersector) SelectMgr_AxisIntersector::ScaleAndTransform (
   return aRes;
 }
 
+//=======================================================================
+// function : CopyWithBuilder
+// purpose  : Returns a copy of the frustum using the given frustum builder configuration.
+//            Returned frustum should be re-constructed before being used.
+//=======================================================================
+Handle(SelectMgr_BaseIntersector) SelectMgr_AxisIntersector::CopyWithBuilder (const Handle(SelectMgr_FrustumBuilder)& theBuilder) const
+{
+  (void )theBuilder;
+  Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Point,
+    "Error! SelectMgr_AxisIntersector::CopyWithBuilder() should be called after selection axis initialization");
+
+  Handle(SelectMgr_AxisIntersector) aRes = new SelectMgr_AxisIntersector();
+  aRes->myAxis = myAxis;
+  aRes->mySelectionType = mySelectionType;
+
+  return aRes;
+}
+
 // =======================================================================
 // function : hasIntersection
 // purpose  :
index 6a6b60bc09c8b94d45bd2cef8287dc589e562871..bd225bf735b559dfc6df840e0e7340cf92834287 100644 (file)
@@ -52,6 +52,11 @@ public:
                                                                                const gp_GTrsf& theTrsf,
                                                                                const Handle(SelectMgr_FrustumBuilder)& theBuilder) const Standard_OVERRIDE;
 
+  //! Returns a copy of the intersector transformed using the builder configuration given.
+  //! Builder is an argument that represents corresponding settings for re-constructing transformed frustum from scratch.
+  //! In this class, builder is not used and theBuilder parameter is ignored.
+  Standard_EXPORT virtual Handle(SelectMgr_BaseIntersector) CopyWithBuilder (const Handle(SelectMgr_FrustumBuilder)& theBuilder) const Standard_OVERRIDE;
+
 public:
 
   //! Intersection test between defined axis and given axis-aligned box
index e9bd50edfc8c53ad1d7130ead958f669f63e464e..e35f04d939b576b9aab5607c0d0d1bae44c8331e 100644 (file)
@@ -71,6 +71,11 @@ public:
                                                                const gp_GTrsf& theTrsf,
                                                                const Handle(SelectMgr_FrustumBuilder)& theBuilder) const = 0;
 
+  //! @param theBuilder [in] argument that represents corresponding settings for re-constructing transformed frustum from scratch;
+  //!                        should NOT be NULL.
+  //! @return a copy of the frustum with the input builder assigned
+  virtual Handle(SelectMgr_BaseIntersector) CopyWithBuilder (const Handle(SelectMgr_FrustumBuilder)& theBuilder) const = 0;
+
 public:
 
   //! Return camera definition.
index 0031c5f2756598ef82f52e123067468b503946bf..6ae92c1a0b7b52f3736e86c9047e6d46c14a61d9 100644 (file)
@@ -449,6 +449,28 @@ Handle(SelectMgr_BaseIntersector) SelectMgr_RectangularFrustum::ScaleAndTransfor
   return aRes;
 }
 
+// =======================================================================
+// function : CopyWithBuilder
+// purpose  : Returns a copy of the frustum using the given frustum builder configuration.
+//            Returned frustum should be re-constructed before being used.
+// =======================================================================
+Handle(SelectMgr_BaseIntersector) SelectMgr_RectangularFrustum::CopyWithBuilder (const Handle(SelectMgr_FrustumBuilder)& theBuilder) const
+{
+  Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Point || mySelectionType == SelectMgr_SelectionType_Box,
+    "Error! SelectMgr_RectangularFrustum::CopyWithBuilder() should be called after selection frustum initialization");
+
+  Standard_ASSERT_RAISE (!theBuilder.IsNull(), 
+    "Error! SelectMgr_RectangularFrustum::CopyWithBuilder() should be called with valid builder");
+
+  Handle(SelectMgr_RectangularFrustum) aRes = new SelectMgr_RectangularFrustum();
+  aRes->mySelectionType = mySelectionType;
+  aRes->mySelRectangle = mySelRectangle;
+  aRes->myPixelTolerance = myPixelTolerance;
+  aRes->SetBuilder (theBuilder);
+
+  return aRes;
+}
+
 // =======================================================================
 // function : IsScalable
 // purpose  :
index bcebbb626bfc65a3a9352ec08adcf6b23c306c1e..4db8c2644e8cedd43b78f2f21e29b11f7dc9a837 100644 (file)
@@ -99,6 +99,13 @@ public:
                                                                                const gp_GTrsf& theTrsf,
                                                                                const Handle(SelectMgr_FrustumBuilder)& theBuilder) const Standard_OVERRIDE;
 
+  //! Returns a copy of the frustum using the given frustum builder configuration.
+  //! Returned frustum should be re-constructed before being used.
+  //! @param theBuilder [in] argument that represents corresponding settings for re-constructing transformed frustum from scratch;
+  //!                        should NOT be NULL.
+  //! @return a copy of the frustum with the input builder assigned
+  Standard_EXPORT virtual Handle(SelectMgr_BaseIntersector) CopyWithBuilder (const Handle(SelectMgr_FrustumBuilder)& theBuilder) const Standard_OVERRIDE;
+
   // SAT Tests for different objects
 
   //! SAT intersection test between defined volume and given axis-aligned box
index 89fb16e790fd02e2e3284e5581119cdb82a6d9a6..49794719082f6aee9fad6882c4111ab1fce1f0dd 100644 (file)
@@ -241,17 +241,23 @@ namespace
 //=============================================================================
 SelectMgr_SelectableObjectSet::SelectMgr_SelectableObjectSet()
 {
-  myBVH[BVHSubset_2dPersistent] = new BVH_Tree<Standard_Real, 3>();
-  myBVH[BVHSubset_3dPersistent] = new BVH_Tree<Standard_Real, 3>();
-  myBVH[BVHSubset_3d]           = new BVH_Tree<Standard_Real, 3>();
-
-  myBuilder[BVHSubset_2dPersistent] = new BVH_LinearBuilder<Standard_Real, 3>    (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth);
-  myBuilder[BVHSubset_3dPersistent] = new BVH_LinearBuilder<Standard_Real, 3>    (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth);
-  myBuilder[BVHSubset_3d]           = new BVH_BinnedBuilder<Standard_Real, 3, 4> (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth, Standard_True);
-
-  myIsDirty[BVHSubset_2dPersistent] = Standard_False;
-  myIsDirty[BVHSubset_3dPersistent] = Standard_False;
-  myIsDirty[BVHSubset_3d]           = Standard_False;
+  myBVH[BVHSubset_ortho2dPersistent] = new BVH_Tree<Standard_Real, 3>();
+  myBVH[BVHSubset_ortho3dPersistent] = new BVH_Tree<Standard_Real, 3>();
+  myBVH[BVHSubset_2dPersistent]      = new BVH_Tree<Standard_Real, 3>();
+  myBVH[BVHSubset_3dPersistent]      = new BVH_Tree<Standard_Real, 3>();
+  myBVH[BVHSubset_3d]                = new BVH_Tree<Standard_Real, 3>();
+
+  myBuilder[BVHSubset_ortho2dPersistent] = new BVH_LinearBuilder<Standard_Real, 3>    (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth);
+  myBuilder[BVHSubset_ortho3dPersistent] = new BVH_LinearBuilder<Standard_Real, 3>    (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth);
+  myBuilder[BVHSubset_2dPersistent]      = new BVH_LinearBuilder<Standard_Real, 3>    (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth);
+  myBuilder[BVHSubset_3dPersistent]      = new BVH_LinearBuilder<Standard_Real, 3>    (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth);
+  myBuilder[BVHSubset_3d]                = new BVH_BinnedBuilder<Standard_Real, 3, 4> (BVH_Constants_LeafNodeSizeSingle, BVH_Constants_MaxTreeDepth, Standard_True);
+
+  myIsDirty[BVHSubset_ortho2dPersistent] = Standard_False;
+  myIsDirty[BVHSubset_ortho3dPersistent] = Standard_False;
+  myIsDirty[BVHSubset_2dPersistent]      = Standard_False;
+  myIsDirty[BVHSubset_3dPersistent]      = Standard_False;
+  myIsDirty[BVHSubset_3d]                = Standard_False;
 }
 
 //=============================================================================
@@ -262,10 +268,9 @@ Standard_Boolean SelectMgr_SelectableObjectSet::Append (const Handle(SelectMgr_S
 {
   // get an appropriate BVH subset to insert the object into it
   const Standard_Integer aSubsetIdx = appropriateSubset (theObject);
-
+  
   // check that the object is excluded from other subsets
-  if (myObjects[(aSubsetIdx + 1) % BVHSubsetNb].Contains (theObject)
-   || myObjects[(aSubsetIdx + 2) % BVHSubsetNb].Contains (theObject))
+  if (currentSubset (theObject) != -1)
   {
     return Standard_False;
   }
@@ -401,9 +406,51 @@ void SelectMgr_SelectableObjectSet::UpdateBVH (const Handle(Graphic3d_Camera)& t
       myBuilder[BVHSubset_2dPersistent]->Build (&anAdaptor, myBVH[BVHSubset_2dPersistent].get(), anAdaptor.Box());
     }
 
+    // -------------------------------------------------------------------
+    // check and update 3D orthographic persistence BVH tree if necessary
+    // -------------------------------------------------------------------
+    if (!IsEmpty (BVHSubset_ortho3dPersistent)
+      && (myIsDirty[BVHSubset_ortho3dPersistent]
+       || myLastViewState.IsChanged (aViewState)
+       || isWinSizeChanged))
+    {
+      Handle(Graphic3d_Camera) aNewOrthoCam = new Graphic3d_Camera (*theCam); // If OrthoPers, copy camera and set to orthographic projection
+      aNewOrthoCam->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
+
+      // construct adaptor over private fields to provide direct access for the BVH builder
+      BVHBuilderAdaptorPersistent anAdaptor (myObjects[BVHSubset_ortho3dPersistent],
+                                             aNewOrthoCam, aNewOrthoCam->ProjectionMatrix(), 
+                                             aNewOrthoCam->OrientationMatrix(), theWinSize);
+
+      // update corresponding BVH tree data structure
+      myBuilder[BVHSubset_ortho3dPersistent]->Build (&anAdaptor, myBVH[BVHSubset_ortho3dPersistent].get(), anAdaptor.Box());
+    }
+
+    // -------------------------------------------------------------------
+    // check and update 2D orthographic persistence BVH tree if necessary
+    // -------------------------------------------------------------------
+    if (!IsEmpty (BVHSubset_ortho2dPersistent)
+      && (myIsDirty[BVHSubset_ortho2dPersistent]
+       || myLastViewState.IsProjectionChanged (aViewState)
+       || isWinSizeChanged))
+    {
+      Handle(Graphic3d_Camera) aNewOrthoCam = new Graphic3d_Camera (*theCam); // If OrthoPers, copy camera and set to orthographic projection
+      aNewOrthoCam->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
+
+      // construct adaptor over private fields to provide direct access for the BVH builder
+      BVHBuilderAdaptorPersistent anAdaptor (myObjects[BVHSubset_ortho2dPersistent],
+                                             aNewOrthoCam, aNewOrthoCam->ProjectionMatrix(), 
+                                             SelectMgr_SelectableObjectSet_THE_IDENTITY_MAT, theWinSize);
+
+      // update corresponding BVH tree data structure
+      myBuilder[BVHSubset_ortho2dPersistent]->Build (&anAdaptor, myBVH[BVHSubset_ortho2dPersistent].get(), anAdaptor.Box());
+    }
+
     // release dirty state for every subset
-    myIsDirty[BVHSubset_3dPersistent] = Standard_False;
-    myIsDirty[BVHSubset_2dPersistent] = Standard_False;
+    myIsDirty[BVHSubset_3dPersistent]      = Standard_False;
+    myIsDirty[BVHSubset_2dPersistent]      = Standard_False;
+    myIsDirty[BVHSubset_ortho3dPersistent] = Standard_False;
+    myIsDirty[BVHSubset_ortho2dPersistent] = Standard_False;
 
     // keep last view state
     myLastViewState = aViewState;
@@ -419,9 +466,11 @@ void SelectMgr_SelectableObjectSet::UpdateBVH (const Handle(Graphic3d_Camera)& t
 //=============================================================================
 void SelectMgr_SelectableObjectSet::MarkDirty()
 {
-  myIsDirty[BVHSubset_3d]           = Standard_True;
-  myIsDirty[BVHSubset_3dPersistent] = Standard_True;
-  myIsDirty[BVHSubset_2dPersistent] = Standard_True;
+  myIsDirty[BVHSubset_3d]                = Standard_True;
+  myIsDirty[BVHSubset_3dPersistent]      = Standard_True;
+  myIsDirty[BVHSubset_2dPersistent]      = Standard_True;
+  myIsDirty[BVHSubset_ortho3dPersistent] = Standard_True;
+  myIsDirty[BVHSubset_ortho2dPersistent] = Standard_True;
 }
 //=======================================================================
 //function : DumpJson
index c8cb188fcf9a1fd03956499829e4a7ee2c776178..fa1a7367016ced881eee4130d033b648353319d5 100644 (file)
@@ -42,11 +42,22 @@ public:
   //! needs to be updated only when camera's projection changes. Bounding volumes for this object subclass
   //! is represented directly in eye space coordinates.
   //! This subset uses linear BVH builder with 32 levels of depth and 1 element per leaf.
+  //! - BVHSubset_ortho3dPersistent refers to the subset of 3D persistent selectable objects (rotate, pan, zoom persistence)
+  //! that contains `Graphic3d_TMF_OrthoPers` persistence mode.
+  //! Associated BVH tree needs to be updated when either the camera's projection and position change.
+  //! This subset uses linear BVH builder with 32 levels of depth and 1 element per leaf.
+  //! - BVHSubset_ortho2dPersistent refers to the subset of 2D persistent selectable objects
+  //! that contains `Graphic3d_TMF_OrthoPers` persistence mode. Associated BVH tree
+  //! needs to be updated only when camera's projection changes. Bounding volumes for this object subclass
+  //! is represented directly in eye space coordinates.
+  //! This subset uses linear BVH builder with 32 levels of depth and 1 element per leaf.
   enum BVHSubset
   {
     BVHSubset_3d,
     BVHSubset_3dPersistent,
     BVHSubset_2dPersistent,
+    BVHSubset_ortho3dPersistent,
+    BVHSubset_ortho2dPersistent,
     BVHSubsetNb
   };
 
@@ -140,7 +151,9 @@ public:
   {
     return myObjects[BVHSubset_3d].Contains (theObject)
         || myObjects[BVHSubset_3dPersistent].Contains (theObject)
-        || myObjects[BVHSubset_2dPersistent].Contains (theObject);
+        || myObjects[BVHSubset_2dPersistent].Contains (theObject)
+        || myObjects[BVHSubset_ortho3dPersistent].Contains (theObject)
+        || myObjects[BVHSubset_ortho2dPersistent].Contains (theObject);
   }
 
   //! Returns true if the object set does not contain any selectable objects.
@@ -148,7 +161,9 @@ public:
   {
     return myObjects[BVHSubset_3d].IsEmpty()
         && myObjects[BVHSubset_3dPersistent].IsEmpty()
-        && myObjects[BVHSubset_2dPersistent].IsEmpty();
+        && myObjects[BVHSubset_2dPersistent].IsEmpty()
+        && myObjects[BVHSubset_ortho3dPersistent].IsEmpty()
+        && myObjects[BVHSubset_ortho2dPersistent].IsEmpty();
   }
 
   //! Returns true if the specified object subset is empty.
@@ -192,10 +207,18 @@ private:
       }
       return SelectMgr_SelectableObjectSet::BVHSubset_3d;
     }
-    else if (theObject->TransformPersistence()->Mode() == Graphic3d_TMF_2d)
+    else if ((theObject->TransformPersistence()->Mode() & Graphic3d_TMF_2d) != 0)
     {
+      if (theObject->TransformPersistence()->IsOrthoPers())
+      {
+        return SelectMgr_SelectableObjectSet::BVHSubset_ortho2dPersistent;
+      }
       return SelectMgr_SelectableObjectSet::BVHSubset_2dPersistent;
     }
+    else if (theObject->TransformPersistence()->IsOrthoPers())
+    {
+      return SelectMgr_SelectableObjectSet::BVHSubset_ortho3dPersistent;
+    }
     else
     {
       return SelectMgr_SelectableObjectSet::BVHSubset_3dPersistent;
index d33ea30427092d66ea658f866dbf3234835cfa90..db1e25fabe6574c3063f0fb06a00bcfbdddc263d 100644 (file)
@@ -67,6 +67,28 @@ SelectMgr_SelectingVolumeManager SelectMgr_SelectingVolumeManager::ScaleAndTrans
   return aMgr;
 }
 
+//=======================================================================
+// function : CopyWithBuilder
+// purpose  : Returns a copy of the selecting volume manager and its active frustum re-constructed using the passed builder.
+//            Builder is an argument that represents corresponding settings for re-constructing transformed
+//            frustum from scratch.
+//=======================================================================
+SelectMgr_SelectingVolumeManager SelectMgr_SelectingVolumeManager::CopyWithBuilder (const Handle(SelectMgr_FrustumBuilder)& theBuilder) const
+{
+  SelectMgr_SelectingVolumeManager aMgr;
+  aMgr.myToAllowOverlap = myToAllowOverlap;
+  aMgr.myViewClipPlanes = myViewClipPlanes;
+  aMgr.myObjectClipPlanes = myObjectClipPlanes;
+  aMgr.myViewClipRange = myViewClipRange;
+  if (!myActiveSelectingVolume.IsNull())
+  {
+    aMgr.myActiveSelectingVolume = myActiveSelectingVolume->CopyWithBuilder (theBuilder);
+    aMgr.BuildSelectingVolume();
+  }
+
+  return aMgr;
+}
+
 //=======================================================================
 // function : GetActiveSelectionType
 // purpose  :
index aed25cd94abbaf1cc390101e5f0bf49e007f0d2e..0dd115ffc0e5ae02ff37217f2792b5f6deefe3a1 100644 (file)
@@ -81,6 +81,11 @@ public:
                                                                               const gp_GTrsf& theTrsf,
                                                                               const Handle(SelectMgr_FrustumBuilder)& theBuilder) const;
 
+  //! Returns a copy of the selecting volume manager and its active frustum re-constructed using the passed builder.
+  //! Builder is an argument that represents corresponding settings for re-constructing transformed
+  //! frustum from scratch.
+  Standard_EXPORT virtual SelectMgr_SelectingVolumeManager CopyWithBuilder (const Handle(SelectMgr_FrustumBuilder)& theBuilder) const;
+
 public:
 
   //! Returns current camera definition.
index efaf686e28710a9a4d3367a24534a236a8dca3ae..05abc17df25cab9410c56520e0d112df3def0652 100644 (file)
@@ -189,6 +189,20 @@ Handle(SelectMgr_BaseIntersector) SelectMgr_TriangularFrustum::ScaleAndTransform
   return aRes;
 }
 
+//=======================================================================
+// function : CopyWithBuilder
+// purpose  : Returns a copy of the frustum using the given frustum builder configuration.
+//            Returned frustum should be re-constructed before being used.
+//=======================================================================
+Handle(SelectMgr_BaseIntersector) SelectMgr_TriangularFrustum::CopyWithBuilder (const Handle(SelectMgr_FrustumBuilder)& theBuilder) const
+{
+  Handle(SelectMgr_TriangularFrustum) aRes = new SelectMgr_TriangularFrustum();
+  aRes->mySelTriangle = mySelTriangle;
+  aRes->SetBuilder (theBuilder);
+
+  return aRes;
+}
+
 //=======================================================================
 // function : OverlapsBox
 // purpose  : SAT intersection test between defined volume and
index a13067b03356a6c4e6e50fa92d4602c6959a0dc4..0255b6f61b74b5ba5501b62a01a41beb595c7f34 100644 (file)
@@ -55,6 +55,13 @@ public:
                                                                                const gp_GTrsf& theTrsf,
                                                                                const Handle(SelectMgr_FrustumBuilder)& theBuilder) const Standard_OVERRIDE;
 
+  //! Returns a copy of the frustum using the given frustum builder configuration.
+  //! Returned frustum should be re-constructed before being used.
+  //! @param theBuilder [in] argument that represents corresponding settings for re-constructing transformed frustum from scratch;
+  //!                        should NOT be NULL.
+  //! @return a copy of the frustum with the input builder assigned
+  Standard_EXPORT virtual Handle(SelectMgr_BaseIntersector) CopyWithBuilder (const Handle(SelectMgr_FrustumBuilder)& theBuilder) const Standard_OVERRIDE;
+
 public: //! @name SAT Tests for different objects
 
   //! SAT intersection test between defined volume and given axis-aligned box
index 907a85406179dbcc2a15a8ed5d50069d63332653..0df5e595afbc80d37ff40ef2fd4d9f274cda8cfd 100644 (file)
@@ -186,6 +186,32 @@ Handle(SelectMgr_BaseIntersector) SelectMgr_TriangularFrustumSet::ScaleAndTransf
   return aRes;
 }
 
+//=======================================================================
+// function : CopyWithBuilder
+// purpose  : Returns a copy of the frustum using the given frustum builder configuration.
+//            Returned frustum should be re-constructed before being used.
+//=======================================================================
+Handle(SelectMgr_BaseIntersector) SelectMgr_TriangularFrustumSet::CopyWithBuilder (const Handle(SelectMgr_FrustumBuilder)& theBuilder) const
+{
+  Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Polyline,
+    "Error! SelectMgr_TriangularFrustumSet::CopyWithBuilder() should be called after selection frustum initialization");
+
+  Standard_ASSERT_RAISE (!theBuilder.IsNull(), 
+    "Error! SelectMgr_TriangularFrustumSet::CopyWithBuilder() should be called with valid builder");
+
+  Handle(SelectMgr_TriangularFrustumSet) aRes = new SelectMgr_TriangularFrustumSet();
+  aRes->SetCamera (myCamera);
+  for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
+  {
+    aRes->myFrustums.Append (Handle(SelectMgr_TriangularFrustum)::DownCast (anIter.Value()->CopyWithBuilder (theBuilder)));
+  }
+  aRes->mySelectionType = mySelectionType;
+  aRes->mySelPolyline = mySelPolyline;
+  aRes->myToAllowOverlap = myToAllowOverlap;
+  aRes->SetBuilder (theBuilder);
+  return aRes;
+}
+
 // =======================================================================
 // function : OverlapsBox
 // purpose  :
index 694c3efc55e4f05e1615d2e5d59beb477815adba..5f8c17035128125e4d0df9d105d962dd79f18666 100644 (file)
@@ -62,6 +62,13 @@ public:
                                                                                const gp_GTrsf& theTrsf,
                                                                                const Handle(SelectMgr_FrustumBuilder)& theBuilder) const Standard_OVERRIDE;
 
+  //! Returns a copy of the frustum using the given frustum builder configuration.
+  //! Returned frustum should be re-constructed before being used.
+  //! @param theBuilder [in] argument that represents corresponding settings for re-constructing transformed frustum from scratch;
+  //!                        should NOT be NULL.
+  //! @return a copy of the frustum with the input builder assigned
+  Standard_EXPORT virtual Handle(SelectMgr_BaseIntersector) CopyWithBuilder (const Handle(SelectMgr_FrustumBuilder)& theBuilder) const Standard_OVERRIDE;
+
 public:
 
   Standard_EXPORT virtual Standard_Boolean OverlapsBox (const SelectMgr_Vec3& theMinPnt,
index 4370d4cee03c553dbef39bc0f28b10c82481a2ba..20656e44a0f2ffe3ed486ef403f6b35fe238423b 100644 (file)
@@ -138,12 +138,12 @@ void SelectMgr_ViewerSelector::updatePoint3d (SelectMgr_SortCriterion& theCriter
     case SelectMgr_TypeOfDepthTolerance_UniformPixels:
     case SelectMgr_TypeOfDepthTolerance_SensitivityFactor:
     {
-      if (mySelectingVolumeMgr.Camera().IsNull())
+      if (theMgr.Camera().IsNull())
       {
         // fallback for an arbitrary projection matrix
         theCriterion.Tolerance = aSensFactor / 33.0;
       }
-      else if (mySelectingVolumeMgr.Camera()->IsOrthographic())
+      else if (theMgr.Camera()->IsOrthographic())
       {
         theCriterion.Tolerance = myCameraScale * aSensFactor;
       }
@@ -634,6 +634,7 @@ void SelectMgr_ViewerSelector::TraverseSensitives (const Standard_Integer theVie
 
   Graphic3d_Vec2i aWinSize;
   mySelectingVolumeMgr.WindowSize (aWinSize.x(), aWinSize.y());
+  const double aPixelSize = Max (1.0 / aWinSize.x(), 1.0 / aWinSize.y());
 
   const Handle(Graphic3d_Camera)& aCamera = mySelectingVolumeMgr.Camera();
   Graphic3d_Mat4d aProjectionMat, aWorldViewMat;
@@ -646,11 +647,6 @@ void SelectMgr_ViewerSelector::TraverseSensitives (const Standard_Integer theVie
 
     myCameraEye = aCamera->Eye().XYZ();
     myCameraDir = aCamera->Direction().XYZ();
-    myCameraScale = aCamera->IsOrthographic()
-                  ? aCamera->Scale()
-                  : 2.0 * Tan (aCamera->FOVy() * M_PI / 360.0);
-    const double aPixelSize = Max (1.0 / aWinSize.x(), 1.0 / aWinSize.y());
-    myCameraScale *= aPixelSize;
   }
   mySelectableObjects.UpdateBVH (aCamera, aWinSize);
 
@@ -672,7 +668,8 @@ void SelectMgr_ViewerSelector::TraverseSensitives (const Standard_Integer theVie
     // for 2D space selection transform selecting volumes to perform overlap testing
     // directly in camera's eye space omitting the camera position, which is not
     // needed there at all
-    if (aBVHSubset == SelectMgr_SelectableObjectSet::BVHSubset_2dPersistent)
+    if (aBVHSubset == SelectMgr_SelectableObjectSet::BVHSubset_2dPersistent 
+     || aBVHSubset == SelectMgr_SelectableObjectSet::BVHSubset_ortho2dPersistent)
     {
       gp_GTrsf aTFrustum;
       aTFrustum.SetValue (1, 1, aWorldViewMat.GetValue (0, 0));
@@ -688,22 +685,43 @@ void SelectMgr_ViewerSelector::TraverseSensitives (const Standard_Integer theVie
                                             aWorldViewMat.GetValue (1, 3),
                                             aWorldViewMat.GetValue (2, 3)));
 
-      // define corresponding frustum builder parameters
+      // define corresponding frustum builder parameters for 2d persistence.
       Handle(SelectMgr_FrustumBuilder) aBuilder = new SelectMgr_FrustumBuilder();
       Handle(Graphic3d_Camera) aNewCamera = new Graphic3d_Camera();
       aNewCamera->CopyMappingData (aCamera);
       aNewCamera->SetIdentityOrientation();
+      if (aBVHSubset == SelectMgr_SelectableObjectSet::BVHSubset_ortho2dPersistent)
+      {
+        aNewCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
+      }
       aWorldViewMat = aNewCamera->OrientationMatrix(); // should be identity matrix
       aProjectionMat = aNewCamera->ProjectionMatrix(); // should be the same to aProjectionMat
       aBuilder->SetCamera (aNewCamera);
       aBuilder->SetWindowSize (aWinSize.x(), aWinSize.y());
       aMgr = mySelectingVolumeMgr.ScaleAndTransform (1, aTFrustum, aBuilder);
     }
+    else if (aBVHSubset == SelectMgr_SelectableObjectSet::BVHSubset_ortho3dPersistent)
+    {
+      // define corresponding frustum builder parameters for 3d orthographic persistence.
+      Handle(SelectMgr_FrustumBuilder) aBuilder = new SelectMgr_FrustumBuilder();
+      Handle(Graphic3d_Camera) aNewCamera = new Graphic3d_Camera (*aCamera);
+      aNewCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
+      aWorldViewMat = aNewCamera->OrientationMatrix(); // should be the same to aWorldViewMat
+      aProjectionMat = aNewCamera->ProjectionMatrix(); // should be orthographic projection
+      aBuilder->SetCamera (aNewCamera);
+      aBuilder->SetWindowSize (aWinSize.x(), aWinSize.y());
+      aMgr = mySelectingVolumeMgr.CopyWithBuilder (aBuilder);
+    }
     else
     {
       aMgr = mySelectingVolumeMgr;
     }
 
+    myCameraScale = aMgr.Camera()->IsOrthographic()
+                  ? aMgr.Camera()->Scale()
+                  : 2.0 * Tan (aMgr.Camera()->FOVy() * M_PI / 360.0);
+    myCameraScale *= aPixelSize;
+
     const opencascade::handle<BVH_Tree<Standard_Real, 3> >& aBVHTree = mySelectableObjects.BVH (aBVHSubset);
 
     Standard_Integer aNode = 0;
index a9dd146cba063f904527b53d48282c3a850082e2..4537080f63e487b59413a3a9ec41d19032479552 100644 (file)
@@ -328,7 +328,7 @@ protected:
   //! @param theObject [in] the selectable object for traversal.
   //! @param theMgr [in] the (un)transformed copy of the selecting volume manager representing active selection frustum.
   //! @param theCamera, theProjectionMat, theWorldViewMat [in] the source camera and matrices for theMgr given.
-  //! @param theViewportWidth, theViewportHeight [in] viewport (window) dimensions for evaluating 
+  //! @param theWinSize [in] viewport (window) dimensions for evaluating 
   //!        object's transformation persistence.
   Standard_EXPORT void traverseObject (const Handle(SelectMgr_SelectableObject)& theObject,
                                        const SelectMgr_SelectingVolumeManager& theMgr,
index 9fb0cfea5ac3144952f678c25a58352a4dc98f88..43aced25af00d2e8753c32968cafe1ef1b040fad 100644 (file)
@@ -5100,6 +5100,24 @@ static int VDisplay2 (Draw_Interpretor& theDI,
         aTrsfPers = new Graphic3d_TransformPers (aTrsfPers->Mode(), Aspect_TypeOfTriedronPosition (aCorner), Graphic3d_Vec2i (aZ.IntegerValue()));
       }
     }
+    else if (aNameCase == "-trsfPersOrtho")
+    {
+      if (aTrsfPers.IsNull())
+      {
+        Message::SendFail() << "Error: wrong syntax at " << aName << ".";
+        return 1;
+      }
+
+      toSetTrsfPers = Standard_True;
+      if (aTrsfPers->IsZoomOrRotate())
+      {
+        aTrsfPers = new Graphic3d_TransformPers (aTrsfPers->Mode() | Graphic3d_TMF_OrthoPers, aTrsfPers->AnchorPoint());
+      }
+      else if (aTrsfPers->IsTrihedronOr2d())
+      {
+        aTrsfPers = new Graphic3d_TransformPers (aTrsfPers->Mode() | Graphic3d_TMF_OrthoPers, aTrsfPers->Corner2d(), aTrsfPers->Offset2d());
+      }
+    }
     else if (aNameCase == "-layer"
           || aNameCase == "-zlayer")
     {
@@ -6630,42 +6648,45 @@ If last 3 optional parameters are not set prints numbers of U-, V- isolines and
 
   addCmd ("vdisplay", VDisplay2, /* [vdisplay] */ R"(
 vdisplay [-noupdate|-update] [-mutable] [-neutral]
-         [-trsfPers {zoom|rotate|zoomRotate|none}=none]
+         [-trsfPers {zoom|rotate|zoomRotate|trihedron|none}=none]
             [-trsfPersPos X Y [Z]] [-3d]
             [-2d|-trihedron [{top|bottom|left|right|topLeft
                             |topRight|bottomLeft|bottomRight}
               [offsetX offsetY]]]
+            [-trsfPersOrtho]
          [-dispMode mode] [-highMode mode]
          [-layer index] [-top|-topmost|-overlay|-underlay]
          [-redisplay] [-erased]
          [-noecho] [-autoTriangulation {0|1}]
          name1 [name2] ... [name n]
 Displays named objects.
- -noupdate    Suppresses viewer redraw call.
- -mutable     Enables optimizations for mutable objects.
- -neutral     Draws objects in main viewer.
- -erased      Loads the object into context, but does not display it.
- -layer       Sets z-layer for objects.
-              Alternatively -overlay|-underlay|-top|-topmost
-              options can be used for the default z-layers.
- -top         Draws object on top of main presentations
-              but below topmost.
- -topmost     Draws in overlay for 3D presentations.
-              with independent Depth.
- -overlay     Draws objects in overlay for 2D presentations.
-              (On-Screen-Display)
- -underlay    Draws objects in underlay for 2D presentations.
-              (On-Screen-Display)
+ -noupdate      Suppresses viewer redraw call.
+ -mutable       Enables optimizations for mutable objects.
+ -neutral       Draws objects in main viewer.
+ -erased        Loads the object into context, but does not display it.
+ -layer         Sets z-layer for objects.
+                Alternatively -overlay|-underlay|-top|-topmost
+                options can be used for the default z-layers.
+ -top           Draws object on top of main presentations
+                but below topmost.
+ -topmost       Draws in overlay for 3D presentations.
+                with independent Depth.
+ -overlay       Draws objects in overlay for 2D presentations.
+                (On-Screen-Display)
+ -underlay      Draws objects in underlay for 2D presentations.
+                (On-Screen-Display)
  -selectable|-noselect Controls selection of objects.
- -trsfPers    Sets a transform persistence flags.
- -trsfPersPos Sets an anchor point for transform persistence.
- -2d          Displays object in screen coordinates.
-              (DY looks up)
- -dispmode    Sets display mode for objects.
- -highmode    Sets hilight mode for objects.
- -redisplay   Recomputes presentation of objects.
- -noecho      Avoid printing of command results.
- -autoTriang  Enable/disable auto-triangulation for displayed shape.
+ -trsfPers      Sets a transform persistence flags.
+ -trsfPersPos   Sets an anchor point for transform persistence.
+ -2d            Displays object in screen coordinates.
+                (DY looks up)
+ -trsfPersOrtho Set orthographic transform persistence.
+                (Objects shown with orthographic projection)
+ -dispmode      Sets display mode for objects.
+ -highmode      Sets hilight mode for objects.
+ -redisplay     Recomputes presentation of objects.
+ -noecho        Avoid printing of command results.
+ -autoTriang    Enable/disable auto-triangulation for displayed shape.
 )" /* [vdisplay] */);
 
   addCmd ("vnbdisplayed", VNbDisplayed, /* [vnbdisplayed] */ R"(
index 0de77278eaa0014bd8b9811307e8c34d7275cd65..d700adce803dae7ba38b9e8d77a0db929e36e944 100644 (file)
@@ -13686,6 +13686,12 @@ static int VViewCube (Draw_Interpretor& ,
     {
       aViewCube->SetAxesSphereRadius (Draw::Atof (theArgVec[++anArgIter]));
     }
+    else if (anArg == "-orthopers")
+    {
+      const Handle(Graphic3d_TransformPers)& aTrsfPers = aViewCube->TransformPersistence();
+      Handle(Graphic3d_TransformPers) anOrthoPers = new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers | Graphic3d_TMF_OrthoPers, aTrsfPers->Corner2d(), aTrsfPers->Offset2d());
+      aViewCube->SetTransformPersistence (anOrthoPers);
+    }
     else
     {
       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
@@ -14983,6 +14989,7 @@ Displays interactive view manipulation object. Options:
  -axesSphereRadius Value  radius of the sphere (central point) of trihedron
  -fixedAnimation {0|1}    uninterruptible animation loop
  -duration Seconds        animation duration in seconds
+ -orthoPers               force orthographic projection persistence.
 )" /* [vviewcube] */);
 
   addCmd ("vcolorconvert", VColorConvert, /* [vcolorconvert] */ R"(
diff --git a/tests/v3d/viewcube/orthopers b/tests/v3d/viewcube/orthopers
new file mode 100644 (file)
index 0000000..5c240ed
--- /dev/null
@@ -0,0 +1,37 @@
+puts "=================================="
+puts "0028954: Visualization - compare AIS_ViewCube on perspective view with and without orthographic persistence"
+puts "=================================="
+
+pload MODELING VISUALIZATION
+vclear
+vinit View1
+vcamera -persp
+
+box b 15 20 70
+vdisplay -dispMode 1 b
+vaxo
+vfit
+vviewcube vc -fixedAnimation 1 -duration 0 -orthoPers
+
+vmoveto 70 350
+if {[vreadpixel 95 350 name rgb] != "GRAY62"} { puts "Error: Highlighting of view cube Side is wrong." }
+vmoveto 0 0
+vdump $imagedir/${casename}_axo.png
+
+# check FRONT side
+vselect 70 340
+if {[vreadpixel 255 300 name rgb] != "BLACK"} { puts "Error: Position of FRONT camera is wrong." }
+vdump $imagedir/${casename}_side.png
+
+# check FRONT/TOP edge
+vselect 110 270
+if {[vreadpixel 100 320 name rgb] != "GRAY57"} { puts "Error: Position of FRONT-TOP camera is wrong." }
+if {[vreadpixel 100 310 name rgb] != "CYAN"}   { puts "Error: Position of FRONT-TOP camera is wrong." }
+vdump $imagedir/${casename}_edge.png
+
+# Check vertex
+vselect 140 310
+if {[vreadpixel 100 290 name rgb] != "GRAY41"} { puts "Error: Position of TOP-FRONT-RIGHT camera is wrong." }
+if {[vreadpixel 100 310 name rgb] != "CYAN"}   { puts "Error: Position of TOP-FRONT-RIGHT camera is wrong." }
+if {[vreadpixel 100 320 name rgb] != "GRAY62"} { puts "Error: Position of TOP-FRONT-RIGHT camera is wrong." }
+vdump $imagedir/${casename}_corner.png