diff --git a/src/AIS/AIS_ViewController.cxx b/src/AIS/AIS_ViewController.cxx index 87a4864bc7..d4e79f7a48 100644 --- a/src/AIS/AIS_ViewController.cxx +++ b/src/AIS/AIS_ViewController.cxx @@ -2210,7 +2210,6 @@ void AIS_ViewController::handleSelectionPoly (const Handle(AIS_InteractiveContex aPolyIter.ChangeValue() = gp_Pnt2d (aNewPnt.x(), -aNewPnt.y()); } - theCtx->MainSelector()->AllowOverlapDetection (false); if (myGL.Selection.IsXOR) { theCtx->ShiftSelect (aPolyline, theView, false); @@ -2219,6 +2218,7 @@ void AIS_ViewController::handleSelectionPoly (const Handle(AIS_InteractiveContex { theCtx->Select (aPolyline, theView, false); } + theCtx->MainSelector()->AllowOverlapDetection (false); } } diff --git a/src/MeshVS/MeshVS_SensitiveQuad.cxx b/src/MeshVS/MeshVS_SensitiveQuad.cxx index 454d9da39c..e12f3f70ce 100644 --- a/src/MeshVS/MeshVS_SensitiveQuad.cxx +++ b/src/MeshVS/MeshVS_SensitiveQuad.cxx @@ -67,6 +67,12 @@ Standard_Boolean MeshVS_SensitiveQuad::Matches (SelectBasics_SelectingVolumeMana { if (!theMgr.IsOverlapAllowed()) // check for inclusion { + if (theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Polyline) + { + SelectBasics_PickResult aDummy; + return theMgr.Overlaps (myVertices[0], myVertices[1], myVertices[2], Select3D_TOS_INTERIOR, aDummy) + && theMgr.Overlaps (myVertices[0], myVertices[2], myVertices[3], Select3D_TOS_INTERIOR, aDummy); + } for (Standard_Integer aPntIdx = 0; aPntIdx < 4; ++aPntIdx) { if (!theMgr.Overlaps (myVertices[aPntIdx])) diff --git a/src/Select3D/Select3D_SensitiveCircle.cxx b/src/Select3D/Select3D_SensitiveCircle.cxx index 3f3f14f5c2..82bf115bde 100644 --- a/src/Select3D/Select3D_SensitiveCircle.cxx +++ b/src/Select3D/Select3D_SensitiveCircle.cxx @@ -211,6 +211,11 @@ Standard_Boolean Select3D_SensitiveCircle::Matches (SelectBasics_SelectingVolume Points3D (anArrayOfPnt); if (!theMgr.IsOverlapAllowed()) { + if (theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Polyline) + { + SelectBasics_PickResult aDummy; + return theMgr.Overlaps (anArrayOfPnt, mySensType, aDummy); + } for (Standard_Integer aPntIdx = anArrayOfPnt->Lower(); aPntIdx <= anArrayOfPnt->Upper(); ++aPntIdx) { if (!theMgr.Overlaps (anArrayOfPnt->Value(aPntIdx))) diff --git a/src/Select3D/Select3D_SensitivePoly.cxx b/src/Select3D/Select3D_SensitivePoly.cxx index bca131d685..d582fef161 100644 --- a/src/Select3D/Select3D_SensitivePoly.cxx +++ b/src/Select3D/Select3D_SensitivePoly.cxx @@ -254,6 +254,11 @@ Standard_Boolean Select3D_SensitivePoly::elementIsInside (SelectBasics_Selecting } const Standard_Integer aSegmentIdx = mySegmentIndexes->Value (theElemIdx); + if (theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Polyline) + { + SelectBasics_PickResult aDummy; + return theMgr.Overlaps (myPolyg.Pnt3d (aSegmentIdx + 0), myPolyg.Pnt3d (aSegmentIdx + 1), aDummy); + } return theMgr.Overlaps (myPolyg.Pnt3d (aSegmentIdx + 0)) && theMgr.Overlaps (myPolyg.Pnt3d (aSegmentIdx + 1)); } diff --git a/src/Select3D/Select3D_SensitiveSegment.cxx b/src/Select3D/Select3D_SensitiveSegment.cxx index 520741138b..c402199ce9 100644 --- a/src/Select3D/Select3D_SensitiveSegment.cxx +++ b/src/Select3D/Select3D_SensitiveSegment.cxx @@ -45,6 +45,10 @@ Standard_Boolean Select3D_SensitiveSegment::Matches (SelectBasics_SelectingVolum { if (!theMgr.IsOverlapAllowed()) // check for inclusion { + if (theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Polyline) + { + return theMgr.Overlaps (myStart, myEnd, thePickResult); + } return theMgr.Overlaps (myStart, thePickResult) && theMgr.Overlaps (myEnd, thePickResult); } diff --git a/src/Select3D/Select3D_SensitiveTriangle.cxx b/src/Select3D/Select3D_SensitiveTriangle.cxx index 2b14690632..47291ad68a 100644 --- a/src/Select3D/Select3D_SensitiveTriangle.cxx +++ b/src/Select3D/Select3D_SensitiveTriangle.cxx @@ -50,6 +50,11 @@ Standard_Boolean Select3D_SensitiveTriangle::Matches (SelectBasics_SelectingVolu { if (!theMgr.IsOverlapAllowed()) { + if (theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Polyline) + { + SelectBasics_PickResult aDummy; + return theMgr.Overlaps (myPoints[0], myPoints[1], myPoints[2], mySensType, aDummy); + } return theMgr.Overlaps (myPoints[0]) && theMgr.Overlaps (myPoints[1]) && theMgr.Overlaps (myPoints[2]); diff --git a/src/Select3D/Select3D_SensitiveTriangulation.cxx b/src/Select3D/Select3D_SensitiveTriangulation.cxx index e80dbc6470..ad7677011b 100644 --- a/src/Select3D/Select3D_SensitiveTriangulation.cxx +++ b/src/Select3D/Select3D_SensitiveTriangulation.cxx @@ -314,6 +314,11 @@ Standard_Boolean Select3D_SensitiveTriangulation::elementIsInside (SelectBasics_ { const gp_Pnt& aSegmPnt1 = myTriangul->Nodes().Value (myFreeEdges->Value (aPrimitiveIdx * 2 + 1)); const gp_Pnt& aSegmPnt2 = myTriangul->Nodes().Value (myFreeEdges->Value (aPrimitiveIdx * 2 + 2)); + if (theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Polyline) + { + SelectBasics_PickResult aDummy; + return theMgr.Overlaps (aSegmPnt1, aSegmPnt2, aDummy); + } return theMgr.Overlaps (aSegmPnt1) && theMgr.Overlaps (aSegmPnt2); } else @@ -324,6 +329,11 @@ Standard_Boolean Select3D_SensitiveTriangulation::elementIsInside (SelectBasics_ const gp_Pnt& aPnt1 = myTriangul->Nodes().Value (aNode1); const gp_Pnt& aPnt2 = myTriangul->Nodes().Value (aNode2); const gp_Pnt& aPnt3 = myTriangul->Nodes().Value (aNode3); + if (theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Polyline) + { + SelectBasics_PickResult aDummy; + return theMgr.Overlaps (aPnt1, aPnt2, aPnt3, mySensType, aDummy); + } return theMgr.Overlaps (aPnt1) && theMgr.Overlaps (aPnt2) && theMgr.Overlaps (aPnt3); diff --git a/src/SelectMgr/SelectMgr_SelectingVolumeManager.cxx b/src/SelectMgr/SelectMgr_SelectingVolumeManager.cxx index 03cbffa88f..89230c7668 100644 --- a/src/SelectMgr/SelectMgr_SelectingVolumeManager.cxx +++ b/src/SelectMgr/SelectMgr_SelectingVolumeManager.cxx @@ -230,6 +230,7 @@ void SelectMgr_SelectingVolumeManager::BuildSelectingVolume (const TColgp_Array1 return; mySelectingVolumes[FrustumSet]->Build (thePoints); + Handle(SelectMgr_TriangularFrustumSet)::DownCast (mySelectingVolumes[FrustumSet])->SetAllowOverlapDetection (IsOverlapAllowed()); } //======================================================================= @@ -402,7 +403,7 @@ void SelectMgr_SelectingVolumeManager::AllowOverlapDetection (const Standard_Boo //======================================================================= Standard_Boolean SelectMgr_SelectingVolumeManager::IsOverlapAllowed() const { - return myActiveSelectionType != Box || myToAllowOverlap; + return myToAllowOverlap || myActiveSelectionType == Point; } //======================================================================= diff --git a/src/SelectMgr/SelectMgr_SelectingVolumeManager.hxx b/src/SelectMgr/SelectMgr_SelectingVolumeManager.hxx index 5b89bbdd92..6b3fe7822d 100644 --- a/src/SelectMgr/SelectMgr_SelectingVolumeManager.hxx +++ b/src/SelectMgr/SelectMgr_SelectingVolumeManager.hxx @@ -158,7 +158,6 @@ public: //! Throws exception if active selection type is not Point. Standard_EXPORT virtual gp_Pnt DetectedPoint (const Standard_Real theDepth) const Standard_OVERRIDE; - //! Is used for rectangular selection only //! If theIsToAllow is false, only fully included sensitives will be detected, otherwise the algorithm will //! mark both included and overlapped entities as matched Standard_EXPORT virtual void AllowOverlapDetection (const Standard_Boolean theIsToAllow); diff --git a/src/SelectMgr/SelectMgr_TriangularFrustumSet.cxx b/src/SelectMgr/SelectMgr_TriangularFrustumSet.cxx index 7da53986e4..78a5d72654 100644 --- a/src/SelectMgr/SelectMgr_TriangularFrustumSet.cxx +++ b/src/SelectMgr/SelectMgr_TriangularFrustumSet.cxx @@ -22,6 +22,14 @@ #define MEMORY_BLOCK_SIZE 512 * 7 +// ======================================================================= +// function : SelectMgr_TriangularFrustumSet +// purpose : +// ======================================================================= +SelectMgr_TriangularFrustumSet::SelectMgr_TriangularFrustumSet() +: myToAllowOverlap (Standard_False) +{} + // ======================================================================= // function : BuildSelectingVolume // purpose : Meshes polygon bounded by polyline. Than organizes a set of @@ -34,14 +42,20 @@ void SelectMgr_TriangularFrustumSet::Build (const TColgp_Array1OfPnt2d& thePoint myFrustums.Clear(); Handle(NCollection_IncAllocator) anAllocator = new NCollection_IncAllocator (MEMORY_BLOCK_SIZE); - Handle(BRepMesh_DataStructureOfDelaun) aMeshStructure = new BRepMesh_DataStructureOfDelaun(anAllocator); + Handle(BRepMesh_DataStructureOfDelaun) aMeshStructure = new BRepMesh_DataStructureOfDelaun (anAllocator); Standard_Integer aPtsLower = thePoints.Lower(); Standard_Integer aPtsUpper = thePoints.Upper(); IMeshData::VectorOfInteger anIndexes(aPtsUpper - aPtsLower, anAllocator); + myBoundaryPoints.Resize (aPtsLower, aPtsLower + 2 * (thePoints.Size()) - 1, Standard_False); + for (Standard_Integer aPtIdx = aPtsLower; aPtIdx <= aPtsUpper; ++aPtIdx) { - BRepMesh_Vertex aVertex(thePoints.Value(aPtIdx).XY(), aPtIdx, BRepMesh_Frontier); - anIndexes.Append(aMeshStructure->AddNode(aVertex)); + BRepMesh_Vertex aVertex (thePoints.Value (aPtIdx).XY(), aPtIdx, BRepMesh_Frontier); + anIndexes.Append (aMeshStructure->AddNode (aVertex)); + const gp_Pnt aNearPnt = myBuilder->ProjectPntOnViewPlane (aVertex.Coord().X(), aVertex.Coord().Y(), 0.0); + const gp_Pnt aFarPnt = myBuilder->ProjectPntOnViewPlane (aVertex.Coord().X(), aVertex.Coord().Y(), 1.0); + myBoundaryPoints.SetValue (aPtIdx, aNearPnt); + myBoundaryPoints.SetValue (aPtIdx + thePoints.Size(), aFarPnt); } Standard_Real aPtSum = 0; @@ -118,6 +132,14 @@ Handle(SelectMgr_BaseFrustum) SelectMgr_TriangularFrustumSet::ScaleAndTransform aRes->myFrustums.Append (Handle(SelectMgr_TriangularFrustum)::DownCast (anIter.Value()->ScaleAndTransform (theScale, theTrsf))); } + aRes->myBoundaryPoints.Resize (myBoundaryPoints.Lower(), myBoundaryPoints.Upper(), Standard_False); + for (Standard_Integer anIdx = myBoundaryPoints.Lower(); anIdx <= myBoundaryPoints.Upper(); anIdx++) + { + gp_Pnt aPoint = myBoundaryPoints.Value (anIdx); + theTrsf.Transforms (aPoint.ChangeCoord()); + aRes->myBoundaryPoints.SetValue (anIdx, aPoint); + } + return aRes; } @@ -145,12 +167,43 @@ Standard_Boolean SelectMgr_TriangularFrustumSet::Overlaps (const SelectMgr_Vec3& // ======================================================================= Standard_Boolean SelectMgr_TriangularFrustumSet::Overlaps (const SelectMgr_Vec3& theMinPnt, const SelectMgr_Vec3& theMaxPnt, - Standard_Boolean* /*theInside*/) const + Standard_Boolean* theInside) const { for (SelectMgr_TriangFrustumsIter anIter (myFrustums); anIter.More(); anIter.Next()) { if (anIter.Value()->Overlaps (theMinPnt, theMaxPnt, NULL)) - return Standard_True; + { + if (myToAllowOverlap || theInside == NULL) + { + return Standard_True; + } + else + { + gp_Pnt aMinMaxPnts[2] = { gp_Pnt (theMinPnt.x(), theMinPnt.y(), theMinPnt.z()), + gp_Pnt (theMaxPnt.x(), theMaxPnt.y(), theMaxPnt.z())}; + + gp_Pnt anOffset[3] = { gp_Pnt (aMinMaxPnts[1].X() - aMinMaxPnts[0].X(), 0.0, 0.0), + gp_Pnt (0.0, aMinMaxPnts[1].Y() - aMinMaxPnts[0].Y(), 0.0), + gp_Pnt (0.0, 0.0, aMinMaxPnts[1].Z() - aMinMaxPnts[0].Z()) }; + + Standard_Integer aSign = 1; + for (Standard_Integer aPntsIdx = 0; aPntsIdx < 2; aPntsIdx++) + { + for (Standard_Integer aCoordIdx = 0; aCoordIdx < 3; aCoordIdx++) + { + gp_Pnt anOffsetPnt = aMinMaxPnts [aPntsIdx].XYZ() + aSign * anOffset [aCoordIdx].XYZ(); + if (isIntersectBoundary (aMinMaxPnts [aPntsIdx], anOffsetPnt) + || isIntersectBoundary (anOffsetPnt, anOffsetPnt.XYZ() + aSign * anOffset [(aCoordIdx + 1) % 3].XYZ())) + { + *theInside &= Standard_False; + return Standard_True; + } + } + aSign = -aSign; + } + return Standard_True; + } + } } return Standard_False; @@ -185,7 +238,25 @@ Standard_Boolean SelectMgr_TriangularFrustumSet::Overlaps (const TColgp_Array1Of for (SelectMgr_TriangFrustumsIter anIter (myFrustums); anIter.More(); anIter.Next()) { if (anIter.Value()->Overlaps (theArrayOfPts, theSensType, theClipRange, thePickResult)) - return Standard_True; + { + if (myToAllowOverlap) + { + return Standard_True; + } + else + { + Standard_Integer aPtsLower = theArrayOfPts.Lower(); + Standard_Integer aPtsUpper = theArrayOfPts.Upper(); + for (Standard_Integer anIdx = aPtsLower; anIdx <= aPtsUpper; anIdx++) + { + if (isIntersectBoundary (theArrayOfPts.Value (anIdx), theArrayOfPts.Value (anIdx < aPtsUpper ? anIdx + 1 : aPtsLower))) + { + return Standard_False; + } + } + return Standard_True; + } + } } return Standard_False; @@ -203,7 +274,20 @@ Standard_Boolean SelectMgr_TriangularFrustumSet::Overlaps (const gp_Pnt& thePnt1 for (SelectMgr_TriangFrustumsIter anIter (myFrustums); anIter.More(); anIter.Next()) { if (anIter.Value()->Overlaps (thePnt1, thePnt2, theClipRange, thePickResult)) - return Standard_True; + { + if (myToAllowOverlap) + { + return Standard_True; + } + else + { + if (isIntersectBoundary (thePnt1, thePnt2)) + { + return Standard_False; + } + return Standard_True; + } + } } return Standard_False; @@ -223,7 +307,22 @@ Standard_Boolean SelectMgr_TriangularFrustumSet::Overlaps (const gp_Pnt& thePnt1 for (SelectMgr_TriangFrustumsIter anIter (myFrustums); anIter.More(); anIter.Next()) { if (anIter.Value()->Overlaps (thePnt1, thePnt2, thePnt3, theSensType, theClipRange, thePickResult)) - return Standard_True; + { + if (myToAllowOverlap) + { + return Standard_True; + } + else + { + if (isIntersectBoundary (thePnt1, thePnt2) + || isIntersectBoundary (thePnt2, thePnt3) + || isIntersectBoundary (thePnt3, thePnt1)) + { + return Standard_False; + } + return Standard_True; + } + } } return Standard_False; @@ -243,4 +342,83 @@ void SelectMgr_TriangularFrustumSet::GetPlanes (NCollection_Vector 1.0) + { + return Standard_False; + } + + aQVec = aTVec.Crossed (anEdge1); + aV = aInvD * theDir.Dot (aQVec); + if (aV < 0.0 || anU + aV > 1.0) + { + return Standard_False; + } + + aT = aInvD * anEdge2.Dot (aQVec); + if (aT < 0 || aT > 1) + { + return Standard_False; + } + + return Standard_True; +} + #undef MEMORY_BLOCK_SIZE diff --git a/src/SelectMgr/SelectMgr_TriangularFrustumSet.hxx b/src/SelectMgr/SelectMgr_TriangularFrustumSet.hxx index fc2d4c122c..08f4cb5b01 100644 --- a/src/SelectMgr/SelectMgr_TriangularFrustumSet.hxx +++ b/src/SelectMgr/SelectMgr_TriangularFrustumSet.hxx @@ -37,7 +37,7 @@ class SelectMgr_TriangularFrustumSet : public SelectMgr_BaseFrustum { public: - SelectMgr_TriangularFrustumSet() {}; + SelectMgr_TriangularFrustumSet(); ~SelectMgr_TriangularFrustumSet() {}; @@ -84,9 +84,24 @@ public: //! Ax + By + Cz + D = 0) to the given vector Standard_EXPORT virtual void GetPlanes (NCollection_Vector& thePlaneEquations) const Standard_OVERRIDE; + //! If theIsToAllow is false, only fully included sensitives will be detected, otherwise the algorithm will + //! mark both included and overlapped entities as matched + Standard_EXPORT virtual void SetAllowOverlapDetection (const Standard_Boolean theIsToAllow); + private: - SelectMgr_TriangFrustums myFrustums; + //! Checks whether the segment intersects with the boundary of the current volume selection + Standard_EXPORT Standard_Boolean isIntersectBoundary (const gp_Pnt& thePnt1, const gp_Pnt& thePnt2) const; + + //! Checks whether the triangle intersects with a segment + Standard_EXPORT Standard_Boolean segmentTriangleIntersection (const gp_Pnt &theOrig, const gp_Vec& theDir, + const gp_Pnt& theV1, const gp_Pnt& theV2, const gp_Pnt& theV3) const; + +private: + + SelectMgr_TriangFrustums myFrustums; + TColgp_Array1OfPnt myBoundaryPoints; + Standard_Boolean myToAllowOverlap; }; #endif // _SelectMgr_TriangularFrustumSet_HeaderFile diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 9bc02b1375..3ac07336ef 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -7635,12 +7635,7 @@ static Standard_Integer VSelect (Draw_Interpretor& , return 1; } } - if (toAllowOverlap - && aPnts.Length() != 2) - { - std::cout << "Syntax error: -allowoverlap key is applied only for rectangle selection\n"; - return 1; - } + if (toAllowOverlap) { aCtx->MainSelector()->AllowOverlapDetection (toAllowOverlap); @@ -14279,10 +14274,10 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) "- 1) single click selection\n" "- 2) selection with rectangle having corners at pixel positions (x1,y1) and (x2,y2)\n" "- 3) selection with polygon having corners in pixel positions (x1,y1), (x2,y2),...,(xn,yn)\n" - "- 4) -allowoverlap manages overlap and inclusion detection in rectangular selection.\n" - " If the flag is set to 1, both sensitives that were included completely and overlapped partially by defined rectangle will be detected,\n" - " otherwise algorithm will chose only fully included sensitives. Default behavior is to detect only full inclusion. " - " (partial inclusion - overlap - is not allowed by default)\n" + "- 4) -allowoverlap manages overlap and inclusion detection in rectangular and polygonal selection.\n" + " If the flag is set to 1, both sensitives that were included completely and overlapped partially by defined \n" + " rectangle or polygon will be detected, otherwise algorithm will chose only fully included sensitives.\n" + " Default behavior is to detect only full inclusion. (partial inclusion - overlap - is not allowed by default)\n" "- 5) any of these selections with shift button pressed", __FILE__, VSelect, group); theCommands.Add ("vmoveto", diff --git a/tests/bugs/vis/bug27008 b/tests/bugs/vis/bug27008 index 24a6bfdcf4..6a326d51f7 100644 --- a/tests/bugs/vis/bug27008 +++ b/tests/bugs/vis/bug27008 @@ -15,7 +15,7 @@ vsetdispmode m 2 vselmode m 8 1 vselect 0 0 409 409 0 409 -if { [vnbselected] != "56748" } { puts "Error: the number of selected elements differs for mode 8" } +if { [vnbselected] != "55607" } { puts "Error: the number of selected elements differs for mode 8" } vdump $imagedir/${casename}_mode_8.png vselect 0 0 diff --git a/tests/bugs/vis/bug31440 b/tests/bugs/vis/bug31440 new file mode 100644 index 0000000000..1d6a897eeb --- /dev/null +++ b/tests/bugs/vis/bug31440 @@ -0,0 +1,34 @@ +puts "============" +puts "0031440: Visualization - Impossible to make common behaviour for multi-selection in viewer" +puts "============" +puts "" + +vinit View1 +vpoint radP1 0 0 0 +vpoint radP2 50 50 0 +vpoint radP3 100 0 0 +vcircle circle radP1 radP2 radP3 1 +vfit + +vselect 50 300 150 300 150 100 50 100 +if {[vreadpixel 120 200 rgb name] != "DARKGOLDENROD"} { puts "ERROR: the circle is selected with no overlap mode activated" } +vselect 0 0 + +vselect 50 300 360 300 360 100 50 100 +if {[vreadpixel 120 200 rgb name] != "GRAY73"} { puts "ERROR: the circle is not selected" } +vselect 0 0 +vclear + +box b 0 0 0 1 1 1 +vdisplay b +vfit +vselmode b 2 1 +vviewparams -scale 500 + +vdrawparray line polylines v 10 9 0 v 400 9 0 v 400 209 0 v 200 109 0 v 10 209 0 v 10 9 0 +vdisplay line -2d +vsetcolor line red + +vselect 10 400 400 400 400 200 200 300 10 200 + +vdump ${imagedir}/${casename}.png