Salome HOME
Fix CRASH after mesh.RemoveGroupWithContents( group_of_other_mesh )
[modules/smesh.git] / src / SMESHUtils / SMESH_Offset.cxx
index 29aed953721c6242636c119e975c22a26899909c..34e3c9d26bdd7991452a30c7ff4cc85884a86a64 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2019  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -141,11 +141,11 @@ namespace
     EdgeLoop() : SMDS_PolygonalFaceOfNodes( std::vector<const SMDS_MeshNode *>() ) {}
     void Clear() { myLinks.clear(); myIsBndConnected = false; myHasPending = false; }
     bool SetConnected() { bool was = myIsBndConnected; myIsBndConnected = true; return !was; }
-    bool Contains( const SMDS_MeshNode* n ) const
+    size_t Contains( const SMDS_MeshNode* n ) const
     {
       for ( size_t i = 0; i < myLinks.size(); ++i )
-        if ( myLinks[i]->myNode1 == n ) return true;
-      return false;
+        if ( myLinks[i]->myNode1 == n ) return i + 1;
+      return 0;
     }
     virtual int NbNodes() const { return myLinks.size(); }
     virtual SMDS_ElemIteratorPtr nodesIterator() const
@@ -224,6 +224,24 @@ namespace
         myLoopOfEdge[ Index( *loop->myLinks[ iE ] )] = 0;
       loop->Clear();
     }
+    void Join( EdgeLoop& loop1, size_t iAfterConcact,
+               EdgeLoop& loop2, size_t iFromEdge2 )
+    {
+      std::vector< const EdgePart* > linksAfterContact( loop1.myLinks.begin() + iAfterConcact,
+                                                        loop1.myLinks.end() );
+      loop1.myLinks.reserve( loop2.myLinks.size() + loop1.myLinks.size() );
+      loop1.myLinks.resize( iAfterConcact );
+      loop1.myLinks.insert( loop1.myLinks.end(),
+                            loop2.myLinks.begin() + iFromEdge2, loop2.myLinks.end() );
+      loop1.myLinks.insert( loop1.myLinks.end(),
+                            loop2.myLinks.begin(), loop2.myLinks.begin() + iFromEdge2 );
+      loop1.myLinks.insert( loop1.myLinks.end(),
+                            linksAfterContact.begin(), linksAfterContact.end() );
+      loop1.myIsBndConnected = loop2.myIsBndConnected;
+      loop2.Clear();
+      for ( size_t iE = 0; iE < loop1.myLinks.size(); ++iE )
+        myLoopOfEdge[ Index( *loop1.myLinks[ iE ] )] = & loop1;
+    }
     size_t    Index( const EdgePart& edge ) const { return &edge - myEdge0; }
     EdgeLoop* GetLoopOf( const EdgePart* edge ) { return myLoopOfEdge[ Index( *edge )]; }
   };
@@ -741,10 +759,7 @@ namespace SMESH_MeshAlgos
                        const double     theSign,
                        const bool       theOptimize );
 
-    //! Cut a face by planes, whose normals point to parts to keep
-    bool CutByPlanes(const SMDS_MeshElement*        face,
-                     const std::vector< gp_Ax1 > &  planes,
-                     std::vector< SMESH_NodeXYZ > & newConnectivity );
+    void IntersectNewEdges( const CutFace& theCFace );
 
   private:
 
@@ -797,7 +812,6 @@ namespace SMESH_MeshAlgos
                             bool &      isCollinear  );
     bool intersectEdgeEdge( int iE1, int iE2, IntPoint2D& intPoint );
     bool isPointInTriangle( const gp_XYZ& p, const std::vector< SMESH_NodeXYZ >& nodes );
-    void intersectNewEdges( const CutFace& theCFace );
     const SMDS_MeshNode* createNode( const gp_XYZ& p );
   };
 
@@ -1644,7 +1658,7 @@ namespace SMESH_MeshAlgos
    */
   //================================================================================
 
-  void Intersector::Algo::intersectNewEdges( const CutFace& cf )
+  void Intersector::Algo::IntersectNewEdges( const CutFace& cf )
   {
     IntPoint2D intPoint;
 
@@ -1841,7 +1855,7 @@ namespace SMESH_MeshAlgos
           }
         }
         if ( cf.myLinks.size() >= limit )
-          throw SALOME_Exception( "Infinite loop in Intersector::Algo::intersectNewEdges()" );
+          throw SALOME_Exception( "Infinite loop in Intersector::Algo::IntersectNewEdges()" );
       }
       ++i1; // each internal edge encounters twice
     }
@@ -1895,7 +1909,7 @@ namespace SMESH_MeshAlgos
     {
       const CutFace& cf = *cutFacesIt;
       cf.ReplaceNodes( myRemove2KeepNodes );
-      intersectNewEdges( cf );
+      IntersectNewEdges( cf );
     }
 
     // make new faces
@@ -1930,7 +1944,7 @@ namespace SMESH_MeshAlgos
       // avoid loops that are not connected to boundary edges of cf.myInitFace
       if ( cf.RemoveInternalLoops( loopSet ))
       {
-        intersectNewEdges( cf );
+        IntersectNewEdges( cf );
         cf.MakeLoops( loopSet, normal );
       }
       // erase loops that are cut off by face intersections
@@ -2210,6 +2224,10 @@ namespace SMESH_MeshAlgos
         theNewFaceConnectivity.push_back( facePoints );
         break;
       }
+
+      // intersect cut lines
+      algo.IntersectNewEdges( cf );
+
       // form loops of new faces
       EdgeLoopSet loopSet;
       cf.MakeLoops( loopSet, normals[ faceToCut->GetID() ]);
@@ -2373,8 +2391,9 @@ namespace
           // if ( !myLinks[i].IsInternal() )
           //   myLinks[ i ].myFace = cutterFace;
           // else
-          myLinks[ i   ].ReplaceCoplanar( newEdge );
-          myLinks[ i+1 ].ReplaceCoplanar( newEdge );
+          myLinks[ i ].ReplaceCoplanar( newEdge );
+          if ( myLinks[i].IsInternal() && i+1 < myLinks.size() )
+            myLinks[ i+1 ].ReplaceCoplanar( newEdge );
           return;
         }
         i += myLinks[i].IsInternal();
@@ -2558,7 +2577,8 @@ namespace
   //================================================================================
   /*!
    * \brief Remove loops that are not connected to boundary edges of myFace by
-   *        adding edges connecting these loops to the boundary
+   *        adding edges connecting these loops to the boundary.
+   *        Such loops must be removed as they form polygons with ring topology.
    */
   //================================================================================
 
@@ -2607,14 +2627,49 @@ namespace
     while ( prevNbReached < nbReachedLoops );
 
 
-    // add links connecting internal loops with the boundary ones
 
     for ( size_t iL = 0; iL < theLoops.myNbLoops; ++iL )
     {
       EdgeLoop& loop = theLoops.myLoops[ iL ];
-      if ( loop.myIsBndConnected )
+      if ( loop.myIsBndConnected || loop.myLinks.size() == 0 )
         continue;
 
+      if ( loop.myHasPending )
+      {
+        // try to join the loop to another one, with which it contacts at a node
+
+        // look for a node where the loop reverses
+        const EdgePart* edgePrev = loop.myLinks.back();
+        for ( size_t iE = 0; iE < loop.myLinks.size(); edgePrev = loop.myLinks[ iE++ ] )
+        {
+          if ( !edgePrev->IsTwin( *loop.myLinks[ iE ]))
+            continue;
+          const SMDS_MeshNode* reverseNode = edgePrev->myNode2;
+
+          // look for a loop including reverseNode
+          size_t iContactEdge2; // index(+1) of edge starting at reverseNode
+          for ( size_t iL2 = 0; iL2 < theLoops.myNbLoops; ++iL2 )
+          {
+            if ( iL == iL2 )
+              continue;
+            EdgeLoop& loop2 = theLoops.myLoops[ iL2 ];
+            if ( ! ( iContactEdge2 = loop2.Contains( reverseNode )))
+              continue;
+
+            // insert loop2 into the loop
+            theLoops.Join( loop, iE, loop2, iContactEdge2 - 1 );
+            break;
+          }
+          if ( loop.myIsBndConnected )
+            break;
+        }
+
+        if ( loop.myIsBndConnected )
+          continue;
+      }
+
+      // add links connecting internal loops with the boundary ones
+
       // find a pair of closest nodes
       const SMDS_MeshNode *closestNode1, *closestNode2;
       double minDist = 1e100;
@@ -2689,7 +2744,7 @@ namespace
 
     while ( !theLoops.AllEdgesUsed() )
     {
-      theLoops.AddNewLoop();
+      EdgeLoop& loop = theLoops.AddNewLoop();
 
       // add 1st edge to a new loop
       size_t i1;
@@ -2720,7 +2775,7 @@ namespace
         // choose among candidates
         if ( theLoops.myCandidates.size() == 0 )
         {
-          theLoops.GetLoopOf( lastEdge )->myHasPending = true;
+          loop.myHasPending = bool( twinEdge );
           lastEdge = twinEdge;
         }
         else if ( theLoops.myCandidates.size() == 1 )
@@ -2751,6 +2806,10 @@ namespace
       }
       while ( lastNode != firstNode );
 
+
+      if ( twinEdge == & myLinks[ i1 ])
+        loop.myHasPending = true;
+
     } // while ( !theLoops.AllEdgesUsed() )
 
     return;