From 8996b4490a69f1a96ca9b689dc239d1f8acf5fc5 Mon Sep 17 00:00:00 2001 From: nds Date: Wed, 7 Aug 2019 09:42:33 +0300 Subject: [PATCH] 0030695: Visualization - selection by box should use clipping planes set for viewer - moving check on touching the clipping plane in selection only. --- src/Graphic3d/Graphic3d_ClipPlane.hxx | 32 +++++++++ src/SelectMgr/SelectMgr_ViewerSelector.cxx | 76 +++++++++++++++++--- src/StdSelect/StdSelect_ViewerSelector3d.cxx | 4 ++ tests/bugs/vis/bug30695 | 47 ++++++++++++ 4 files changed, 150 insertions(+), 9 deletions(-) create mode 100644 tests/bugs/vis/bug30695 diff --git a/src/Graphic3d/Graphic3d_ClipPlane.hxx b/src/Graphic3d/Graphic3d_ClipPlane.hxx index b1857607e1..41259dbee2 100755 --- a/src/Graphic3d/Graphic3d_ClipPlane.hxx +++ b/src/Graphic3d/Graphic3d_ClipPlane.hxx @@ -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 { diff --git a/src/SelectMgr/SelectMgr_ViewerSelector.cxx b/src/SelectMgr/SelectMgr_ViewerSelector.cxx index 9ff49df7aa..e80ff644df 100644 --- a/src/SelectMgr/SelectMgr_ViewerSelector.cxx +++ b/src/SelectMgr/SelectMgr_ViewerSelector.cxx @@ -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) diff --git a/src/StdSelect/StdSelect_ViewerSelector3d.cxx b/src/StdSelect/StdSelect_ViewerSelector3d.cxx index b6836d7503..51a5286e32 100644 --- a/src/StdSelect/StdSelect_ViewerSelector3d.cxx +++ b/src/StdSelect/StdSelect_ViewerSelector3d.cxx @@ -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 index 0000000000..d8ce2bfca4 --- /dev/null +++ b/tests/bugs/vis/bug30695 @@ -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!" +} -- 2.20.1