Salome HOME
Zcracks plugin adaptation to new Zcracks tool
[modules/smesh.git] / src / SMESHUtils / SMESH_MeshAlgos.cxx
index dfdaf42d9a1a366242844707a5e4c01f5e384576..6670e509e9d00a8d06677dd91ee726145a6a8902 100644 (file)
@@ -442,6 +442,7 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
   SMDS_Mesh*                   _mesh;
   SMDS_ElemIteratorPtr         _meshPartIt;
   ElementBndBoxTree*           _ebbTree;
+  int                          _ebbTreeHeight;
   SMESH_NodeSearcherImpl*      _nodeSearcher;
   SMDSAbs_ElementType          _elementType;
   double                       _tolerance;
@@ -451,7 +452,7 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
   SMESH_ElementSearcherImpl( SMDS_Mesh&           mesh,
                              double               tol=-1,
                              SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
-    : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(tol),_outerFacesFound(false) {}
+    : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_ebbTreeHeight(-1),_nodeSearcher(0),_tolerance(tol),_outerFacesFound(false) {}
   virtual ~SMESH_ElementSearcherImpl()
   {
     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
@@ -479,6 +480,12 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
   {
     return _outerFaces.empty() || _outerFaces.count(face);
   }
+  int getTreeHeight()
+  {
+    if ( _ebbTreeHeight < 0 )
+      _ebbTreeHeight = _ebbTree->getHeight();
+    return _ebbTreeHeight;
+  }
 
   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
   {
@@ -584,7 +591,7 @@ bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           lin
   {
     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
-    anExtCC.Init( lineCurve, edge);
+    anExtCC.Init( lineCurve, edge.Value() );
     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
     {
       Quantity_Parameter pl, pe;
@@ -796,7 +803,7 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
       if ( _ebbTree->getBox()->IsOut( point.XYZ() ))
         radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize();
       if ( radius < 0 )
-        radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2;
+        radius = _ebbTree->maxSize() / pow( 2., getTreeHeight()) / 2;
       while ( suspectElems.empty() )
       {
         _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
@@ -906,8 +913,9 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
       }
       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
       {
+        double tol = 1e-4 * Sqrt( fNorm.Modulus() );
         gp_Pnt intersectionPoint = intersection.Point(1);
-        if ( !SMESH_MeshAlgos::IsOut( *face, intersectionPoint, tolerance ))
+        if ( !SMESH_MeshAlgos::IsOut( *face, intersectionPoint, tol ))
           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
       }
     }
@@ -986,16 +994,19 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
 
           // skip tangent intersections
           int nbTgt = 0;
-          const SMDS_MeshElement* prevFace = u_int1->second._face;
-          while ( ok && u_int2->second._coincides )
+          if ( u_int2 != u2inters.end() )
           {
-            if ( SMESH_MeshAlgos::GetCommonNodes(prevFace , u_int2->second._face).empty() )
-              ok = false;
-            else
+            const SMDS_MeshElement* prevFace = u_int1->second._face;
+            while ( ok && u_int2->second._coincides )
             {
-              nbTgt++;
-              u_int2++;
-              ok = ( u_int2 != u2inters.end() );
+              if ( SMESH_MeshAlgos::GetCommonNodes(prevFace , u_int2->second._face).empty() )
+                ok = false;
+              else
+              {
+                nbTgt++;
+                u_int2++;
+                ok = ( u_int2 != u2inters.end() );
+              }
             }
           }
           if ( !ok ) break;
@@ -1133,14 +1144,11 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
 
   // get ordered nodes
 
-  vector< SMESH_TNodeXYZ > xyz;
+  vector< SMESH_TNodeXYZ > xyz; xyz.reserve( element->NbNodes()+1 );
 
   SMDS_ElemIteratorPtr nodeIt = element->interlacedNodesElemIterator();
-  while ( nodeIt->more() )
-  {
-    SMESH_TNodeXYZ node = nodeIt->next();
-    xyz.push_back( node );
-  }
+  for ( int i = 0; nodeIt->more(); ++i )
+    xyz.push_back( SMESH_TNodeXYZ( nodeIt->next() ));
 
   int i, nbNodes = (int) xyz.size(); // central node of biquadratic is missing
 
@@ -1171,8 +1179,23 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
 
     // check if the point lays on face plane
     gp_Vec n2p( xyz[0], point );
-    if ( fabs( n2p * faceNorm ) > tol )
-      return true; // not on face plane
+    double dot = n2p * faceNorm;
+    if ( Abs( dot ) > tol ) // not on face plane
+    {
+      bool isOut = true;
+      if ( nbNodes > 3 ) // maybe the face is not planar
+      {
+        double elemThick = 0;
+        for ( i = 1; i < nbNodes; ++i )
+        {
+          gp_Vec n2n( xyz[0], xyz[i] );
+          elemThick = Max( elemThick, Abs( n2n * faceNorm ));
+        }
+        isOut = Abs( dot ) > elemThick + tol;
+      }
+      if ( isOut )
+        return isOut;
+    }
 
     // check if point is out of face boundary:
     // define it by closest transition of a ray point->infinity through face boundary
@@ -1184,7 +1207,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
     normSize = plnNorm.Magnitude();
     if ( normSize <= tol ) return false; // point coincides with the first node
     plnNorm /= normSize;
-    // for each node of the face, compute its signed distance to the plane
+    // for each node of the face, compute its signed distance to the cutting plane
     vector<double> dist( nbNodes + 1);
     for ( i = 0; i < nbNodes; ++i )
     {
@@ -1194,12 +1217,12 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
     dist.back() = dist.front();
     // find the closest intersection
     int    iClosest = -1;
-    double rClosest, distClosest = 1e100;;
+    double rClosest = 0, distClosest = 1e100;
     gp_Pnt pClosest;
     for ( i = 0; i < nbNodes; ++i )
     {
       double r;
-      if ( fabs( dist[i]) < tol )
+      if ( fabs( dist[i] ) < tol )
         r = 0.;
       else if ( fabs( dist[i+1]) < tol )
         r = 1.;
@@ -1208,17 +1231,14 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
       else
         continue; // no intersection
       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
-      gp_Vec p2int ( point, pInt);
-      if ( p2int * ray > -tol ) // right half-space
+      gp_Vec p2int( point, pInt);
+      double intDist = p2int.SquareMagnitude();
+      if ( intDist < distClosest )
       {
-        double intDist = p2int.SquareMagnitude();
-        if ( intDist < distClosest )
-        {
-          iClosest = i;
-          rClosest = r;
-          pClosest = pInt;
-          distClosest = intDist;
-        }
+        iClosest = i;
+        rClosest = r;
+        pClosest = pInt;
+        distClosest = intDist;
       }
     }
     if ( iClosest < 0 )
@@ -1242,6 +1262,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
     return covexCorner ? (out || out2) : (out && out2);
   }
+
   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
   {
     // point is out of edge if it is NOT ON any straight part of edge
@@ -1269,6 +1290,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
     }
     return true;
   }
+
   // Node or 0D element -------------------------------------------------------------------------
   {
     gp_Vec n2p ( xyz[0], point );