0030695: Visualization - selection by box should use clipping planes set for viewer...
authornds <nds@opencascade.com>
Wed, 7 Aug 2019 06:42:33 +0000 (09:42 +0300)
committerbugmaster <bugmaster@opencascade.com>
Wed, 7 Aug 2019 16:54:06 +0000 (19:54 +0300)
src/Graphic3d/Graphic3d_ClipPlane.hxx
src/SelectMgr/SelectMgr_ViewerSelector.cxx
src/StdSelect/StdSelect_ViewerSelector3d.cxx
tests/bugs/vis/bug30695 [new file with mode: 0644]

index b1857607e1d422f385f029c937289b3668262460..41259dbee2a4539c8be14f5c8ea97674fe818707 100755 (executable)
@@ -291,6 +291,28 @@ public:
     return aState;
   }
 
+  //! Check if the given bounding box is In and touch the clipping planes
+  Standard_Boolean ProbeBoxTouch (const Graphic3d_BndBox3d& theBox) const
+  {
+    for (const Graphic3d_ClipPlane* aPlaneIter = this; aPlaneIter != NULL; aPlaneIter = aPlaneIter->myNextInChain.get())
+    {
+      if (aPlaneIter->IsBoxFullInHalfspace (theBox))
+      {
+        // within union operation, if box is entirely inside at least one half-space, others can be ignored
+        return Standard_False;
+      }
+      else if (!aPlaneIter->IsBoxFullOutHalfspace (theBox))
+      {
+        // the box is not fully out, and not fully in, check is it on (but not intersect)
+        if (ProbeBoxMaxPointHalfspace (theBox) != Graphic3d_ClipState_Out)
+        {
+          return Standard_True;
+        }
+      }
+    }
+    return Standard_False;
+  }
+
 public:
 
   //! Check if the given point is outside of the half-space (e.g. should be discarded by clipping plane).
@@ -329,6 +351,16 @@ public:
     return IsPointOutHalfspace (aMaxPnt);
   }
 
+  //! Check if the given bounding box is fully outside of the half-space (e.g. should be discarded by clipping plane).
+  Graphic3d_ClipState ProbeBoxMaxPointHalfspace (const Graphic3d_BndBox3d& theBox) const
+  {
+    const Graphic3d_Vec4d aMaxPnt (myEquation.x() > 0.0 ? theBox.CornerMax().x() : theBox.CornerMin().x(),
+                                   myEquation.y() > 0.0 ? theBox.CornerMax().y() : theBox.CornerMin().y(),
+                                   myEquation.z() > 0.0 ? theBox.CornerMax().z() : theBox.CornerMin().z(),
+                                   1.0);
+    return ProbePointHalfspace (aMaxPnt);
+  }
+
   //! Check if the given bounding box is fully inside (or touches from inside) the half-space (e.g. NOT discarded by clipping plane).
   bool IsBoxFullInHalfspace (const Graphic3d_BndBox3d& theBox) const
   {
index 9ff49df7aa0241ba4af901ade84f14cbf53fbc43..e80ff644dfe5d6c6b4c716354a672e8a7aaab3d0 100644 (file)
@@ -378,6 +378,30 @@ void SelectMgr_ViewerSelector::traverseObject (const Handle(SelectMgr_Selectable
     aMgr.SetViewClipping (theMgr.ViewClipping(), theObject->ClipPlanes());
   }
 
+  if (!theMgr.ViewClipping().IsNull() &&
+      theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Box)
+  {
+    Graphic3d_BndBox3d aBBox (aSensitivesTree->MinPoint (0), aSensitivesTree->MaxPoint (0));
+    // If box selection is active, and the whole sensitive tree is out of the clip planes
+    // selection is empty for this object
+    const Handle(Graphic3d_SequenceOfHClipPlane)& aViewPlanes = theMgr.ViewClipping();
+
+    for (Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (*aViewPlanes); aPlaneIt.More(); aPlaneIt.Next())
+    {
+      const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
+      if (!aPlane->IsOn())
+      {
+        continue;
+      }
+
+      Graphic3d_ClipState aState = aPlane->ProbeBox (aBBox);
+      if (aState == Graphic3d_ClipState_Out) // do not process only whole trees, next check on the tree node
+      {
+        return;
+      }
+    }
+  }
+
   const Standard_Integer aFirstStored = mystored.Extent() + 1;
 
   Standard_Integer aStack[BVH_Constants_MaxTreeDepth];
@@ -419,17 +443,51 @@ void SelectMgr_ViewerSelector::traverseObject (const Handle(SelectMgr_Selectable
     }
     else
     {
-      Standard_Integer aStartIdx = aSensitivesTree->BegPrimitive (aNode);
-      Standard_Integer anEndIdx = aSensitivesTree->EndPrimitive (aNode);
-      for (Standard_Integer anIdx = aStartIdx; anIdx <= anEndIdx; ++anIdx)
+      bool aClipped = false;
+      if (!theMgr.ViewClipping().IsNull() &&
+          theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Box)
       {
-        const Handle(SelectMgr_SensitiveEntity)& aSensitive = anEntitySet->GetSensitiveById (anIdx);
-        if (aSensitive->IsActiveForSelection())
+        Graphic3d_BndBox3d aBBox (aSensitivesTree->MinPoint (aNode), aSensitivesTree->MaxPoint (aNode));
+        // If box selection is active, and the whole sensitive tree is out of the clip planes
+        // selection is empty for this object
+        const Handle(Graphic3d_SequenceOfHClipPlane)& aViewPlanes = theMgr.ViewClipping();
+
+        for (Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (*aViewPlanes); aPlaneIt.More(); aPlaneIt.Next())
         {
-          const Handle(Select3D_SensitiveEntity)& anEnt = aSensitive->BaseSensitive();
-          SelectMgr_SelectingVolumeManager aTmpMgr = aMgr;
-          computeFrustum (anEnt, theMgr, aInversedTrsf, aScaledTrnsfFrustums, aTmpMgr);
-          checkOverlap (anEnt, aInversedTrsf, aTmpMgr);
+          const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
+          if (!aPlane->IsOn())
+          {
+            continue;
+          }
+          Graphic3d_ClipState aState = aPlane->ProbeBox (aBBox);
+          if (aState == Graphic3d_ClipState_Out)
+          {
+            aClipped = true;
+            break;
+          }
+          if (aState == Graphic3d_ClipState_On && !mySelectingVolumeMgr.IsOverlapAllowed()) // partially clipped
+          {
+            if (aPlane->ProbeBoxTouch (aBBox))
+              continue;
+            aClipped = true;
+            break;
+          }
+        }
+      }
+      if (!aClipped)
+      {
+        Standard_Integer aStartIdx = aSensitivesTree->BegPrimitive (aNode);
+        Standard_Integer anEndIdx = aSensitivesTree->EndPrimitive (aNode);
+        for (Standard_Integer anIdx = aStartIdx; anIdx <= anEndIdx; ++anIdx)
+        {
+          const Handle(SelectMgr_SensitiveEntity)& aSensitive = anEntitySet->GetSensitiveById (anIdx);
+          if (aSensitive->IsActiveForSelection())
+          {
+            const Handle(Select3D_SensitiveEntity)& anEnt = aSensitive->BaseSensitive();
+            SelectMgr_SelectingVolumeManager aTmpMgr = aMgr;
+            computeFrustum (anEnt, theMgr, aInversedTrsf, aScaledTrnsfFrustums, aTmpMgr);
+            checkOverlap (anEnt, aInversedTrsf, aTmpMgr);
+          }
         }
       }
       if (aHead < 0)
index b6836d7503e2a9098ea24eabc62016928657a6ee..51a5286e32512f904d8e005c7aa71a938f0c1850 100644 (file)
@@ -160,6 +160,8 @@ void StdSelect_ViewerSelector3d::Pick (const Standard_Integer theXPMin,
   mySelectingVolumeMgr.BuildSelectingVolume (aMinMousePos,
                                              aMaxMousePos);
 
+  mySelectingVolumeMgr.SetViewClipping (theView->ClipPlanes(), Handle(Graphic3d_SequenceOfHClipPlane)());
+
   TraverseSensitives();
 }
 
@@ -178,6 +180,8 @@ void StdSelect_ViewerSelector3d::Pick (const TColgp_Array1OfPnt2d& thePolyline,
   mySelectingVolumeMgr.SetWindowSize (aWidth, aHeight);
   mySelectingVolumeMgr.BuildSelectingVolume (thePolyline);
 
+  mySelectingVolumeMgr.SetViewClipping (theView->ClipPlanes(), Handle(Graphic3d_SequenceOfHClipPlane)());
+
   TraverseSensitives();
 }
 
diff --git a/tests/bugs/vis/bug30695 b/tests/bugs/vis/bug30695
new file mode 100644 (file)
index 0000000..d8ce2bf
--- /dev/null
@@ -0,0 +1,47 @@
+puts "============="
+puts "0030695: Visualization - selection by box should use clipping planes set for viewer"
+puts "============="
+
+pload ALL
+vinit View1
+
+box b 10 10 10
+vdisplay b
+
+box b1 -5 0 0 2 2 2
+vdisplay b1
+
+box b2 13 0 0 2 2 2
+vdisplay b2
+
+box b3 16 0 0 2 2 2
+vdisplay b3
+
+vsetdispmode 1
+
+vtop
+vfit
+vzoom 0.5
+
+# apply selection with rectangle covering all visualized objects
+vselect 40 100 370 300
+if {[vnbselected] != 4} {
+  puts "ERROR: Initial objects are not selected!"
+}
+
+vclipplane create pln
+vclipplane set pln view Driver1/Viewer1/View1
+# use clippling plane to have two objects visible (the second object is partially visible)
+vclipplane change pln equation -1 0 0 5
+
+# apply inital selection rectangle, expecting selection of only fully visible object
+vselect 40 100 370 300
+if {[vnbselected] != 1} {
+  puts "ERROR: Bad numer of selected objects after clippling plane set on view!"
+}
+
+# apply inital selection rectangle, expecting selection of partially included object also
+vselect 40 100 370 300 -allowoverlap 1
+if {[vnbselected] != 2} {
+  puts "ERROR: Bad numer of selected objects after clippling plane set on view with allow overlap selection!"
+}