Salome HOME
#18963 Minimize compiler warnings
[modules/smesh.git] / src / SMESHUtils / SMESH_FreeBorders.cxx
index 6d180f8c26b19c0ebe081c317f07cd3d42e22fe0..e5913cdac85293d17833d4733437e8d7a173be9d 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
@@ -36,6 +36,7 @@
 #include <vector>
 
 #include <NCollection_DataMap.hxx>
+#include <Precision.hxx>
 #include <gp_Pnt.hxx>
 
 using namespace SMESH_MeshAlgos;
@@ -62,6 +63,7 @@ namespace
     bool   HasCloseEdgeWithNode( const BNode* n ) const;
     bool   IsCloseEdge( const BEdge*, double * u = 0 ) const;
     bool operator<(const BNode& other) const { return Node()->GetID() < other.Node()->GetID(); }
+    double SquareDistance(const BNode& e2) const { return ( e2 - *this ).SquareModulus(); }
   };
   /*!
    * \brief Edge of a free border
@@ -90,7 +92,7 @@ namespace
       myNodes[0] = node1->Node();
       myNodes[1] = node2->Node();
       myFace     = face;
-      setId( ID ); // mesh element ID
+      setID( ID ); // mesh element ID
     }
     bool IsInGroup() const
     {
@@ -129,10 +131,19 @@ namespace
       if ( myID < 0 )
       {
         myID = id;
-        if ( myNext )
-          myNext->SetID( id + 1 );
+
+        for ( BEdge* be = myNext; be && be->myID < 0; be = be->myNext )
+        {
+          be->myID = ++id;
+        }
       }
     }
+    //================================================================================
+    /*!
+     * \brief Checks if a point is closer to this BEdge than tol
+     */
+    //================================================================================
+
     bool IsOut( const gp_XYZ& point, const double tol, double& u ) const
     {
       gp_XYZ  me = *myBNode2 - *myBNode1;
@@ -145,6 +156,12 @@ namespace
       double dist2 = ( point - proj ).SquareModulus();
       return ( dist2 > tol * tol );
     }
+    //================================================================================
+    /*!
+     * \brief Checks if two BEdges can be considered as overlapping
+     */
+    //================================================================================
+
     bool IsOverlappingProjection( const BEdge* toE, const double u, bool is1st ) const
     {
       // is1st shows which end of toE is projected on this at u
@@ -160,6 +177,12 @@ namespace
         return Abs( u - u2 ) > eps;
       return false;
     }
+    //================================================================================
+    /*!
+     * \brief Finds all neighbor BEdge's having the same close borders
+     */
+    //================================================================================
+
     bool GetRangeOfSameCloseBorders(BEdge* eRange[2], const std::set< int >& bordIDs)
     {
       if ( this->myCloseBorders != bordIDs )
@@ -221,6 +244,64 @@ namespace
     }
   }; // class BEdge
 
+  //================================================================================
+  /*!
+   * \brief Checks if all border parts include the whole closed border, and if so
+   *        returns \c true and choose starting BEdge's with most coincident nodes
+   */
+  //================================================================================
+
+  bool chooseStartOfClosedBorders( std::vector< BEdge* >& ranges ) // PAL23078#c21002
+  {
+    bool allClosed = true;
+    for ( size_t iR = 1; iR < ranges.size() && allClosed; iR += 2 )
+      allClosed = ( ranges[ iR-1 ]->myPrev == ranges[ iR ] );
+    if ( !allClosed )
+      return allClosed;
+
+    double u, minDiff = Precision::Infinite();
+    std::vector< BEdge* > start( ranges.size() / 2 );
+    BEdge* range0 = start[0] = ranges[0];
+    do
+    {
+      double maxDiffU = 0;
+      double  maxDiff = 0;
+      for ( size_t iR = 3; iR < ranges.size(); iR += 2 )
+      {
+        int borderID = ranges[iR]->myBorderID;
+        if ( BEdge* e = start[0]->myBNode1->GetCloseEdgeOfBorder( borderID, & u ))
+        {
+          start[ iR / 2 ] = e;
+          double diffU = Min( Abs( u ), Abs( 1.-u ));
+          double  diff = e->myBNode1->SquareDistance( *e->myBNode2 ) * diffU * diffU;
+          maxDiffU = Max( diffU, maxDiffU );
+          maxDiff  = Max( diff,  maxDiff );
+        }
+      }
+      if ( maxDiff < minDiff )
+      {
+        minDiff = maxDiff;
+        for ( size_t iR = 1; iR < ranges.size(); iR += 2 )
+        {
+          ranges[ iR-1 ] = start[ iR/2 ];
+          ranges[ iR   ] = ranges[ iR-1]->myPrev;
+        }
+      }
+      if ( maxDiffU < 1e-6 )
+        break;
+      start[0] = start[0]->myNext;
+    }
+    while ( start[0] != range0 );
+
+    return allClosed;
+  }
+
+  //================================================================================
+  /*!
+   * \brief Tries to include neighbor BEdge's into a border part
+   */
+  //================================================================================
+
   void extendPart( BEdge* & e1, BEdge* & e2, const std::set< int >& bordIDs, int groupID )
   {
     if (( e1->myPrev == e2 ) ||
@@ -268,6 +349,12 @@ namespace
     }
   }
 
+  //================================================================================
+  /*!
+   * \brief Connect BEdge's incident at this node
+   */
+  //================================================================================
+
   void BNode::AddLinked( BEdge* e ) const
   {
     myLinkedEdges.reserve(2);
@@ -290,7 +377,7 @@ namespace
   void BNode::AddClose ( const BEdge* e, double u ) const
   {
     if ( ! e->Contains( this ))
-      myCloseEdges.push_back( make_pair( const_cast< BEdge* >( e ), u ));
+      myCloseEdges.push_back( std::make_pair( const_cast< BEdge* >( e ), u ));
   }
   BEdge* BNode::GetCloseEdgeOfBorder( int borderID, double * uPtr ) const
   {
@@ -344,19 +431,6 @@ namespace
 
 } // namespace
 
-// struct needed for NCollection_Map
-struct TLinkHasher
-{
-  static int HashCode(const SMESH_TLink& link, int aLimit)
-  {
-    return ::HashCode( link.node1()->GetID() + link.node2()->GetID(), aLimit );
-  }
-  static Standard_Boolean IsEqual(const SMESH_TLink& l1, const SMESH_TLink& l2)
-  {
-    return ( l1.node1() == l2.node1() && l1.node2() == l2.node2() );
-  }
-};
-
 //================================================================================
 /*
  * Returns groups of TFreeBorder's coincident within the given tolerance.
@@ -370,7 +444,7 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
                                                 CoincidentFreeBorders & foundFreeBordes)
 {
   // find free links
-  typedef NCollection_DataMap<SMESH_TLink, const SMDS_MeshElement*, TLinkHasher > TLink2FaceMap;
+  typedef NCollection_DataMap<SMESH_TLink, const SMDS_MeshElement*, SMESH_TLink > TLink2FaceMap;
   TLink2FaceMap linkMap;
   int nbSharedLinks = 0;
   SMDS_FaceIteratorPtr faceIt = mesh.facesIterator();
@@ -582,9 +656,9 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
 
   // form groups of coincident parts of free borders
 
-  TFreeBorderPart  part;
-  TCoincidentGroup group;
-  vector< BEdge* > ranges; // couples of edges delimiting parts
+  TFreeBorderPart       part;
+  TCoincidentGroup      group;
+  std::vector< BEdge* > ranges; // couples of edges delimiting parts
   BEdge* be = 0; // a current edge
   int skipGroup = bEdges.size(); // a group ID used to avoid repeating treatment of edges
 
@@ -683,8 +757,9 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
 
     if ( ranges.size() > 2 )
     {
-      for ( size_t iR = 1; iR < ranges.size(); iR += 2 )
-        extendPart( ranges[ iR-1 ], ranges[ iR ], be1st->myCloseBorders, groupID );
+      if ( !chooseStartOfClosedBorders( ranges ))
+        for ( size_t iR = 1; iR < ranges.size(); iR += 2 )
+          extendPart( ranges[ iR-1 ], ranges[ iR ], be1st->myCloseBorders, groupID );
 
       // fill in a group
       beRange[0] = ranges[0];
@@ -749,3 +824,137 @@ void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh&              mesh,
 
 } // SMESH_MeshAlgos::FindCoincidentFreeBorders()
 
+//================================================================================
+/*
+ * Returns all TFreeBorder's. Optionally check if the mesh is manifold
+ * and if faces are correctly oriented.
+ */
+//================================================================================
+
+void SMESH_MeshAlgos::FindFreeBorders(SMDS_Mesh&       theMesh,
+                                      TFreeBorderVec & theFoundFreeBordes,
+                                      const bool       theClosedOnly,
+                                      bool*            theIsManifold,
+                                      bool*            theIsGoodOri)
+{
+  bool isManifold = true;
+
+  // find free links
+  typedef NCollection_DataMap<SMESH_TLink, const SMDS_MeshElement*, SMESH_TLink > TLink2FaceMap;
+  TLink2FaceMap linkMap;
+  int nbSharedLinks = 0;
+  SMDS_FaceIteratorPtr faceIt = theMesh.facesIterator();
+  while ( faceIt->more() )
+  {
+    const SMDS_MeshElement* face = faceIt->next();
+    if ( !face ) continue;
+
+    const SMDS_MeshNode*     n0 = face->GetNode( face->NbNodes() - 1 );
+    SMDS_NodeIteratorPtr nodeIt = face->interlacedNodesIterator();
+    while ( nodeIt->more() )
+    {
+      const SMDS_MeshNode* n1 = nodeIt->next();
+      SMESH_TLink link( n0, n1 );
+      if ( const SMDS_MeshElement** faceInMap = linkMap.ChangeSeek( link ))
+      {
+        if ( *faceInMap )
+        {
+          if ( theIsGoodOri && *theIsGoodOri && !IsRightOrder( *faceInMap, n1, n0 ))
+            *theIsGoodOri = false;
+        }
+        else
+        {
+          isManifold = false;
+        }
+        nbSharedLinks += bool( *faceInMap );
+        *faceInMap = 0;
+      }
+      else
+      {
+        linkMap.Bind( link, face );
+      }
+      n0 = n1;
+    }
+  }
+  if ( theIsManifold )
+    *theIsManifold = isManifold;
+
+  if ( linkMap.Extent() == nbSharedLinks )
+    return;
+
+  // form free borders
+  std::set   < BNode > bNodes;
+  std::vector< BEdge > bEdges( linkMap.Extent() - nbSharedLinks );
+
+  TLink2FaceMap::Iterator linkIt( linkMap );
+  for ( int iEdge = 0; linkIt.More(); linkIt.Next() )
+  {
+    if ( !linkIt.Value() ) continue;
+    const SMESH_TLink & link = linkIt.Key();
+    std::set< BNode >::iterator n1 = bNodes.insert( BNode( link.node1() )).first;
+    std::set< BNode >::iterator n2 = bNodes.insert( BNode( link.node2() )).first;
+    bEdges[ iEdge ].Set( &*n1, &*n2, linkIt.Value(), iEdge+1 );
+    n1->AddLinked( & bEdges[ iEdge ] );
+    n2->AddLinked( & bEdges[ iEdge ] );
+    ++iEdge;
+  }
+  linkMap.Clear();
+
+  // assign IDs to borders
+  std::vector< BEdge* > borders; // 1st of connected (via myPrev and myNext) edges
+  std::set< BNode >::iterator bn = bNodes.begin();
+  for ( ; bn != bNodes.end(); ++bn )
+  {
+    for ( size_t i = 0; i < bn->myLinkedEdges.size(); ++i )
+    {
+      if ( bn->myLinkedEdges[i]->myBorderID < 0 )
+      {
+        BEdge* be = bn->myLinkedEdges[i];
+        int borderID = borders.size();
+        borders.push_back( be );
+        for ( ; be && be->myBorderID < 0; be = be->myNext )
+        {
+          be->myBorderID = borderID;
+          be->Orient();
+        }
+        bool isClosed = ( be == bn->myLinkedEdges[i] );
+        if ( !isClosed && theClosedOnly )
+        {
+          borders.pop_back();
+          continue;
+        }
+        be = bn->myLinkedEdges[i]->myPrev;
+        for ( ; be && be->myBorderID < 0; be = be->myPrev )
+        {
+          be->myBorderID = borderID;
+          be->Orient();
+        }
+        if ( !isClosed )
+          while ( borders.back()->myPrev )
+            borders.back() = borders.back()->myPrev;
+      }
+    }
+  }
+  theFoundFreeBordes.resize( borders.size() );
+  for ( size_t i = 0; i < borders.size(); ++i )
+  {
+    TFreeBorder & bordNodes = theFoundFreeBordes[ i ];
+    BEdge*               be = borders[i];
+
+    size_t cnt = 1;
+    for ( be = be->myNext; be && be != borders[i]; be = be->myNext )
+      ++cnt;
+    bordNodes.resize( cnt + 1 );
+
+    BEdge* beLast = 0;
+    for ( be = borders[i], cnt = 0;
+          be && cnt < bordNodes.size()-1;
+          be = be->myNext, ++cnt )
+    {
+      bordNodes[ cnt ] = be->myBNode1->Node();
+      beLast = be;
+    }
+    if ( beLast )
+      bordNodes.back() = beLast->myBNode2->Node();
+  }
+}