Salome HOME
Copyright update 2020
[modules/smesh.git] / src / SMESHUtils / SMESH_MeshAlgos.cxx
index 6cd891ccc544fe572f8150f136fb203a9625c0e6..14c781836c6b9a5b9c95a847b210ee91ec248b1b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2020  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
@@ -238,6 +238,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
     void getElementsInBox    ( const Bnd_B3d& box,  TElemSeq& foundElems );
     void getElementsInSphere ( const gp_XYZ& center, const double radius, TElemSeq& foundElems );
     ElementBndBoxTree* getLeafAtPoint( const gp_XYZ& point );
+    int  getNbElements();
 
   protected:
     ElementBndBoxTree() {}
@@ -466,6 +467,27 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
     return 0;
   }
 
+  //================================================================================
+  /*!
+   * \brief Return number of elements
+   */
+  //================================================================================
+
+  int ElementBndBoxTree::getNbElements()
+  {
+    int nb = 0;
+    if ( isLeaf() )
+    {
+      nb = _elements.size();
+    }
+    else
+    {
+      for (int i = 0; i < 8; i++)
+        nb += ((ElementBndBoxTree*) myChildren[i])->getNbElements();
+    }
+    return nb;
+  }
+
   //================================================================================
   /*!
    * \brief Construct the element box
@@ -848,7 +870,7 @@ FindElementsByPoint(const gp_Pnt&                           point,
 /*!
  * \brief Find an element of given type most close to the given point
  *
- * WARNING: Only face search is implemeneted so far
+ * WARNING: Only edge, face and volume search is implemented so far
  */
 //=======================================================================
 
@@ -1076,7 +1098,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
             const SMDS_MeshElement* prevFace = u_int1->second._face;
             while ( ok && u_int2->second._coincides )
             {
-              if ( SMESH_MeshAlgos::GetCommonNodes(prevFace , u_int2->second._face).empty() )
+              if ( SMESH_MeshAlgos::NbCommonNodes(prevFace , u_int2->second._face) == 0 )
                 ok = false;
               else
               {
@@ -1254,18 +1276,43 @@ gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt&            point,
   gp_XYZ p = point.XYZ();
   ElementBndBoxTree* ebbLeaf = ebbTree->getLeafAtPoint( p );
   const Bnd_B3d* box = ebbLeaf ? ebbLeaf->getBox() : ebbTree->getBox();
-  double radius = ( box->CornerMax() - box->CornerMin() ).Modulus();
+  gp_XYZ pMin = box->CornerMin(), pMax = box->CornerMax();
+  double radius = Precision::Infinite();
+  if ( ebbLeaf || !box->IsOut( p ))
+  {
+    for ( int i = 1; i <= 3; ++i )
+    {
+      double d = 0.5 * ( pMax.Coord(i) - pMin.Coord(i) );
+      if ( d > Precision::Confusion() )
+        radius = Min( d, radius );
+    }
+    if ( !ebbLeaf )
+      radius /= ebbTree->getHeight( /*full=*/true );
+  }
+  else // p outside of box
+  {
+    for ( int i = 1; i <= 3; ++i )
+    {
+      double d = 0;
+      if ( point.Coord(i) < pMin.Coord(i) )
+        d = pMin.Coord(i) - point.Coord(i);
+      else if ( point.Coord(i) > pMax.Coord(i) )
+        d = point.Coord(i) - pMax.Coord(i);
+      if ( d > Precision::Confusion() )
+        radius = Min( d, radius );
+    }
+  }
 
   ElementBndBoxTree::TElemSeq elems;
   ebbTree->getElementsInSphere( p, radius, elems );
   while ( elems.empty() && radius < 1e100 )
   {
-    radius *= 1.5;
+    radius *= 1.1;
     ebbTree->getElementsInSphere( p, radius, elems );
   }
   gp_XYZ proj, bestProj;
   const SMDS_MeshElement* elem = 0;
-  double minDist = 2 * radius;
+  double minDist = Precision::Infinite();
   ElementBndBoxTree::TElemSeq::iterator e = elems.begin();
   for ( ; e != elems.end(); ++e )
   {
@@ -1277,6 +1324,23 @@ gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt&            point,
       minDist = d;
     }
   }
+  if ( minDist > radius )
+  {
+    ElementBndBoxTree::TElemSeq elems2;
+    ebbTree->getElementsInSphere( p, minDist, elems2 );
+    for ( e = elems2.begin(); e != elems2.end(); ++e )
+    {
+      if ( elems.count( *e ))
+        continue;
+      double d = SMESH_MeshAlgos::GetDistance( *e, point, &proj );
+      if ( d < minDist )
+      {
+        bestProj = proj;
+        elem = *e;
+        minDist = d;
+      }
+    }
+  }
   if ( closestElem ) *closestElem = elem;
 
   return bestProj;
@@ -1764,7 +1828,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume,
          !vTool.GetFaceBaryCenter( iF, bc[0], bc[1], bc[2] ))
       continue;
     gp_XYZ bcp = point.XYZ() - gp_XYZ( bc[0], bc[1], bc[2] );
-    if ( gp_XYZ( n[0], n[1], n[2] ) * bcp < 1e-6 )
+    if ( gp_XYZ( n[0], n[1], n[2] ) * bcp < -1e-12 )
       continue;
 
     // find distance to a facet
@@ -2146,10 +2210,26 @@ bool SMESH_MeshAlgos::FaceNormal(const SMDS_MeshElement* F, gp_XYZ& normal, bool
   return ok;
 }
 
-//=======================================================================
-//function : GetCommonNodes
-//purpose  : Return nodes common to two elements
-//=======================================================================
+//================================================================================
+/*!
+ * \brief Return nodes common to two elements
+ */
+//================================================================================
+
+int SMESH_MeshAlgos::NbCommonNodes(const SMDS_MeshElement* e1,
+                                   const SMDS_MeshElement* e2)
+{
+  int nb = 0;
+  for ( int i = 0 ; i < e1->NbNodes(); ++i )
+    nb += ( e2->GetNodeIndex( e1->GetNode( i )) >= 0 );
+  return nb;
+}
+
+//================================================================================
+/*!
+ * \brief Return nodes common to two elements
+ */
+//================================================================================
 
 std::vector< const SMDS_MeshNode*> SMESH_MeshAlgos::GetCommonNodes(const SMDS_MeshElement* e1,
                                                                    const SMDS_MeshElement* e2)
@@ -2160,6 +2240,7 @@ std::vector< const SMDS_MeshNode*> SMESH_MeshAlgos::GetCommonNodes(const SMDS_Me
       common.push_back( e1->GetNode( i ));
   return common;
 }
+
 //================================================================================
 /*!
  * \brief Return true if node1 encounters first in the face and node2, after
@@ -2347,28 +2428,16 @@ void SMESH_MeshAlgos::Get1DBranches( SMDS_ElemIteratorPtr theEdgeIt,
 
     if ( nbBranches == 2 && !startIsBranchEnd ) // join two branches starting at the same node
     {
-      if ( nodeBranches[0].back() == nodeBranches[1].back() )
-      {
-        // it is a closed branch, keep theStartNode first
-        nodeBranches[0].pop_back();
-        nodeBranches[0].reserve( nodeBranches[0].size() + nodeBranches[1].size() );
-        nodeBranches[0].insert( nodeBranches[0].end(),
-                                nodeBranches[1].rbegin(), nodeBranches[1].rend() );
-        branches[0].reserve( branches[0].size() + branches[1].size() );
-        branches[0].insert( branches[0].end(), branches[1].rbegin(), branches[1].rend() );
-      }
-      else
-      {
-        std::reverse( nodeBranches[0].begin(), nodeBranches[0].end() );
-        nodeBranches[0].pop_back();
-        nodeBranches[0].reserve( nodeBranches[0].size() + nodeBranches[1].size() );
-        nodeBranches[0].insert( nodeBranches[0].end(),
-                                nodeBranches[1].begin(), nodeBranches[1].end() );
-
-        std::reverse( branches[0].begin(), branches[0].end() );
-        branches[0].reserve( branches[0].size() + branches[1].size() );
-        branches[0].insert( branches[0].end(), branches[1].begin(), branches[1].end() );
-      }
+      std::reverse( nodeBranches[0].begin(), nodeBranches[0].end() );
+      nodeBranches[0].pop_back();
+      nodeBranches[0].reserve( nodeBranches[0].size() + nodeBranches[1].size() );
+      nodeBranches[0].insert( nodeBranches[0].end(),
+                              nodeBranches[1].begin(), nodeBranches[1].end() );
+
+      std::reverse( branches[0].begin(), branches[0].end() );
+      branches[0].reserve( branches[0].size() + branches[1].size() );
+      branches[0].insert( branches[0].end(), branches[1].begin(), branches[1].end() );
+
       nodeBranches[1].clear();
       branches[1].clear();
     }