Salome HOME
PAL0023627: [IMACS] ASERIS: project point to the mesh
[modules/smesh.git] / src / SMESHUtils / SMESH_MeshAlgos.cxx
index 1776f3dd4f4227e4e7658b819572f742819ab786..0fc388e75939e987fed1b662f93419fbce4a79fd 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "SMESH_MeshAlgos.hxx"
 
+#include "ObjectPool.hxx"
 #include "SMDS_FaceOfNodes.hxx"
 #include "SMDS_LinearEdge.hxx"
 #include "SMDS_Mesh.hxx"
@@ -35,6 +36,8 @@
 #include "SMDS_VolumeTool.hxx"
 #include "SMESH_OctreeNode.hxx"
 
+#include <Utils_SALOME_Exception.hxx>
+
 #include <GC_MakeSegment.hxx>
 #include <GeomAPI_ExtremaCurveCurve.hxx>
 #include <Geom_Line.hxx>
@@ -46,7 +49,7 @@
 #include <limits>
 #include <numeric>
 
-using namespace std;
+#include <boost/container/flat_set.hpp>
 
 //=======================================================================
 /*!
@@ -67,7 +70,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
 
     TIDSortedNodeSet nodes;
     if ( theMesh ) {
-      SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
+      SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
       while ( nIt->more() )
         nodes.insert( nodes.end(), nIt->next() );
     }
@@ -108,21 +111,22 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
    */
   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
   {
-    map<double, const SMDS_MeshNode*> dist2Nodes;
+    std::map<double, const SMDS_MeshNode*> dist2Nodes;
     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
     if ( !dist2Nodes.empty() )
       return dist2Nodes.begin()->second;
-    list<const SMDS_MeshNode*> nodes;
+
+    std::vector<const SMDS_MeshNode*> nodes;
     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
 
     double minSqDist = DBL_MAX;
     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
     {
       // sort leafs by their distance from thePnt
-      typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
+      typedef std::multimap< double, SMESH_OctreeNode* > TDistTreeMap;
       TDistTreeMap treeMap;
-      list< SMESH_OctreeNode* > treeList;
-      list< SMESH_OctreeNode* >::iterator trIt;
+      std::list< SMESH_OctreeNode* > treeList;
+      std::list< SMESH_OctreeNode* >::iterator trIt;
       treeList.push_back( myOctreeNode );
 
       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
@@ -141,9 +145,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
         {
           const Bnd_B3d& box = *tree->getBox();
           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
-          pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
-          if ( !it_in.second ) // not unique distance to box center
-            treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
+          treeMap.insert( std::make_pair( sqDist, tree ));
         }
       }
       // find distance after which there is no sense to check tree's
@@ -160,17 +162,17 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
         if ( sqDist_tree->first > sqLimit )
           break;
         SMESH_OctreeNode* tree = sqDist_tree->second;
-        tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
+        tree->AllNodesAround( tree->GetNodeIterator()->next(), &nodes );
       }
     }
     // find closest among nodes
     minSqDist = DBL_MAX;
     const SMDS_MeshNode* closestNode = 0;
-    list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
-    for ( ; nIt != nodes.end(); ++nIt ) {
-      double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
+    for ( size_t i = 0; i < nodes.size(); ++i )
+    {
+      double sqDist = thePnt.SquareDistance( SMESH_NodeXYZ( nodes[ i ]));
       if ( minSqDist > sqDist ) {
-        closestNode = *nIt;
+        closestNode = nodes[ i ];
         minSqDist = sqDist;
       }
     }
@@ -179,7 +181,7 @@ struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
 
   //---------------------------------------------------------------------
   /*!
-   * \brief Finds nodes located within a tolerance near a point 
+   * \brief Finds nodes located within a tolerance near a point
    */
   int FindNearPoint(const gp_Pnt&                        point,
                     const double                         tolerance,
@@ -224,19 +226,20 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
   {
   public:
 
+    typedef boost::container::flat_set< const SMDS_MeshElement*, TIDCompare > TElemSeq;
+
     ElementBndBoxTree(const SMDS_Mesh&     mesh,
                       SMDSAbs_ElementType  elemType,
                       SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(),
                       double               tolerance = NodeRadius );
-    void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems );
-    void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
-    void getElementsInSphere ( const gp_XYZ& center,
-                               const double  radius, TIDSortedElemSet& foundElems);
-    size_t getSize() { return std::max( _size, _elements.size() ); }
-    virtual ~ElementBndBoxTree();
+    void getElementsNearPoint( const gp_Pnt& point, TElemSeq& foundElems );
+    void getElementsNearLine ( const gp_Ax1& line,  TElemSeq& foundElems );
+    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 );
 
   protected:
-    ElementBndBoxTree():_size(0) {}
+    ElementBndBoxTree() {}
     SMESH_Octree* newChild() const { return new ElementBndBoxTree; }
     void          buildChildrenData();
     Bnd_B3d*      buildRootBox();
@@ -245,11 +248,23 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
     struct ElementBox : public Bnd_B3d
     {
       const SMDS_MeshElement* _element;
-      int                     _refCount; // an ElementBox can be included in several tree branches
-      ElementBox(const SMDS_MeshElement* elem, double tolerance);
+      void init(const SMDS_MeshElement* elem, double tolerance);
+    };
+    std::vector< ElementBox* > _elements;
+
+    typedef ObjectPool< ElementBox > TElementBoxPool;
+
+    //!< allocator of ElementBox's and SMESH_TreeLimit
+    struct LimitAndPool : public SMESH_TreeLimit
+    {
+      TElementBoxPool _elBoPool;
+      LimitAndPool():SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ) {}
     };
-    vector< ElementBox* > _elements;
-    size_t                _size;
+    LimitAndPool* getLimitAndPool() const
+    {
+      SMESH_TreeLimit* limitAndPool = const_cast< SMESH_TreeLimit* >( myLimit );
+      return static_cast< LimitAndPool* >( limitAndPool );
+    }
   };
 
   //================================================================================
@@ -258,32 +273,27 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
-    :SMESH_Octree( new SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ))
+  ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh&     mesh,
+                                       SMDSAbs_ElementType  elemType,
+                                       SMDS_ElemIteratorPtr theElemIt,
+                                       double               tolerance)
+    :SMESH_Octree( new LimitAndPool() )
   {
     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
     _elements.reserve( nbElems );
 
+    TElementBoxPool& elBoPool = getLimitAndPool()->_elBoPool;
+
     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
     while ( elemIt->more() )
-      _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
-
+    {
+      ElementBox* eb = elBoPool.getNew();
+      eb->init( elemIt->next(), tolerance );
+      _elements.push_back( eb );
+    }
     compute();
   }
 
-  //================================================================================
-  /*!
-   * \brief Destructor
-   */
-  //================================================================================
-
-  ElementBndBoxTree::~ElementBndBoxTree()
-  {
-    for ( size_t i = 0; i < _elements.size(); ++i )
-      if ( --_elements[i]->_refCount <= 0 )
-        delete _elements[i];
-  }
-
   //================================================================================
   /*!
    * \brief Return the maximal box
@@ -311,14 +321,10 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
       for (int j = 0; j < 8; j++)
       {
         if ( !_elements[i]->IsOut( *myChildren[j]->getBox() ))
-        {
-          _elements[i]->_refCount++;
           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
-        }
       }
-      _elements[i]->_refCount--;
     }
-    _size = _elements.size();
+    //_size = _elements.size();
     SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory
 
     for (int j = 0; j < 8; j++)
@@ -327,7 +333,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
       if ((int) child->_elements.size() <= MaxNbElemsInLeaf )
         child->myIsLeaf = true;
 
-      if ( child->_elements.capacity() - child->_elements.size() > 1000 )
+      if ( child->isLeaf() && child->_elements.capacity() > child->_elements.size() )
         SMESHUtils::CompactVector( child->_elements );
     }
   }
@@ -338,8 +344,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
-                                                TIDSortedElemSet& foundElems)
+  void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point, TElemSeq& foundElems)
   {
     if ( getBox()->IsOut( point.XYZ() ))
       return;
@@ -363,8 +368,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
-                                               TIDSortedElemSet& foundElems)
+  void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line, TElemSeq& foundElems )
   {
     if ( getBox()->IsOut( line ))
       return;
@@ -372,7 +376,7 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
     if ( isLeaf() )
     {
       for ( size_t i = 0; i < _elements.size(); ++i )
-        if ( !_elements[i]->IsOut( line ))
+        if ( !_elements[i]->IsOut( line ) )
           foundElems.insert( _elements[i]->_element );
     }
     else
@@ -388,9 +392,9 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
    */
   //================================================================================
 
-  void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ&     center,
-                                                const double      radius,
-                                                TIDSortedElemSet& foundElems)
+  void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center,
+                                                const double  radius,
+                                                TElemSeq&     foundElems)
   {
     if ( getBox()->IsOut( center, radius ))
       return;
@@ -408,19 +412,66 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
     }
   }
 
+  //================================================================================
+  /*!
+   * \brief Return elements from leaves intersecting the box
+   */
+  //================================================================================
+
+  void ElementBndBoxTree::getElementsInBox( const Bnd_B3d& box,  TElemSeq& foundElems )
+  {
+    if ( getBox()->IsOut( box ))
+      return;
+
+    if ( isLeaf() )
+    {
+      for ( size_t i = 0; i < _elements.size(); ++i )
+        if ( !_elements[i]->IsOut( box ))
+          foundElems.insert( _elements[i]->_element );
+    }
+    else
+    {
+      for (int i = 0; i < 8; i++)
+        ((ElementBndBoxTree*) myChildren[i])->getElementsInBox( box, foundElems );
+    }
+  }
+
+  //================================================================================
+  /*!
+   * \brief Return a leaf including a point
+   */
+  //================================================================================
+
+  ElementBndBoxTree* ElementBndBoxTree::getLeafAtPoint( const gp_XYZ& point )
+  {
+    if ( getBox()->IsOut( point ))
+      return 0;
+
+    if ( isLeaf() )
+    {
+      return this;
+    }
+    else
+    {
+      for (int i = 0; i < 8; i++)
+        if ( ElementBndBoxTree* l = ((ElementBndBoxTree*) myChildren[i])->getLeafAtPoint( point ))
+          return l;
+    }
+    return 0;
+  }
+
   //================================================================================
   /*!
    * \brief Construct the element box
    */
   //================================================================================
 
-  ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
+  void ElementBndBoxTree::ElementBox::init(const SMDS_MeshElement* elem, double tolerance)
   {
     _element  = elem;
-    _refCount = 1;
     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
     while ( nIt->more() )
-      Add( SMESH_TNodeXYZ( nIt->next() ));
+      Add( SMESH_NodeXYZ( nIt->next() ));
     Enlarge( tolerance );
   }
 
@@ -439,38 +490,56 @@ SMESH_ElementSearcher::~SMESH_ElementSearcher()
 
 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
 {
-  SMDS_Mesh*                   _mesh;
-  SMDS_ElemIteratorPtr         _meshPartIt;
-  ElementBndBoxTree*           _ebbTree;
-  SMESH_NodeSearcherImpl*      _nodeSearcher;
-  SMDSAbs_ElementType          _elementType;
-  double                       _tolerance;
-  bool                         _outerFacesFound;
-  set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
+  SMDS_Mesh*                        _mesh;
+  SMDS_ElemIteratorPtr              _meshPartIt;
+  ElementBndBoxTree*                _ebbTree      [SMDSAbs_NbElementTypes];
+  int                               _ebbTreeHeight[SMDSAbs_NbElementTypes];
+  SMESH_NodeSearcherImpl*           _nodeSearcher;
+  SMDSAbs_ElementType               _elementType;
+  double                            _tolerance;
+  bool                              _outerFacesFound;
+  std::set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
 
   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),_nodeSearcher(0),_tolerance(tol),_outerFacesFound(false)
+  {
+    for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
+    {
+      _ebbTree[i] = NULL;
+      _ebbTreeHeight[i] = -1;
+    }
+    _elementType = SMDSAbs_All;
+  }
   virtual ~SMESH_ElementSearcherImpl()
   {
-    if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
+    for ( int i = 0; i < SMDSAbs_NbElementTypes; ++i )
+    {
+      delete _ebbTree[i]; _ebbTree[i] = NULL;
+    }
     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
   }
-  virtual int FindElementsByPoint(const gp_Pnt&                      point,
-                                  SMDSAbs_ElementType                type,
-                                  vector< const SMDS_MeshElement* >& foundElements);
+  virtual int FindElementsByPoint(const gp_Pnt&                           point,
+                                  SMDSAbs_ElementType                     type,
+                                  std::vector< const SMDS_MeshElement* >& foundElements);
   virtual TopAbs_State GetPointState(const gp_Pnt& point);
   virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt&       point,
                                                  SMDSAbs_ElementType type );
 
-  void GetElementsNearLine( const gp_Ax1&                      line,
-                            SMDSAbs_ElementType                type,
-                            vector< const SMDS_MeshElement* >& foundElems);
-  void GetElementsInSphere( const gp_XYZ&                      center,
-                            const double                       radius,
-                            SMDSAbs_ElementType                type,
-                            vector< const SMDS_MeshElement* >& foundElems);
+  virtual void GetElementsNearLine( const gp_Ax1&                           line,
+                                    SMDSAbs_ElementType                     type,
+                                    std::vector< const SMDS_MeshElement* >& foundElems);
+  virtual void GetElementsInSphere( const gp_XYZ&                           center,
+                                    const double                            radius,
+                                    SMDSAbs_ElementType                     type,
+                                    std::vector< const SMDS_MeshElement* >& foundElems);
+  virtual void GetElementsInBox( const Bnd_B3d&                          box,
+                                 SMDSAbs_ElementType                     type,
+                                 std::vector< const SMDS_MeshElement* >& foundElems);
+  virtual gp_XYZ Project(const gp_Pnt&            point,
+                         SMDSAbs_ElementType      type,
+                         const SMDS_MeshElement** closestElem);
   double getTolerance();
   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
                             const double tolerance, double & param);
@@ -479,6 +548,12 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
   {
     return _outerFaces.empty() || _outerFaces.count(face);
   }
+  int getTreeHeight()
+  {
+    if ( _ebbTreeHeight[ _elementType ] < 0 )
+      _ebbTreeHeight[ _elementType ] = _ebbTree[ _elementType ]->getHeight();
+    return _ebbTreeHeight[ _elementType ];
+  }
 
   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
   {
@@ -521,9 +596,9 @@ double SMESH_ElementSearcherImpl::getTolerance()
       double boxSize = _nodeSearcher->getTree()->maxSize();
       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
     }
-    else if ( _ebbTree && meshInfo.NbElements() > 0 )
+    else if ( _ebbTree[_elementType] && meshInfo.NbElements() > 0 )
     {
-      double boxSize = _ebbTree->maxSize();
+      double boxSize = _ebbTree[_elementType]->maxSize();
       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
     }
     if ( _tolerance == 0 )
@@ -544,16 +619,15 @@ double SMESH_ElementSearcherImpl::getTolerance()
       }
       else
       {
-        SMDS_ElemIteratorPtr elemIt =
-            _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
+        SMDS_ElemIteratorPtr  elemIt = _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
         const SMDS_MeshElement* elem = elemIt->next();
-        SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
+        SMDS_ElemIteratorPtr  nodeIt = elem->nodesIterator();
         SMESH_TNodeXYZ n1( nodeIt->next() );
         elemSize = 0;
         while ( nodeIt->more() )
         {
           double dist = n1.Distance( static_cast<const SMDS_MeshNode*>( nodeIt->next() ));
-          elemSize = max( dist, elemSize );
+          elemSize = std::max( dist, elemSize );
         }
       }
       _tolerance = 1e-4 * elemSize;
@@ -587,7 +661,7 @@ bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           lin
     anExtCC.Init( lineCurve, edge.Value() );
     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
     {
-      Quantity_Parameter pl, pe;
+      Standard_Real pl, pe;
       anExtCC.LowerDistanceParameters( pl, pe );
       param += pl;
       if ( ++nbInts == 2 )
@@ -611,10 +685,10 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF
   // and BTW find out if there are internal faces at all.
 
   // checked links and links where outer boundary meets internal one
-  set< SMESH_TLink > visitedLinks, seamLinks;
+  std::set< SMESH_TLink > visitedLinks, seamLinks;
 
   // links to treat with already visited faces sharing them
-  list < TFaceLink > startLinks;
+  std::list < TFaceLink > startLinks;
 
   // load startLinks with the first outerFace
   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
@@ -656,8 +730,8 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF
         // direction from the link inside outerFace
         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
         // sort all other faces by angle with the dirInOF
-        map< double, const SMDS_MeshElement* > angle2Face;
-        set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
+        std::map< double, const SMDS_MeshElement* > angle2Face;
+        std::set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
         for ( ; face != faces.end(); ++face )
         {
           if ( *face == outerFace ) continue;
@@ -666,13 +740,13 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF
           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
           if ( angle < 0 ) angle += 2. * M_PI;
-          angle2Face.insert( make_pair( angle, *face ));
+          angle2Face.insert( std::make_pair( angle, *face ));
         }
         if ( !angle2Face.empty() )
           outerFace2 = angle2Face.begin()->second;
       }
     }
-    // store the found outer face and add its links to continue seaching from
+    // store the found outer face and add its links to continue searching from
     if ( outerFace2 )
     {
       _outerFaces.insert( outerFace2 );
@@ -711,11 +785,12 @@ void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerF
 //=======================================================================
 
 int SMESH_ElementSearcherImpl::
-FindElementsByPoint(const gp_Pnt&                      point,
-                    SMDSAbs_ElementType                type,
-                    vector< const SMDS_MeshElement* >& foundElements)
+FindElementsByPoint(const gp_Pnt&                           point,
+                    SMDSAbs_ElementType                     type,
+                    std::vector< const SMDS_MeshElement* >& foundElements)
 {
   foundElements.clear();
+  _elementType = type;
 
   double tolerance = getTolerance();
 
@@ -749,14 +824,13 @@ FindElementsByPoint(const gp_Pnt&                      point,
   // =================================================================================
   else // elements more complex than 0D
   {
-    if ( !_ebbTree || _elementType != type )
+    if ( !_ebbTree[type] )
     {
-      if ( _ebbTree ) delete _ebbTree;
-      _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
+      _ebbTree[_elementType] = new ElementBndBoxTree( *_mesh, type, _meshPartIt, tolerance );
     }
-    TIDSortedElemSet suspectElems;
-    _ebbTree->getElementsNearPoint( point, suspectElems );
-    TIDSortedElemSet::iterator elem = suspectElems.begin();
+    ElementBndBoxTree::TElemSeq suspectElems;
+    _ebbTree[ type ]->getElementsNearPoint( point, suspectElems );
+    ElementBndBoxTree::TElemSeq::iterator elem = suspectElems.begin();
     for ( ; elem != suspectElems.end(); ++elem )
       if ( !SMESH_MeshAlgos::IsOut( *elem, point, tolerance ))
         foundElements.push_back( *elem );
@@ -777,47 +851,49 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
                                           SMDSAbs_ElementType type )
 {
   const SMDS_MeshElement* closestElem = 0;
+  _elementType = type;
 
-  if ( type == SMDSAbs_Face || type == SMDSAbs_Volume )
+  if ( type == SMDSAbs_Face ||
+       type == SMDSAbs_Volume ||
+       type == SMDSAbs_Edge )
   {
-    if ( !_ebbTree || _elementType != type )
-    {
-      if ( _ebbTree ) delete _ebbTree;
-      _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
-    }
-    TIDSortedElemSet suspectElems;
-    _ebbTree->getElementsNearPoint( point, suspectElems );
+    ElementBndBoxTree*& ebbTree = _ebbTree[ type ];
+    if ( !ebbTree )
+      ebbTree = new ElementBndBoxTree( *_mesh, type, _meshPartIt );
+
+    ElementBndBoxTree::TElemSeq suspectElems;
+    ebbTree->getElementsNearPoint( point, suspectElems );
 
-    if ( suspectElems.empty() && _ebbTree->maxSize() > 0 )
+    if ( suspectElems.empty() && ebbTree->maxSize() > 0 )
     {
-      gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox()->CornerMin() +
-                                 _ebbTree->getBox()->CornerMax() );
+      gp_Pnt boxCenter = 0.5 * ( ebbTree->getBox()->CornerMin() +
+                                 ebbTree->getBox()->CornerMax() );
       double radius = -1;
-      if ( _ebbTree->getBox()->IsOut( point.XYZ() ))
-        radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize();
+      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 );
+        ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
         radius *= 1.1;
       }
     }
     double minDist = std::numeric_limits<double>::max();
-    multimap< double, const SMDS_MeshElement* > dist2face;
-    TIDSortedElemSet::iterator elem = suspectElems.begin();
+    std::multimap< double, const SMDS_MeshElement* > dist2face;
+    ElementBndBoxTree::TElemSeq::iterator elem = suspectElems.begin();
     for ( ; elem != suspectElems.end(); ++elem )
     {
       double dist = SMESH_MeshAlgos::GetDistance( *elem, point );
       if ( dist < minDist + 1e-10)
       {
         minDist = dist;
-        dist2face.insert( dist2face.begin(), make_pair( dist, *elem ));
+        dist2face.insert( dist2face.begin(), std::make_pair( dist, *elem ));
       }
     }
     if ( !dist2face.empty() )
     {
-      multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin();
+      std::multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin();
       closestElem = d2f->second;
       // if there are several elements at the same distance, select one
       // with GC closest to the point
@@ -862,33 +938,35 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
 
 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
 {
+  _elementType = SMDSAbs_Face;
+
   double tolerance = getTolerance();
-  if ( !_ebbTree || _elementType != SMDSAbs_Face )
-  {
-    if ( _ebbTree ) delete _ebbTree;
-    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
-  }
+
+  ElementBndBoxTree*& ebbTree = _ebbTree[ SMDSAbs_Face ];
+  if ( !ebbTree )
+    ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
+
   // Algo: analyse transition of a line starting at the point through mesh boundary;
   // try three lines parallel to axis of the coordinate system and perform rough
   // analysis. If solution is not clear perform thorough analysis.
 
   const int nbAxes = 3;
   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
-  map< double, TInters >   paramOnLine2TInters[ nbAxes ];
-  list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
-  multimap< int, int > nbInt2Axis; // to find the simplest case
+  std::map< double, TInters >   paramOnLine2TInters[ nbAxes ];
+  std::list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
+  std::multimap< int, int > nbInt2Axis; // to find the simplest case
   for ( int axis = 0; axis < nbAxes; ++axis )
   {
     gp_Ax1 lineAxis( point, axisDir[axis]);
     gp_Lin line    ( lineAxis );
 
-    TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
-    _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
+    ElementBndBoxTree::TElemSeq suspectFaces; // faces possibly intersecting the line
+    ebbTree->getElementsNearLine( lineAxis, suspectFaces );
 
     // Intersect faces with the line
 
-    map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
-    TIDSortedElemSet::iterator face = suspectFaces.begin();
+    std::map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
+    ElementBndBoxTree::TElemSeq::iterator face = suspectFaces.begin();
     for ( ; face != suspectFaces.end(); ++face )
     {
       // get face plane
@@ -906,9 +984,10 @@ 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 ))
-          u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
+        if ( !SMESH_MeshAlgos::IsOut( *face, intersectionPoint, tol ))
+          u2inters.insert( std::make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
       }
     }
     // Analyse intersections roughly
@@ -932,7 +1011,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
       return TopAbs_IN;
 
-    nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
+    nbInt2Axis.insert( std::make_pair( std::min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
 
     if ( _outerFacesFound ) break; // pass to thorough analysis
 
@@ -946,29 +1025,29 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
 
   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
   {
-    multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
+    std::multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
     {
       int axis = nb_axis->second;
-      map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
+      std::map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
 
       gp_Ax1 lineAxis( point, axisDir[axis]);
       gp_Lin line    ( lineAxis );
 
       // add tangent intersections to u2inters
       double param;
-      list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
+      std::list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
-          u2inters.insert(make_pair( param, *tgtInt ));
+          u2inters.insert( std::make_pair( param, *tgtInt ));
       tangentInters[ axis ].clear();
 
       // Count intersections before and after the point excluding touching ones.
       // If hasPositionInfo we count intersections of outer boundary only
 
       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
-      double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
-      map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
+      double f = std::numeric_limits<double>::max(), l = -std::numeric_limits<double>::max();
+      std::map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
       bool ok = ! u_int1->second._coincides;
       while ( ok && u_int1 != u2inters.end() )
       {
@@ -986,16 +1065,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;
@@ -1014,8 +1096,8 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
           // decide if we skipped a touching intersection
           if ( nbSamePnt + nbTgt > 0 )
           {
-            double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
-            map< double, TInters >::iterator u_int = u_int1;
+            double minDot = std::numeric_limits<double>::max(), maxDot = -minDot;
+            std::map< double, TInters >::iterator u_int = u_int1;
             for ( ; u_int != u_int2; ++u_int )
             {
               if ( u_int->second._coincides ) continue;
@@ -1068,7 +1150,7 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
     if ( !hasPositionInfo )
     {
       // gather info on faces position - is face in the outer boundary or not
-      map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
+      std::map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
       findOuterBoundary( u2inters.begin()->second._face );
     }
 
@@ -1083,18 +1165,20 @@ TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
  */
 //=======================================================================
 
-void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
-                                                     SMDSAbs_ElementType                type,
-                                                     vector< const SMDS_MeshElement* >& foundElems)
+void SMESH_ElementSearcherImpl::
+GetElementsNearLine( const gp_Ax1&                           line,
+                     SMDSAbs_ElementType                     type,
+                     std::vector< const SMDS_MeshElement* >& foundElems)
 {
-  if ( !_ebbTree || _elementType != type )
-  {
-    if ( _ebbTree ) delete _ebbTree;
-    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
-  }
-  TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
-  _ebbTree->getElementsNearLine( line, suspectFaces );
-  foundElems.assign( suspectFaces.begin(), suspectFaces.end());
+  _elementType = type;
+  ElementBndBoxTree*& ebbTree = _ebbTree[ type ];
+  if ( !ebbTree )
+    ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
+
+  ElementBndBoxTree::TElemSeq elems;
+  ebbTree->getElementsNearLine( line, elems );
+
+  foundElems.insert( foundElems.end(), elems.begin(), elems.end() );
 }
 
 //=======================================================================
@@ -1103,19 +1187,93 @@ void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&
  */
 //=======================================================================
 
-void SMESH_ElementSearcherImpl::GetElementsInSphere( const gp_XYZ&                      center,
-                                                     const double                       radius,
-                                                     SMDSAbs_ElementType                type,
-                                                     vector< const SMDS_MeshElement* >& foundElems)
+void SMESH_ElementSearcherImpl::
+GetElementsInSphere( const gp_XYZ&                           center,
+                     const double                            radius,
+                     SMDSAbs_ElementType                     type,
+                     std::vector< const SMDS_MeshElement* >& foundElems)
+{
+  _elementType = type;
+  ElementBndBoxTree*& ebbTree = _ebbTree[ type ];
+  if ( !ebbTree )
+    ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
+
+  ElementBndBoxTree::TElemSeq elems;
+  ebbTree->getElementsInSphere( center, radius, elems );
+
+  foundElems.insert( foundElems.end(), elems.begin(), elems.end() );
+}
+
+//=======================================================================
+/*
+ * Return elements whose bounding box intersects a given bounding box
+ */
+//=======================================================================
+
+void SMESH_ElementSearcherImpl::
+GetElementsInBox( const Bnd_B3d&                          box,
+                  SMDSAbs_ElementType                     type,
+                  std::vector< const SMDS_MeshElement* >& foundElems)
+{
+  _elementType = type;
+  ElementBndBoxTree*& ebbTree = _ebbTree[ type ];
+  if ( !ebbTree )
+    ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt, getTolerance() );
+
+  ElementBndBoxTree::TElemSeq elems;
+  ebbTree->getElementsInBox( box, elems );
+
+  foundElems.insert( foundElems.end(), elems.begin(), elems.end() );
+}
+
+//=======================================================================
+/*
+ * \brief Return a projection of a given point to a mesh.
+ *        Optionally return the closest element
+ */
+//=======================================================================
+
+gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt&            point,
+                                          SMDSAbs_ElementType      type,
+                                          const SMDS_MeshElement** closestElem)
 {
-  if ( !_ebbTree || _elementType != type )
+  _elementType = type;
+  if ( _mesh->GetMeshInfo().NbElements( _elementType ) == 0 )
+    throw SALOME_Exception( LOCALIZED( "No elements of given type in the mesh" ));
+
+  ElementBndBoxTree*& ebbTree = _ebbTree[ _elementType ];
+  if ( !ebbTree )
+    ebbTree = new ElementBndBoxTree( *_mesh, _elementType, _meshPartIt );
+
+  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();
+
+  ElementBndBoxTree::TElemSeq elems;
+  ebbTree->getElementsInSphere( p, radius, elems );
+  while ( elems.empty() )
   {
-    if ( _ebbTree ) delete _ebbTree;
-    _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
+    radius *= 1.5;
+    ebbTree->getElementsInSphere( p, radius, elems );
   }
-  TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
-  _ebbTree->getElementsInSphere( center, radius, suspectFaces );
-  foundElems.assign( suspectFaces.begin(), suspectFaces.end() );
+  gp_XYZ proj, bestProj;
+  const SMDS_MeshElement* elem = 0;
+  double minDist = 2 * radius;
+  ElementBndBoxTree::TElemSeq::iterator e = elems.begin();
+  for ( ; e != elems.end(); ++e )
+  {
+    double d = SMESH_MeshAlgos::GetDistance( *e, p, &proj );
+    if ( d < minDist )
+    {
+      bestProj = proj;
+      elem = *e;
+      minDist = d;
+    }
+  }
+  if ( closestElem ) *closestElem = elem;
+
+  return bestProj;
 }
 
 //=======================================================================
@@ -1133,14 +1291,11 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
 
   // get ordered nodes
 
-  vector< SMESH_TNodeXYZ > xyz;
+  std::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 );
-  }
+  SMDS_NodeIteratorPtr nodeIt = element->interlacedNodesIterator();
+  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
 
@@ -1155,8 +1310,8 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
       faceNorm += edge1 ^ edge2;
     }
-    double normSize = faceNorm.Magnitude();
-    if ( normSize <= tol )
+    double fNormSize = faceNorm.Magnitude();
+    if ( fNormSize <= tol )
     {
       // degenerated face: point is out if it is out of all face edges
       for ( i = 0; i < nbNodes; ++i )
@@ -1167,12 +1322,27 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
       }
       return true;
     }
-    faceNorm /= normSize;
+    faceNorm /= fNormSize;
 
     // 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
@@ -1181,11 +1351,12 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
     // to find intersections of the ray with the boundary.
     gp_Vec ray = n2p;
     gp_Vec plnNorm = ray ^ faceNorm;
-    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
-    vector<double> dist( nbNodes + 1);
+    double n2pSize = plnNorm.Magnitude();
+    if ( n2pSize <= tol ) return false; // point coincides with the first node
+    if ( n2pSize * n2pSize > fNormSize * 100 ) return true; // point is very far
+    plnNorm /= n2pSize;
+    // for each node of the face, compute its signed distance to the cutting plane
+    std::vector<double> dist( nbNodes + 1);
     for ( i = 0; i < nbNodes; ++i )
     {
       gp_Vec n2p( xyz[i], point );
@@ -1194,12 +1365,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 = 0, 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 +1379,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 )
@@ -1232,7 +1400,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin
     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
       return out;
 
-    // ray pass through a face node; analyze transition through an adjacent edge
+    // the ray passes through a face node; analyze transition through an adjacent edge
     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
     gp_Vec edgeAdjacent( p1, p2 );
@@ -1242,6 +1410,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 +1438,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 );
@@ -1353,17 +1523,19 @@ namespace
 //=======================================================================
 
 double SMESH_MeshAlgos::GetDistance( const SMDS_MeshElement* elem,
-                                     const gp_Pnt&           point )
+                                     const gp_Pnt&           point,
+                                     gp_XYZ*                 closestPnt )
 {
   switch ( elem->GetType() )
   {
   case SMDSAbs_Volume:
-    return GetDistance( dynamic_cast<const SMDS_MeshVolume*>( elem ), point);
+    return GetDistance( static_cast<const SMDS_MeshVolume*>( elem ), point, closestPnt );
   case SMDSAbs_Face:
-    return GetDistance( dynamic_cast<const SMDS_MeshFace*>( elem ), point);
+    return GetDistance( static_cast<const SMDS_MeshFace*>( elem ), point, closestPnt );
   case SMDSAbs_Edge:
-    return GetDistance( dynamic_cast<const SMDS_MeshEdge*>( elem ), point);
+    return GetDistance( static_cast<const SMDS_MeshEdge*>( elem ), point, closestPnt );
   case SMDSAbs_Node:
+    if ( closestPnt ) *closestPnt = SMESH_TNodeXYZ( elem );
     return point.Distance( SMESH_TNodeXYZ( elem ));
   default:;
   }
@@ -1379,14 +1551,15 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshElement* elem,
 //=======================================================================
 
 double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
-                                     const gp_Pnt&        point )
+                                     const gp_Pnt&        point,
+                                     gp_XYZ*              closestPnt )
 {
-  double badDistance = -1;
+  const double badDistance = -1;
   if ( !face ) return badDistance;
 
   // coordinates of nodes (medium nodes, if any, ignored)
   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
-  vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
+  std::vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
   xyz.resize( face->NbCornerNodes()+1 );
 
   // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis,
@@ -1410,7 +1583,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
   trsf.SetTransformation( tgtCS );
 
   // move all the nodes to 2D
-  vector<gp_XY> xy( xyz.size() );
+  std::vector<gp_XY> xy( xyz.size() );
   for ( size_t i = 0;i < xyz.size()-1; ++i )
   {
     gp_XYZ p3d = xyz[i];
@@ -1425,8 +1598,8 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
   trsf.Transforms( tmpPnt );
   gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
 
-  // loop on segments of the face to analyze point position ralative to the face
-  set< PointPos > pntPosSet;
+  // loop on edges of the face to analyze point position ralative to the face
+  std::set< PointPos > pntPosSet;
   for ( size_t i = 1; i < xy.size(); ++i )
   {
     PointPos pos = getPointPosition( point2D, &xy[0], i-1 );
@@ -1435,31 +1608,40 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
 
   // compute distance
   PointPos pos = *pntPosSet.begin();
-  // cout << "Face " << face->GetID() << " DIST: ";
   switch ( pos._name )
   {
-  case POS_LEFT: {
-    // point is most close to a segment
-    gp_Vec p0p1( point, xyz[ pos._index ] );
-    gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector
-    p1p2.Normalize();
-    double projDist = p0p1 * p1p2; // distance projected to the segment
-    gp_Vec projVec = p1p2 * projDist;
-    gp_Vec distVec = p0p1 - projVec;
-    // cout << distVec.Magnitude()  << ", SEG " << face->GetNode(pos._index)->GetID()
-    //      << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl;
-    return distVec.Magnitude();
+  case POS_LEFT:
+  {
+    // point is most close to an edge
+    gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]);
+    gp_Vec n1p ( xyz[ pos._index ], point  );
+    double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
+    // projection of the point on the edge
+    gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ();
+    if ( closestPnt ) *closestPnt = proj;
+    return point.Distance( proj );
   }
-  case POS_RIGHT: {
+  case POS_RIGHT:
+  {
     // point is inside the face
-    double distToFacePlane = tmpPnt.Y();
-    // cout << distToFacePlane << ", INSIDE " << endl;
-    return Abs( distToFacePlane );
+    double distToFacePlane = Abs( tmpPnt.Y() );
+    if ( closestPnt )
+    {
+      if ( distToFacePlane < std::numeric_limits<double>::min() ) {
+        *closestPnt = point.XYZ();
+      }
+      else {
+        tmpPnt.SetY( 0 );
+        trsf.Inverted().Transforms( tmpPnt );
+        *closestPnt = tmpPnt;
+      }
+    }
+    return distToFacePlane;
   }
-  case POS_VERTEX: {
+  case POS_VERTEX:
+  {
     // point is most close to a node
     gp_Vec distVec( point, xyz[ pos._index ]);
-    // cout << distVec.Magnitude()  << " VERTEX " << face->GetNode(pos._index)->GetID() << endl;
     return distVec.Magnitude();
   }
   default:;
@@ -1473,32 +1655,42 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
  */
 //=======================================================================
 
-double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, const gp_Pnt& point )
+double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg,
+                                     const gp_Pnt&        point,
+                                     gp_XYZ*              closestPnt )
 {
   double dist = Precision::Infinite();
   if ( !seg ) return dist;
 
   int i = 0, nbNodes = seg->NbNodes();
 
-  vector< SMESH_TNodeXYZ > xyz( nbNodes );
-  SMDS_ElemIteratorPtr nodeIt = seg->interlacedNodesElemIterator();
-  while ( nodeIt->more() )
-    xyz[ i++ ].Set( nodeIt->next() );
+  std::vector< SMESH_TNodeXYZ > xyz( nbNodes );
+  for ( SMDS_NodeIteratorPtr nodeIt = seg->interlacedNodesIterator(); nodeIt->more(); i++ )
+    xyz[ i ].Set( nodeIt->next() );
 
   for ( i = 1; i < nbNodes; ++i )
   {
     gp_Vec edge( xyz[i-1], xyz[i] );
     gp_Vec n1p ( xyz[i-1], point  );
-    double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
+    double d, u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
     if ( u <= 0. ) {
-      dist = Min( dist, n1p.SquareMagnitude() );
+      if (( d = n1p.SquareMagnitude() ) < dist ) {
+        dist = d;
+        if ( closestPnt ) *closestPnt = xyz[i-1];
+      }
     }
     else if ( u >= 1. ) {
-      dist = Min( dist, point.SquareDistance( xyz[i] ));
+      if (( d = point.SquareDistance( xyz[i] )) < dist ) {
+        dist = d;
+        if ( closestPnt ) *closestPnt = xyz[i];
+      }
     }
     else {
-      gp_XYZ proj = ( 1. - u ) * xyz[i-1] + u * xyz[i]; // projection of the point on the edge
-      dist = Min( dist, point.SquareDistance( proj ));
+      gp_XYZ proj = xyz[i-1] + u * edge.XYZ(); // projection of the point on the edge
+      if (( d = point.SquareDistance( proj )) < dist ) {
+        dist = d;
+        if ( closestPnt ) *closestPnt = proj;
+      }
     }
   }
   return Sqrt( dist );
@@ -1512,7 +1704,9 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* seg, const gp_Pnt& poi
  */
 //=======================================================================
 
-double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point )
+double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume,
+                                     const gp_Pnt&          point,
+                                     gp_XYZ*                closestPnt )
 {
   SMDS_VolumeTool vTool( volume );
   vTool.SetExternalNormal();
@@ -1520,6 +1714,8 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt
 
   double n[3], bc[3];
   double minDist = 1e100, dist;
+  gp_XYZ closeP = point.XYZ();
+  bool isOut = false;
   for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
   {
     // skip a facet with normal not "looking at" the point
@@ -1536,23 +1732,34 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt
     case 3:
     {
       SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ] );
-      dist = GetDistance( &tmpFace, point );
+      dist = GetDistance( &tmpFace, point, closestPnt );
       break;
     }
     case 4:
     {
       SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ], nodes[ 3*iQ ]);
-      dist = GetDistance( &tmpFace, point );
+      dist = GetDistance( &tmpFace, point, closestPnt );
       break;
     }
     default:
-      vector<const SMDS_MeshNode *> nvec( nodes, nodes + vTool.NbFaceNodes( iF ));
+      std::vector<const SMDS_MeshNode *> nvec( nodes, nodes + vTool.NbFaceNodes( iF ));
       SMDS_PolygonalFaceOfNodes tmpFace( nvec );
-      dist = GetDistance( &tmpFace, point );
+      dist = GetDistance( &tmpFace, point, closestPnt );
+    }
+    if ( dist < minDist )
+    {
+      minDist = dist;
+      isOut = true;
+      if ( closestPnt ) closeP = *closestPnt;
     }
-    minDist = Min( minDist, dist );
   }
-  return minDist;
+  if ( isOut )
+  {
+    if ( closestPnt ) *closestPnt = closeP;
+    return minDist;
+  }
+
+  return 0; // point is inside the volume
 }
 
 //================================================================================
@@ -1583,7 +1790,7 @@ void SMESH_MeshAlgos::GetBarycentricCoords( const gp_XY& p,
   const double t11 = T22, t12 = -T12, t21 = -T21, t22 = T11;
   // vector
   const double r11 = p.X()-t2.X(), r12 = p.Y()-t2.Y();
-  // barycentric coordinates: mutiply matrix by vector
+  // barycentric coordinates: multiply matrix by vector
   bc0 = (t11 * r11 + t12 * r12)/Tdet;
   bc1 = (t21 * r11 + t22 * r12)/Tdet;
 }
@@ -1629,7 +1836,7 @@ SMESH_MeshAlgos::FindFaceInSet(const SMDS_MeshNode*    n1,
     if ( !face && elem->IsQuadratic())
     {
       // analysis for quadratic elements using all nodes
-      SMDS_ElemIteratorPtr anIter = elem->interlacedNodesElemIterator();
+      SMDS_NodeIteratorPtr anIter = elem->interlacedNodesIterator();
       const SMDS_MeshNode* prevN = static_cast<const SMDS_MeshNode*>( anIter->next() );
       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
       {
@@ -1640,7 +1847,7 @@ SMESH_MeshAlgos::FindFaceInSet(const SMDS_MeshNode*    n1,
         }
         else if ( n2 == prevN && n1 == n )
         {
-          face = elem; swap( i1, i2 );
+          face = elem; std::swap( i1, i2 );
         }
         prevN = n;
       }
@@ -1675,7 +1882,7 @@ bool SMESH_MeshAlgos::FaceNormal(const SMDS_MeshElement* F, gp_XYZ& normal, bool
     normal += ( p[2] - p[1] ) ^ ( p[0] - p[1] );
   }
   double size2 = normal.SquareModulus();
-  bool ok = ( size2 > numeric_limits<double>::min() * numeric_limits<double>::min());
+  bool ok = ( size2 > std::numeric_limits<double>::min() * std::numeric_limits<double>::min());
   if ( normalized && ok )
     normal /= sqrt( size2 );
 
@@ -1687,15 +1894,43 @@ bool SMESH_MeshAlgos::FaceNormal(const SMDS_MeshElement* F, gp_XYZ& normal, bool
 //purpose  : Return nodes common to two elements
 //=======================================================================
 
-vector< const SMDS_MeshNode*> SMESH_MeshAlgos::GetCommonNodes(const SMDS_MeshElement* e1,
-                                                              const SMDS_MeshElement* e2)
+std::vector< const SMDS_MeshNode*> SMESH_MeshAlgos::GetCommonNodes(const SMDS_MeshElement* e1,
+                                                                   const SMDS_MeshElement* e2)
 {
-  vector< const SMDS_MeshNode*> common;
+  std::vector< const SMDS_MeshNode*> common;
   for ( int i = 0 ; i < e1->NbNodes(); ++i )
     if ( e2->GetNodeIndex( e1->GetNode( i )) >= 0 )
       common.push_back( e1->GetNode( i ));
   return common;
 }
+//================================================================================
+/*!
+ * \brief Return true if node1 encounters first in the face and node2, after
+ */
+//================================================================================
+
+bool SMESH_MeshAlgos::IsRightOrder( const SMDS_MeshElement* face,
+                                    const SMDS_MeshNode*    node0,
+                                    const SMDS_MeshNode*    node1 )
+{
+  int i0 = face->GetNodeIndex( node0 );
+  int i1 = face->GetNodeIndex( node1 );
+  if ( face->IsQuadratic() )
+  {
+    if ( face->IsMediumNode( node0 ))
+    {
+      i0 -= ( face->NbNodes()/2 - 1 );
+      i1 *= 2;
+    }
+    else
+    {
+      i1 -= ( face->NbNodes()/2 - 1 );
+      i0 *= 2;
+    }
+  }
+  int diff = i1 - i0;
+  return ( diff == 1 ) || ( diff == -face->NbNodes()+1 );
+}
 
 //=======================================================================
 /*!