]> OCCT Git - occt.git/commitdiff
0031586: BRepMesh hangs up
authoroan <oan@opencascade.com>
Wed, 9 Nov 2022 14:57:30 +0000 (17:57 +0300)
committeroan <oan@opencascade.com>
Wed, 9 Nov 2022 15:19:38 +0000 (18:19 +0300)
Use NCollection_UBTree to detect intersections between newly added links and contour of the polygon

src/BRepMesh/BRepMesh_Delaun.cxx
src/BRepMesh/BRepMesh_Delaun.hxx

index 0aa1eeb2bab2fcb502cbc4dbe44f4ca8d8a63490..2abbed47c1590f1b6bdcfe3fa07dd3b30fe417db 100644 (file)
@@ -76,8 +76,128 @@ 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::UBTreeOfB2d_Selector : public NCollection_UBTree<Standard_Integer, Bnd_B2d>::Selector
+{
+public:
+  //! Constructor.
+  UBTreeOfB2d_Selector(
+    const Handle(BRepMesh_DataStructureOfDelaun)& theMeshData,
+    const DataMapOfPVoid&                         theSegmentsPolyMap)
+    : myMeshData        (theMeshData),
+      mySegmentsPolyMap (theSegmentsPolyMap),
+      myPolygonPtr      (nullptr)
+  {
+  }
+
+  //! Implementation of rejection method
+  //! @return
+  //!   True if the bounding box does not intersect with the current 
+  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
+  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,
+          Standard_False, Standard_False, 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<typename... T>
+  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;
+  }
+
+private:
+  const Handle(BRepMesh_DataStructureOfDelaun)& myMeshData;
+  const DataMapOfPVoid&                         mySegmentsPolyMap;
+
+  BRepMesh_Edge                                 myLink;
+  Bnd_B2d                                       myBox;
+  const void*                                   myPolygonPtr;
+
+  NCollection_Map<Standard_Integer>             mySkipLinks;
+};
+
 //=======================================================================
 //function : BRepMesh_Delaun
 //purpose  : 
@@ -1883,24 +2003,31 @@ void BRepMesh_Delaun::meshPolygon(IMeshData::SequenceOfInteger&   thePolygon,
     }
   }
 
-  IMeshData::SequenceOfInteger* aPolygon1   = &thePolygon;
-  IMeshData::SequenceOfBndB2d*  aPolyBoxes1 = &thePolyBoxes;
+  SegmentsBoxes     aSegmentsBoxes;
+  UBTreeOfB2dFiller aTreeFiller (aSegmentsBoxes.Boxes);
 
-  Handle(IMeshData::SequenceOfInteger) aPolygon2   = new IMeshData::SequenceOfInteger;
-  Handle(IMeshData::SequenceOfBndB2d)  aPolyBoxes2 = new IMeshData::SequenceOfBndB2d;
+  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();
+
+  IMeshData::SequenceOfInteger*        aPolygon1 = &thePolygon;
+  Handle(IMeshData::SequenceOfInteger) aPolygon2 = new IMeshData::SequenceOfInteger;
 
   NCollection_Sequence<Handle(IMeshData::SequenceOfInteger)> aPolyStack;
-  NCollection_Sequence<Handle(IMeshData::SequenceOfBndB2d)>  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 +2035,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());
     }
   }
 }
@@ -1966,15 +2091,14 @@ Standard_Boolean BRepMesh_Delaun::meshElementaryPolygon(
 //=======================================================================
 void BRepMesh_Delaun::decomposeSimplePolygon(
   IMeshData::SequenceOfInteger& thePolygon,
-  IMeshData::SequenceOfBndB2d&  thePolyBoxes,
   IMeshData::SequenceOfInteger& thePolygonCut,
-  IMeshData::SequenceOfBndB2d&  thePolyBoxesCut)
+  SegmentsBoxes&                theSegmentsPolyMap)
 {
   // Check is the given polygon elementary
   if ( meshElementaryPolygon( thePolygon ) )
   {
+    theSegmentsPolyMap.Rebind (thePolygon, nullptr);
     thePolygon.Clear();
-    thePolyBoxes.Clear();
     return;
   }
 
@@ -1994,13 +2118,15 @@ void BRepMesh_Delaun::decomposeSimplePolygon(
   Standard_Real aRefEdgeLen = aRefEdgeDir.Magnitude();
   if ( aRefEdgeLen < Precision )
   {
+    theSegmentsPolyMap.Rebind (thePolygon, nullptr);
     thePolygon.Clear();
-    thePolyBoxes.Clear();
     return;
   }
 
   aRefEdgeDir /= aRefEdgeLen;
 
+  UBTreeOfB2d_Selector aSelector (myMeshData, theSegmentsPolyMap.PolyMap);
+
   // Find a point with minimum distance respect
   // the end of reference link
   Standard_Integer aUsedLinkId = 0;
@@ -2010,8 +2136,8 @@ void BRepMesh_Delaun::decomposeSimplePolygon(
   Standard_Integer aPolyLen    = thePolygon.Length();
   for ( Standard_Integer aLinkIt = 3; aLinkIt <= aPolyLen; ++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 ? 
       aNextEdge.FirstNode() : 
@@ -2048,32 +2174,11 @@ void BRepMesh_Delaun::decomposeSimplePolygon(
 
       BRepMesh_Edge aCheckLink( aLinkFirstNode, aPivotNode, 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(), aLinkInfo);
 
-          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;
-          }
-        }
-      }
+      theSegmentsPolyMap.Boxes.Select (aSelector);
+      isIntersect = aSelector.IsIntersected();
 
       if ( isIntersect )
         break;
@@ -2092,8 +2197,8 @@ void BRepMesh_Delaun::decomposeSimplePolygon(
 
   if ( aUsedLinkId == 0 )
   {
+    theSegmentsPolyMap.Rebind (thePolygon, nullptr);
     thePolygon.Clear();
-    thePolyBoxes.Clear();
     return;
   }
 
@@ -2119,14 +2224,14 @@ void BRepMesh_Delaun::decomposeSimplePolygon(
 
   if (aUsedLinkId == 3)
   {
-    thePolygon.Remove  ( 1 );
-    thePolyBoxes.Remove( 1 );
+    theSegmentsPolyMap.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 );
+    theSegmentsPolyMap.Add (thePolygon.First(), aBox, &thePolygon);
   }
   else
   {
@@ -2136,24 +2241,26 @@ void BRepMesh_Delaun::decomposeSimplePolygon(
     if ( aUsedLinkId < aPolyLen )
     {
       thePolygon.Split(aUsedLinkId, thePolygonCut);
+
+      theSegmentsPolyMap.Rebind (thePolygonCut, &thePolygonCut);
+
       thePolygonCut.Prepend( -aNewEdgesInfo[2] );
-      thePolyBoxes.Split(aUsedLinkId, thePolyBoxesCut);
 
       Bnd_B2d aBox;
       UpdateBndBox(aRefVertices[0].Coord(), aRefVertices[2].Coord(), aBox);
-      thePolyBoxesCut.Prepend( aBox );
+      theSegmentsPolyMap.Add (thePolygonCut.First(), aBox, &thePolygonCut);
     }
     else
     {
+      theSegmentsPolyMap.Rebind(thePolygon.Last(), nullptr);
       thePolygon.Remove  ( aPolyLen );
-      thePolyBoxes.Remove( aPolyLen );
     }
 
-    thePolygon.SetValue( 1, -aNewEdgesInfo[1] );
+    thePolygon.SetValue (1, -aNewEdgesInfo[1]);
 
     Bnd_B2d aBox;
     UpdateBndBox(aRefVertices[1].Coord(), aRefVertices[2].Coord(), aBox);
-    thePolyBoxes.SetValue( 1, aBox );
+    theSegmentsPolyMap.Add (thePolygon.First(), aBox, &thePolygon);
   }
 }
 
@@ -2477,13 +2584,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);
 }
 
index fb575548b2c583267d02a16d075e037abb0566d8..801f3cd5f17c35db5d8069558a5a8dcea7381759 100755 (executable)
@@ -165,6 +165,42 @@ private:
   };
 
   typedef NCollection_DataMap<Standard_Integer, IMeshData::MapOfInteger> DataMapOfMap;
+  typedef NCollection_DataMap<Standard_Integer, void*>                   DataMapOfPVoid;
+  typedef NCollection_UBTree <Standard_Integer, Bnd_B2d>                 UBTreeOfB2d;
+  typedef NCollection_UBTreeFiller <Standard_Integer, Bnd_B2d>           UBTreeOfB2dFiller;
+  class UBTreeOfB2d_Selector;
+
+  struct SegmentsBoxes
+  {
+    UBTreeOfB2d    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 theSegmentsPolyMap map of relations between semgents and their polygons.
   void decomposeSimplePolygon (
     IMeshData::SequenceOfInteger& thePolygon,
-    IMeshData::SequenceOfBndB2d&  thePolyBoxes,
     IMeshData::SequenceOfInteger& thePolygonCut,
-    IMeshData::SequenceOfBndB2d&  thePolyBoxesCut);
+    SegmentsBoxes&                theSegmentsPolyMap);
 
   //! Triangulation of closed polygon containing only three edges.
   Standard_Boolean meshElementaryPolygon (const IMeshData::SequenceOfInteger& thePolygon);