From: oan Date: Tue, 15 Nov 2022 11:39:00 +0000 (+0300) Subject: 0031586: BRepMesh hangs up X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=8c3e6633b8ca308490108da6bec54c474498e873;p=occt.git 0031586: BRepMesh hangs up Use NCollection_UBTree to detect intersections between newly added links and contour of the polygon; Perform check of the solutions for link insertion after all possible solutions are found and sorted according to their priority. --- diff --git a/src/BRepMesh/BRepMesh_Delaun.cxx b/src/BRepMesh/BRepMesh_Delaun.cxx index 0aa1eeb2ba..ef9f657b12 100644 --- a/src/BRepMesh/BRepMesh_Delaun.cxx +++ b/src/BRepMesh/BRepMesh_Delaun.cxx @@ -76,8 +76,137 @@ namespace { theBox.Add( thePnt2 ); theBox.Enlarge(Precision); } + + //============================================================================= + //function : IntSegSeg + //purpose : Checks intersection between the two segments. + //============================================================================= + BRepMesh_GeomTool::IntFlag IntSegSeg( + const Handle(BRepMesh_DataStructureOfDelaun)& theMeshData, + const BRepMesh_Edge& theEdg1, + const BRepMesh_Edge& theEdg2, + const Standard_Boolean isConsiderEndPointTouch, + const Standard_Boolean isConsiderPointOnEdge, + gp_Pnt2d& theIntPnt) + { + gp_XY p1, p2, p3, p4; + p1 = theMeshData->GetNode( theEdg1.FirstNode() ).Coord(); + p2 = theMeshData->GetNode( theEdg1.LastNode () ).Coord(); + p3 = theMeshData->GetNode( theEdg2.FirstNode() ).Coord(); + p4 = theMeshData->GetNode( theEdg2.LastNode () ).Coord(); + + return BRepMesh_GeomTool::IntSegSeg( p1, p2, p3, p4, + isConsiderEndPointTouch, isConsiderPointOnEdge, theIntPnt ); + } } // anonymous namespace +//! Checks polygon links for intersection with current one of the same polygon. +class BRepMesh_Delaun::EBTreeOfB2d_Selector : + public NCollection_EBTree::Selector +{ +public: + //! Constructor. + EBTreeOfB2d_Selector( + const Handle(BRepMesh_DataStructureOfDelaun)& theMeshData, + const DataMapOfPVoid& theSegmentsPolyMap, + const Standard_Boolean isConsiderEndPointTouch = Standard_False, + const Standard_Boolean isConsiderPointOnEdge = Standard_False) + : myMeshData ( theMeshData ), + mySegmentsPolyMap ( theSegmentsPolyMap ), + myConsiderEndPointTouch ( isConsiderEndPointTouch ), + myConsiderPointOnEdge ( isConsiderPointOnEdge ), + myPolygonPtr ( nullptr ) + { + } + + //! Implementation of rejection method + //! @return + //! True if the bounding box does not intersect with the current + virtual Standard_Boolean Reject (const Bnd_B2d& theBox) const + { + return (myBox.IsOut( theBox )); + } + + //! Implementation of acceptance method + //! This method is called when the bounding box intersect with the current. + //! It stores the object - the index of box in the list of accepted objects. + //! @return + //! True, because the object is accepted + virtual Standard_Boolean Accept (const Standard_Integer& theObj) + { + if (mySkipLinks.Contains( theObj )) + { + return Standard_False; + } + + auto aPtr = mySegmentsPolyMap.Seek( theObj ); + + if (aPtr != nullptr && *aPtr == myPolygonPtr) + { + const BRepMesh_Edge& aPolyLink = myMeshData->GetLink( Abs( theObj ) ); + + if (!myLink.IsEqual( aPolyLink )) + { + // intersection is possible... + gp_Pnt2d anIntPnt; + BRepMesh_GeomTool::IntFlag aIntFlag = IntSegSeg( + myMeshData, myLink, aPolyLink, + myConsiderEndPointTouch, myConsiderPointOnEdge, anIntPnt ); + + myStop = (aIntFlag != BRepMesh_GeomTool::NoIntersection); + return myStop; + } + } + + return Standard_False; + } + + //! Set current box to search for overlapping with him + void SetCurrent (const BRepMesh_Edge& theLink, + const Bnd_B2d& theBox, + const void* thePolygonPtr) + { + mySkipLinks.Clear(); + + myStop = Standard_False; + myLink = theLink; + myBox = theBox; + myPolygonPtr = thePolygonPtr; + } + + void SetSkipLink(const int theLink) + { + mySkipLinks.Add( theLink ); + } + + template + void SetSkipLink( const int theLink, const T... theLinks ) + { + SetSkipLink( theLink ); + SetSkipLink( theLinks... ); + } + + //! Returns true if the current segment intersects another one of the same polygon. + Standard_Boolean IsIntersected() + { + return myStop; + } + +protected: + const Handle(BRepMesh_DataStructureOfDelaun)& myMeshData; + const DataMapOfPVoid& mySegmentsPolyMap; + + const Standard_Boolean myConsiderEndPointTouch; + const Standard_Boolean myConsiderPointOnEdge; + + const void* myPolygonPtr; + + BRepMesh_Edge myLink; + Bnd_B2d myBox; + + NCollection_Map mySkipLinks; +}; + //======================================================================= //function : BRepMesh_Delaun //purpose : @@ -1883,24 +2012,31 @@ void BRepMesh_Delaun::meshPolygon(IMeshData::SequenceOfInteger& thePolygon, } } - IMeshData::SequenceOfInteger* aPolygon1 = &thePolygon; - IMeshData::SequenceOfBndB2d* aPolyBoxes1 = &thePolyBoxes; + SegmentsBoxes aSegmentsBoxes; + EBTreeOfB2dFiller aTreeFiller( aSegmentsBoxes.Boxes ); + + Standard_Integer aLinkIt = thePolygon.Lower(); + for (; aLinkIt <= thePolygon.Upper(); ++aLinkIt) + { + const Standard_Integer aLinkInfo = thePolygon( aLinkIt ); + + aTreeFiller .Add (aLinkInfo, thePolyBoxes( aLinkIt )); + aSegmentsBoxes.Rebind(aLinkInfo, &thePolygon); + } + aTreeFiller.Fill(); - Handle(IMeshData::SequenceOfInteger) aPolygon2 = new IMeshData::SequenceOfInteger; - Handle(IMeshData::SequenceOfBndB2d) aPolyBoxes2 = new IMeshData::SequenceOfBndB2d; + IMeshData::SequenceOfInteger* aPolygon1 = &thePolygon; + Handle(IMeshData::SequenceOfInteger) aPolygon2 = new IMeshData::SequenceOfInteger; NCollection_Sequence aPolyStack; - NCollection_Sequence aPolyBoxStack; for (;;) { - decomposeSimplePolygon(*aPolygon1, *aPolyBoxes1, *aPolygon2, *aPolyBoxes2); + decomposeSimplePolygon(*aPolygon1, *aPolygon2, aSegmentsBoxes); if (!aPolygon2->IsEmpty()) { aPolyStack.Append(aPolygon2); - aPolyBoxStack.Append(aPolyBoxes2); - aPolygon2 = new IMeshData::SequenceOfInteger; - aPolyBoxes2 = new IMeshData::SequenceOfBndB2d; + aPolygon2 = new IMeshData::SequenceOfInteger; } if (aPolygon1->IsEmpty()) @@ -1908,14 +2044,12 @@ void BRepMesh_Delaun::meshPolygon(IMeshData::SequenceOfInteger& thePolygon, if (!aPolyStack.IsEmpty() && aPolygon1 == &(*aPolyStack.First())) { aPolyStack.Remove(1); - aPolyBoxStack.Remove(1); } if (aPolyStack.IsEmpty()) break; - aPolygon1 = &(*aPolyStack.ChangeFirst()); - aPolyBoxes1 = &(*aPolyBoxStack.ChangeFirst()); + aPolygon1 = &(*aPolyStack.ChangeFirst()); } } } @@ -1964,17 +2098,54 @@ Standard_Boolean BRepMesh_Delaun::meshElementaryPolygon( //function : meshSimplePolygon //purpose : //======================================================================= +namespace +{ + struct Candidate + { + Standard_Integer PivotNode; + Standard_Integer LinkId; + Standard_Real Dist; + Standard_Real Angle; + + Candidate() + : PivotNode (0), + LinkId (0), + Dist (RealLast()), + Angle (0.) + { + } + + Candidate(const Standard_Integer thePivotNode, + const Standard_Integer theLinkId, + const Standard_Real theDist, + const Standard_Real theAngle) + : PivotNode (thePivotNode), + LinkId (theLinkId), + Dist (theDist), + Angle (theAngle) + { + } + + bool operator<(const Candidate& theOther) const + { + const bool isWorse = ((Dist >= theOther.Dist) && + (Angle <= theOther.Angle || Angle > AngDeviation90Deg)); + + return !isWorse; + } + }; +} + void BRepMesh_Delaun::decomposeSimplePolygon( IMeshData::SequenceOfInteger& thePolygon, - IMeshData::SequenceOfBndB2d& thePolyBoxes, IMeshData::SequenceOfInteger& thePolygonCut, - IMeshData::SequenceOfBndB2d& thePolyBoxesCut) + SegmentsBoxes& theSegmentsBoxes) { // Check is the given polygon elementary if ( meshElementaryPolygon( thePolygon ) ) { + theSegmentsBoxes.Rebind( thePolygon, nullptr ); thePolygon.Clear(); - thePolyBoxes.Clear(); return; } @@ -1994,8 +2165,8 @@ void BRepMesh_Delaun::decomposeSimplePolygon( Standard_Real aRefEdgeLen = aRefEdgeDir.Magnitude(); if ( aRefEdgeLen < Precision ) { + theSegmentsBoxes.Rebind( thePolygon, nullptr ); thePolygon.Clear(); - thePolyBoxes.Clear(); return; } @@ -2003,19 +2174,16 @@ void BRepMesh_Delaun::decomposeSimplePolygon( // Find a point with minimum distance respect // the end of reference link - Standard_Integer aUsedLinkId = 0; - Standard_Real aOptAngle = 0.0; - Standard_Real aMinDist = RealLast(); - Standard_Integer aPivotNode = aNodes[1]; - Standard_Integer aPolyLen = thePolygon.Length(); - for ( Standard_Integer aLinkIt = 3; aLinkIt <= aPolyLen; ++aLinkIt ) + NCollection_Vector aCandidates( thePolygon.Length() ); + + for ( Standard_Integer aLinkIt = 3; aLinkIt <= thePolygon.Length(); ++aLinkIt ) { - Standard_Integer aLinkInfo = thePolygon( aLinkIt ); - const BRepMesh_Edge& aNextEdge = GetEdge( Abs( aLinkInfo ) ); + const Standard_Integer aLinkInfo = thePolygon( aLinkIt ); + const BRepMesh_Edge& aNextEdge = GetEdge( Abs( aLinkInfo ) ); - aPivotNode = aLinkInfo > 0 ? + const Standard_Integer aPivotNode = aLinkInfo > 0 ? aNextEdge.FirstNode() : - aNextEdge.LastNode(); + aNextEdge.LastNode (); // We have end points touch case in the polygon - ignore it if (aPivotNode == aNodes[1]) @@ -2025,55 +2193,43 @@ void BRepMesh_Delaun::decomposeSimplePolygon( gp_Vec2d aDistanceDir( aRefVertices[1], aPivotVertex ); Standard_Real aDist = aRefEdgeDir ^ aDistanceDir; - Standard_Real aAngle = Abs( aRefEdgeDir.Angle(aDistanceDir) ); + Standard_Real aAngle = Abs( aRefEdgeDir.Angle( aDistanceDir ) ); Standard_Real anAbsDist = Abs( aDist ); if (anAbsDist < Precision || aDist < 0.) continue; - if ( ( anAbsDist >= aMinDist ) && - ( aAngle <= aOptAngle || aAngle > AngDeviation90Deg ) ) - { - continue; - } + aCandidates.Append( Candidate{ aPivotNode, aLinkIt, anAbsDist, aAngle }); + } + + std::sort( aCandidates.begin(), aCandidates.end() ); + + Standard_Integer aUsedLinkId = 0; + EBTreeOfB2d_Selector aSelector( myMeshData, theSegmentsBoxes.PolyMap ); + + Standard_Integer aCandIt = aCandidates.Lower(); + for (; aCandIt <= aCandidates.Upper(); ++aCandIt) + { + const Candidate& aCand = aCandidates.Value( aCandIt ); + + const gp_Pnt2d& aPivotVertex = GetVertex( aCand.PivotNode ).Coord(); // Check is the test link crosses the polygon boundaries Standard_Boolean isIntersect = Standard_False; for ( Standard_Integer aRefLinkNodeIt = 0; aRefLinkNodeIt < 2; ++aRefLinkNodeIt ) { - const Standard_Integer& aLinkFirstNode = aNodes[aRefLinkNodeIt]; + const Standard_Integer& aLinkFirstNode = aNodes [aRefLinkNodeIt]; const gp_Pnt2d& aLinkFirstVertex = aRefVertices[aRefLinkNodeIt]; Bnd_B2d aBox; - UpdateBndBox(aLinkFirstVertex.Coord(), aPivotVertex.Coord(), aBox); + UpdateBndBox( aLinkFirstVertex.Coord(), aPivotVertex.Coord(), aBox ); - BRepMesh_Edge aCheckLink( aLinkFirstNode, aPivotNode, BRepMesh_Free ); + BRepMesh_Edge aCheckLink( aLinkFirstNode, aCand.PivotNode, BRepMesh_Free ); - Standard_Integer aCheckLinkIt = 2; - for ( ; aCheckLinkIt <= aPolyLen; ++aCheckLinkIt ) - { - if( aCheckLinkIt == aLinkIt ) - continue; - - if ( !aBox.IsOut( thePolyBoxes.Value( aCheckLinkIt ) ) ) - { - const BRepMesh_Edge& aPolyLink = - GetEdge( Abs( thePolygon( aCheckLinkIt ) ) ); + aSelector.SetCurrent ( aCheckLink, aBox, &thePolygon ); + aSelector.SetSkipLink( thePolygon.First(), thePolygon( aCand.LinkId ) ); - if ( aCheckLink.IsEqual( aPolyLink ) ) - continue; - - // intersection is possible... - gp_Pnt2d anIntPnt; - BRepMesh_GeomTool::IntFlag aIntFlag = intSegSeg( aCheckLink, aPolyLink, - Standard_False, Standard_False, anIntPnt ); - - if( aIntFlag != BRepMesh_GeomTool::NoIntersection ) - { - isIntersect = Standard_True; - break; - } - } - } + theSegmentsBoxes.Boxes.Select( aSelector ); + isIntersect = aSelector.IsIntersected(); if ( isIntersect ) break; @@ -2083,17 +2239,16 @@ void BRepMesh_Delaun::decomposeSimplePolygon( continue; - aOptAngle = aAngle; - aMinDist = anAbsDist; - aNodes[2] = aPivotNode; + aNodes [2] = aCand.PivotNode; aRefVertices[2] = aPivotVertex; - aUsedLinkId = aLinkIt; + aUsedLinkId = aCand.LinkId; + break; } if ( aUsedLinkId == 0 ) { + theSegmentsBoxes.Rebind( thePolygon, nullptr ); thePolygon.Clear(); - thePolyBoxes.Clear(); return; } @@ -2112,48 +2267,49 @@ void BRepMesh_Delaun::decomposeSimplePolygon( for ( Standard_Integer aTriEdgeIt = 0; aTriEdgeIt < 3; ++aTriEdgeIt ) { const Standard_Integer& anEdgeInfo = aNewEdgesInfo[aTriEdgeIt]; - anEdges[aTriEdgeIt] = Abs( anEdgeInfo ); + anEdges [aTriEdgeIt] = Abs( anEdgeInfo ); anEdgesOri[aTriEdgeIt] = anEdgeInfo > 0; } addTriangle( anEdges, anEdgesOri, aNodes ); if (aUsedLinkId == 3) { - thePolygon.Remove ( 1 ); - thePolyBoxes.Remove( 1 ); + theSegmentsBoxes.Rebind( thePolygon.First(), nullptr ); + thePolygon .Remove( 1 ); thePolygon.SetValue( 1, -aNewEdgesInfo[2] ); Bnd_B2d aBox; - UpdateBndBox(aRefVertices[0].Coord(), aRefVertices[2].Coord(), aBox); - thePolyBoxes.SetValue( 1, aBox ); + UpdateBndBox( aRefVertices[0].Coord(), aRefVertices[2].Coord(), aBox ); + theSegmentsBoxes.Add( thePolygon.First(), aBox, &thePolygon ); } else { // Create triangle and split the source polygon on two // parts (if possible) and mesh each part as independent // polygon. - if ( aUsedLinkId < aPolyLen ) + if ( aUsedLinkId < thePolygon.Length() ) { - thePolygon.Split(aUsedLinkId, thePolygonCut); - thePolygonCut.Prepend( -aNewEdgesInfo[2] ); - thePolyBoxes.Split(aUsedLinkId, thePolyBoxesCut); + thePolygon.Split( aUsedLinkId, thePolygonCut ); + + theSegmentsBoxes.Rebind ( thePolygonCut, &thePolygonCut ); + thePolygonCut .Prepend( -aNewEdgesInfo[2] ); Bnd_B2d aBox; - UpdateBndBox(aRefVertices[0].Coord(), aRefVertices[2].Coord(), aBox); - thePolyBoxesCut.Prepend( aBox ); + UpdateBndBox( aRefVertices[0].Coord(), aRefVertices[2].Coord(), aBox ); + theSegmentsBoxes.Add( thePolygonCut.First(), aBox, &thePolygonCut ); } else { - thePolygon.Remove ( aPolyLen ); - thePolyBoxes.Remove( aPolyLen ); + theSegmentsBoxes.Rebind( thePolygon.Last (), nullptr ); + thePolygon .Remove( thePolygon.Length() ); } thePolygon.SetValue( 1, -aNewEdgesInfo[1] ); Bnd_B2d aBox; - UpdateBndBox(aRefVertices[1].Coord(), aRefVertices[2].Coord(), aBox); - thePolyBoxes.SetValue( 1, aBox ); + UpdateBndBox( aRefVertices[1].Coord(), aRefVertices[2].Coord(), aBox ); + theSegmentsBoxes.Add( thePolygon.First(), aBox, &thePolygon ); } } @@ -2477,13 +2633,7 @@ BRepMesh_GeomTool::IntFlag BRepMesh_Delaun::intSegSeg( const Standard_Boolean isConsiderPointOnEdge, gp_Pnt2d& theIntPnt) const { - gp_XY p1, p2, p3, p4; - p1 = GetVertex( theEdg1.FirstNode() ).Coord(); - p2 = GetVertex( theEdg1.LastNode() ).Coord(); - p3 = GetVertex( theEdg2.FirstNode() ).Coord(); - p4 = GetVertex( theEdg2.LastNode() ).Coord(); - - return BRepMesh_GeomTool::IntSegSeg(p1, p2, p3, p4, + return IntSegSeg (myMeshData, theEdg1, theEdg2, isConsiderEndPointTouch, isConsiderPointOnEdge, theIntPnt); } diff --git a/src/BRepMesh/BRepMesh_Delaun.hxx b/src/BRepMesh/BRepMesh_Delaun.hxx index fb575548b2..b728055d33 100755 --- a/src/BRepMesh/BRepMesh_Delaun.hxx +++ b/src/BRepMesh/BRepMesh_Delaun.hxx @@ -165,6 +165,42 @@ private: }; typedef NCollection_DataMap DataMapOfMap; + typedef NCollection_DataMap DataMapOfPVoid; + typedef NCollection_EBTree EBTreeOfB2d; + typedef NCollection_UBTreeFiller EBTreeOfB2dFiller; + class EBTreeOfB2d_Selector; + + struct SegmentsBoxes + { + EBTreeOfB2d Boxes; + DataMapOfPVoid PolyMap; + + void Rebind (const Standard_Integer theLinkInfo, + void* const& thePolygonPtr) + { + PolyMap.Bind (theLinkInfo, thePolygonPtr); + } + + void Rebind (IMeshData::SequenceOfInteger& thePolygon, + void* const& thePolygonPtr) + { + Standard_Integer aLinkIt = thePolygon.Lower(); + for (; aLinkIt <= thePolygon.Upper(); ++aLinkIt) + { + const Standard_Integer aLinkInfo = thePolygon (aLinkIt); + Rebind (aLinkInfo, thePolygonPtr); + } + } + + void Add (const Standard_Integer theLinkInfo, + const Bnd_B2d& theBox, + void* const& thePolygonPtr) + { + PolyMap.Bind (theLinkInfo, thePolygonPtr); + Boxes .Add (theLinkInfo, theBox); + } + }; + //! Performs initialization of circles cell filter tool. void initCirclesTool (const Bnd_Box2d& theBox, @@ -245,14 +281,12 @@ private: //! In case if source polygon consists of three links, creates new triangle //! and clears source container. //! @param thePolygon source polygon to be decomposed (first part of decomposition). - //! @param thePolyBoxes bounding boxes corresponded to source polygon's links. //! @param thePolygonCut product of decomposition of source polygon (second part of decomposition). - //! @param thePolyBoxesCut bounding boxes corresponded to resulting polygon's links. + //! @param theSegmentsBoxes map of relations between semgents and their polygons. void decomposeSimplePolygon ( IMeshData::SequenceOfInteger& thePolygon, - IMeshData::SequenceOfBndB2d& thePolyBoxes, IMeshData::SequenceOfInteger& thePolygonCut, - IMeshData::SequenceOfBndB2d& thePolyBoxesCut); + SegmentsBoxes& theSegmentsBoxes); //! Triangulation of closed polygon containing only three edges. Standard_Boolean meshElementaryPolygon (const IMeshData::SequenceOfInteger& thePolygon); diff --git a/tests/bugs/mesh/bug31586 b/tests/bugs/mesh/bug31586 new file mode 100644 index 0000000000..a8ef89179c --- /dev/null +++ b/tests/bugs/mesh/bug31586 @@ -0,0 +1,14 @@ +puts "========" +puts "0031586: BRepMesh hangs up" +puts "========" +puts "" + +puts "TODO OCC31586 All: Not connected mesh inside face" + +restore [locate_data_file bug31586.brep] result + +incmesh result 0.022627417117969499 + +checkview -display result -3d -path ${imagedir}/${test_image}.png + +tricheck result