Salome HOME
22316: EDF 2719 SMESH: Split hexas into prisms
[modules/smesh.git] / src / SMESHUtils / SMESH_MeshAlgos.cxx
1 // Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 // File      : SMESH_MeshAlgos.hxx
23 // Created   : Tue Apr 30 18:00:36 2013
24 // Author    : Edward AGAPOV (eap)
25
26 // This file holds some low level algorithms extracted from SMESH_MeshEditor
27 // to make them accessible from Controls package
28
29 #include "SMESH_MeshAlgos.hxx"
30
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_LinearEdge.hxx"
33 #include "SMDS_Mesh.hxx"
34 #include "SMDS_PolygonalFaceOfNodes.hxx"
35 #include "SMDS_VolumeTool.hxx"
36 #include "SMESH_OctreeNode.hxx"
37
38 #include <GC_MakeSegment.hxx>
39 #include <GeomAPI_ExtremaCurveCurve.hxx>
40 #include <Geom_Line.hxx>
41 #include <IntAna_IntConicQuad.hxx>
42 #include <IntAna_Quadric.hxx>
43 #include <gp_Lin.hxx>
44 #include <gp_Pln.hxx>
45
46 #include <limits>
47 #include <numeric>
48
49 using namespace std;
50
51 //=======================================================================
52 /*!
53  * \brief Implementation of search for the node closest to point
54  */
55 //=======================================================================
56
57 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
58 {
59   //---------------------------------------------------------------------
60   /*!
61    * \brief Constructor
62    */
63   SMESH_NodeSearcherImpl( const SMDS_Mesh* theMesh )
64   {
65     myMesh = ( SMDS_Mesh* ) theMesh;
66
67     TIDSortedNodeSet nodes;
68     if ( theMesh ) {
69       SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
70       while ( nIt->more() )
71         nodes.insert( nodes.end(), nIt->next() );
72     }
73     myOctreeNode = new SMESH_OctreeNode(nodes) ;
74
75     // get max size of a leaf box
76     SMESH_OctreeNode* tree = myOctreeNode;
77     while ( !tree->isLeaf() )
78     {
79       SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
80       if ( cIt->more() )
81         tree = cIt->next();
82     }
83     myHalfLeafSize = tree->maxSize() / 2.;
84   }
85
86   //---------------------------------------------------------------------
87   /*!
88    * \brief Move node and update myOctreeNode accordingly
89    */
90   void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
91   {
92     myOctreeNode->UpdateByMoveNode( node, toPnt );
93     myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
94   }
95
96   //---------------------------------------------------------------------
97   /*!
98    * \brief Do it's job
99    */
100   const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
101   {
102     map<double, const SMDS_MeshNode*> dist2Nodes;
103     myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
104     if ( !dist2Nodes.empty() )
105       return dist2Nodes.begin()->second;
106     list<const SMDS_MeshNode*> nodes;
107     //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
108
109     double minSqDist = DBL_MAX;
110     if ( nodes.empty() )  // get all nodes of OctreeNode's closest to thePnt
111     {
112       // sort leafs by their distance from thePnt
113       typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
114       TDistTreeMap treeMap;
115       list< SMESH_OctreeNode* > treeList;
116       list< SMESH_OctreeNode* >::iterator trIt;
117       treeList.push_back( myOctreeNode );
118
119       gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
120       bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
121       for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
122       {
123         SMESH_OctreeNode* tree = *trIt;
124         if ( !tree->isLeaf() ) // put children to the queue
125         {
126           if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
127           SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
128           while ( cIt->more() )
129             treeList.push_back( cIt->next() );
130         }
131         else if ( tree->NbNodes() ) // put a tree to the treeMap
132         {
133           const Bnd_B3d& box = *tree->getBox();
134           double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
135           pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
136           if ( !it_in.second ) // not unique distance to box center
137             treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
138         }
139       }
140       // find distance after which there is no sense to check tree's
141       double sqLimit = DBL_MAX;
142       TDistTreeMap::iterator sqDist_tree = treeMap.begin();
143       if ( treeMap.size() > 5 ) {
144         SMESH_OctreeNode* closestTree = sqDist_tree->second;
145         const Bnd_B3d& box = *closestTree->getBox();
146         double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
147         sqLimit = limit * limit;
148       }
149       // get all nodes from trees
150       for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
151         if ( sqDist_tree->first > sqLimit )
152           break;
153         SMESH_OctreeNode* tree = sqDist_tree->second;
154         tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
155       }
156     }
157     // find closest among nodes
158     minSqDist = DBL_MAX;
159     const SMDS_MeshNode* closestNode = 0;
160     list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
161     for ( ; nIt != nodes.end(); ++nIt ) {
162       double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
163       if ( minSqDist > sqDist ) {
164         closestNode = *nIt;
165         minSqDist = sqDist;
166       }
167     }
168     return closestNode;
169   }
170
171   //---------------------------------------------------------------------
172   /*!
173    * \brief Destructor
174    */
175   ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
176
177   //---------------------------------------------------------------------
178   /*!
179    * \brief Return the node tree
180    */
181   const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
182
183 private:
184   SMESH_OctreeNode* myOctreeNode;
185   SMDS_Mesh*        myMesh;
186   double            myHalfLeafSize; // max size of a leaf box
187 };
188
189 // ========================================================================
190 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
191 {
192   const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
193   const int MaxLevel         = 7;  // maximal tree height -> nb terminal boxes: 8^7 = 2097152
194   const double NodeRadius = 1e-9;  // to enlarge bnd box of element
195
196   //=======================================================================
197   /*!
198    * \brief Octal tree of bounding boxes of elements
199    */
200   //=======================================================================
201
202   class ElementBndBoxTree : public SMESH_Octree
203   {
204   public:
205
206     ElementBndBoxTree(const SMDS_Mesh&     mesh,
207                       SMDSAbs_ElementType  elemType,
208                       SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(),
209                       double               tolerance = NodeRadius );
210     void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems );
211     void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
212     void getElementsInSphere ( const gp_XYZ& center,
213                                const double  radius, TIDSortedElemSet& foundElems);
214     size_t getSize() { return std::max( _size, _elements.size() ); }
215     virtual ~ElementBndBoxTree();
216
217   protected:
218     ElementBndBoxTree():_size(0) {}
219     SMESH_Octree* newChild() const { return new ElementBndBoxTree; }
220     void          buildChildrenData();
221     Bnd_B3d*      buildRootBox();
222   private:
223     //!< Bounding box of element
224     struct ElementBox : public Bnd_B3d
225     {
226       const SMDS_MeshElement* _element;
227       int                     _refCount; // an ElementBox can be included in several tree branches
228       ElementBox(const SMDS_MeshElement* elem, double tolerance);
229     };
230     vector< ElementBox* > _elements;
231     size_t                _size;
232   };
233
234   //================================================================================
235   /*!
236    * \brief ElementBndBoxTree creation
237    */
238   //================================================================================
239
240   ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
241     :SMESH_Octree( new SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ))
242   {
243     int nbElems = mesh.GetMeshInfo().NbElements( elemType );
244     _elements.reserve( nbElems );
245
246     SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
247     while ( elemIt->more() )
248       _elements.push_back( new ElementBox( elemIt->next(),tolerance  ));
249
250     compute();
251   }
252
253   //================================================================================
254   /*!
255    * \brief Destructor
256    */
257   //================================================================================
258
259   ElementBndBoxTree::~ElementBndBoxTree()
260   {
261     for ( int i = 0; i < _elements.size(); ++i )
262       if ( --_elements[i]->_refCount <= 0 )
263         delete _elements[i];
264   }
265
266   //================================================================================
267   /*!
268    * \brief Return the maximal box
269    */
270   //================================================================================
271
272   Bnd_B3d* ElementBndBoxTree::buildRootBox()
273   {
274     Bnd_B3d* box = new Bnd_B3d;
275     for ( int i = 0; i < _elements.size(); ++i )
276       box->Add( *_elements[i] );
277     return box;
278   }
279
280   //================================================================================
281   /*!
282    * \brief Redistrubute element boxes among children
283    */
284   //================================================================================
285
286   void ElementBndBoxTree::buildChildrenData()
287   {
288     for ( int i = 0; i < _elements.size(); ++i )
289     {
290       for (int j = 0; j < 8; j++)
291       {
292         if ( !_elements[i]->IsOut( *myChildren[j]->getBox() ))
293         {
294           _elements[i]->_refCount++;
295           ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
296         }
297       }
298       _elements[i]->_refCount--;
299     }
300     _size = _elements.size();
301     SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory
302
303     for (int j = 0; j < 8; j++)
304     {
305       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
306       if ( child->_elements.size() <= MaxNbElemsInLeaf )
307         child->myIsLeaf = true;
308
309       if ( child->_elements.capacity() - child->_elements.size() > 1000 )
310         SMESHUtils::CompactVector( child->_elements );
311     }
312   }
313
314   //================================================================================
315   /*!
316    * \brief Return elements which can include the point
317    */
318   //================================================================================
319
320   void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt&     point,
321                                                 TIDSortedElemSet& foundElems)
322   {
323     if ( getBox()->IsOut( point.XYZ() ))
324       return;
325
326     if ( isLeaf() )
327     {
328       for ( int i = 0; i < _elements.size(); ++i )
329         if ( !_elements[i]->IsOut( point.XYZ() ))
330           foundElems.insert( _elements[i]->_element );
331     }
332     else
333     {
334       for (int i = 0; i < 8; i++)
335         ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
336     }
337   }
338
339   //================================================================================
340   /*!
341    * \brief Return elements which can be intersected by the line
342    */
343   //================================================================================
344
345   void ElementBndBoxTree::getElementsNearLine( const gp_Ax1&     line,
346                                                TIDSortedElemSet& foundElems)
347   {
348     if ( getBox()->IsOut( line ))
349       return;
350
351     if ( isLeaf() )
352     {
353       for ( int i = 0; i < _elements.size(); ++i )
354         if ( !_elements[i]->IsOut( line ))
355           foundElems.insert( _elements[i]->_element );
356     }
357     else
358     {
359       for (int i = 0; i < 8; i++)
360         ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
361     }
362   }
363
364   //================================================================================
365   /*!
366    * \brief Return elements from leaves intersecting the sphere
367    */
368   //================================================================================
369
370   void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ&     center,
371                                                 const double      radius,
372                                                 TIDSortedElemSet& foundElems)
373   {
374     if ( getBox()->IsOut( center, radius ))
375       return;
376
377     if ( isLeaf() )
378     {
379       for ( int i = 0; i < _elements.size(); ++i )
380         if ( !_elements[i]->IsOut( center, radius ))
381           foundElems.insert( _elements[i]->_element );
382     }
383     else
384     {
385       for (int i = 0; i < 8; i++)
386         ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems );
387     }
388   }
389
390   //================================================================================
391   /*!
392    * \brief Construct the element box
393    */
394   //================================================================================
395
396   ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
397   {
398     _element  = elem;
399     _refCount = 1;
400     SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
401     while ( nIt->more() )
402       Add( SMESH_TNodeXYZ( nIt->next() ));
403     Enlarge( tolerance );
404   }
405
406 } // namespace
407
408 //=======================================================================
409 /*!
410  * \brief Implementation of search for the elements by point and
411  *        of classification of point in 2D mesh
412  */
413 //=======================================================================
414
415 SMESH_ElementSearcher::~SMESH_ElementSearcher()
416 {
417 }
418
419 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
420 {
421   SMDS_Mesh*                   _mesh;
422   SMDS_ElemIteratorPtr         _meshPartIt;
423   ElementBndBoxTree*           _ebbTree;
424   SMESH_NodeSearcherImpl*      _nodeSearcher;
425   SMDSAbs_ElementType          _elementType;
426   double                       _tolerance;
427   bool                         _outerFacesFound;
428   set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
429
430   SMESH_ElementSearcherImpl( SMDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
431     : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
432   virtual ~SMESH_ElementSearcherImpl()
433   {
434     if ( _ebbTree )      delete _ebbTree;      _ebbTree      = 0;
435     if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
436   }
437   virtual int FindElementsByPoint(const gp_Pnt&                      point,
438                                   SMDSAbs_ElementType                type,
439                                   vector< const SMDS_MeshElement* >& foundElements);
440   virtual TopAbs_State GetPointState(const gp_Pnt& point);
441   virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt&       point,
442                                                  SMDSAbs_ElementType type );
443
444   void GetElementsNearLine( const gp_Ax1&                      line,
445                             SMDSAbs_ElementType                type,
446                             vector< const SMDS_MeshElement* >& foundElems);
447   double getTolerance();
448   bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
449                             const double tolerance, double & param);
450   void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
451   bool isOuterBoundary(const SMDS_MeshElement* face) const
452   {
453     return _outerFaces.empty() || _outerFaces.count(face);
454   }
455   struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
456   {
457     const SMDS_MeshElement* _face;
458     gp_Vec                  _faceNorm;
459     bool                    _coincides; //!< the line lays in face plane
460     TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
461       : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
462   };
463   struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
464   {
465     SMESH_TLink      _link;
466     TIDSortedElemSet _faces;
467     TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
468       : _link( n1, n2 ), _faces( &face, &face + 1) {}
469   };
470 };
471
472 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
473 {
474   return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
475              << ", _coincides="<<i._coincides << ")";
476 }
477
478 //=======================================================================
479 /*!
480  * \brief define tolerance for search
481  */
482 //=======================================================================
483
484 double SMESH_ElementSearcherImpl::getTolerance()
485 {
486   if ( _tolerance < 0 )
487   {
488     const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
489
490     _tolerance = 0;
491     if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
492     {
493       double boxSize = _nodeSearcher->getTree()->maxSize();
494       _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
495     }
496     else if ( _ebbTree && meshInfo.NbElements() > 0 )
497     {
498       double boxSize = _ebbTree->maxSize();
499       _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
500     }
501     if ( _tolerance == 0 )
502     {
503       // define tolerance by size of a most complex element
504       int complexType = SMDSAbs_Volume;
505       while ( complexType > SMDSAbs_All &&
506               meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
507         --complexType;
508       if ( complexType == SMDSAbs_All ) return 0; // empty mesh
509       double elemSize;
510       if ( complexType == int( SMDSAbs_Node ))
511       {
512         SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
513         elemSize = 1;
514         if ( meshInfo.NbNodes() > 2 )
515           elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
516       }
517       else
518       {
519         SMDS_ElemIteratorPtr elemIt =
520             _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
521         const SMDS_MeshElement* elem = elemIt->next();
522         SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
523         SMESH_TNodeXYZ n1( nodeIt->next() );
524         elemSize = 0;
525         while ( nodeIt->more() )
526         {
527           double dist = n1.Distance( static_cast<const SMDS_MeshNode*>( nodeIt->next() ));
528           elemSize = max( dist, elemSize );
529         }
530       }
531       _tolerance = 1e-4 * elemSize;
532     }
533   }
534   return _tolerance;
535 }
536
537 //================================================================================
538 /*!
539  * \brief Find intersection of the line and an edge of face and return parameter on line
540  */
541 //================================================================================
542
543 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin&           line,
544                                                      const SMDS_MeshElement* face,
545                                                      const double            tol,
546                                                      double &                param)
547 {
548   int nbInts = 0;
549   param = 0;
550
551   GeomAPI_ExtremaCurveCurve anExtCC;
552   Handle(Geom_Curve) lineCurve = new Geom_Line( line );
553
554   int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
555   for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
556   {
557     GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
558                          SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
559     anExtCC.Init( lineCurve, edge);
560     if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
561     {
562       Quantity_Parameter pl, pe;
563       anExtCC.LowerDistanceParameters( pl, pe );
564       param += pl;
565       if ( ++nbInts == 2 )
566         break;
567     }
568   }
569   if ( nbInts > 0 ) param /= nbInts;
570   return nbInts > 0;
571 }
572 //================================================================================
573 /*!
574  * \brief Find all faces belonging to the outer boundary of mesh
575  */
576 //================================================================================
577
578 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
579 {
580   if ( _outerFacesFound ) return;
581
582   // Collect all outer faces by passing from one outer face to another via their links
583   // and BTW find out if there are internal faces at all.
584
585   // checked links and links where outer boundary meets internal one
586   set< SMESH_TLink > visitedLinks, seamLinks;
587
588   // links to treat with already visited faces sharing them
589   list < TFaceLink > startLinks;
590
591   // load startLinks with the first outerFace
592   startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
593   _outerFaces.insert( outerFace );
594
595   TIDSortedElemSet emptySet;
596   while ( !startLinks.empty() )
597   {
598     const SMESH_TLink& link  = startLinks.front()._link;
599     TIDSortedElemSet&  faces = startLinks.front()._faces;
600
601     outerFace = *faces.begin();
602     // find other faces sharing the link
603     const SMDS_MeshElement* f;
604     while (( f = SMESH_MeshAlgos::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
605       faces.insert( f );
606
607     // select another outer face among the found
608     const SMDS_MeshElement* outerFace2 = 0;
609     if ( faces.size() == 2 )
610     {
611       outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
612     }
613     else if ( faces.size() > 2 )
614     {
615       seamLinks.insert( link );
616
617       // link direction within the outerFace
618       gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
619                    SMESH_TNodeXYZ( link.node2()));
620       int i1 = outerFace->GetNodeIndex( link.node1() );
621       int i2 = outerFace->GetNodeIndex( link.node2() );
622       bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
623       if ( rev ) n1n2.Reverse();
624       // outerFace normal
625       gp_XYZ ofNorm, fNorm;
626       if ( SMESH_MeshAlgos::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
627       {
628         // direction from the link inside outerFace
629         gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
630         // sort all other faces by angle with the dirInOF
631         map< double, const SMDS_MeshElement* > angle2Face;
632         set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
633         for ( ; face != faces.end(); ++face )
634         {
635           if ( !SMESH_MeshAlgos::FaceNormal( *face, fNorm, /*normalized=*/false ))
636             continue;
637           gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
638           double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
639           if ( angle < 0 ) angle += 2. * M_PI;
640           angle2Face.insert( make_pair( angle, *face ));
641         }
642         if ( !angle2Face.empty() )
643           outerFace2 = angle2Face.begin()->second;
644       }
645     }
646     // store the found outer face and add its links to continue seaching from
647     if ( outerFace2 )
648     {
649       _outerFaces.insert( outerFace );
650       int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
651       for ( int i = 0; i < nbNodes; ++i )
652       {
653         SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
654         if ( visitedLinks.insert( link2 ).second )
655           startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
656       }
657     }
658     startLinks.pop_front();
659   }
660   _outerFacesFound = true;
661
662   if ( !seamLinks.empty() )
663   {
664     // There are internal boundaries touching the outher one,
665     // find all faces of internal boundaries in order to find
666     // faces of boundaries of holes, if any.
667
668   }
669   else
670   {
671     _outerFaces.clear();
672   }
673 }
674
675 //=======================================================================
676 /*!
677  * \brief Find elements of given type where the given point is IN or ON.
678  *        Returns nb of found elements and elements them-selves.
679  *
680  * 'ALL' type means elements of any type excluding nodes, balls and 0D elements
681  */
682 //=======================================================================
683
684 int SMESH_ElementSearcherImpl::
685 FindElementsByPoint(const gp_Pnt&                      point,
686                     SMDSAbs_ElementType                type,
687                     vector< const SMDS_MeshElement* >& foundElements)
688 {
689   foundElements.clear();
690
691   double tolerance = getTolerance();
692
693   // =================================================================================
694   if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement || type == SMDSAbs_Ball)
695   {
696     if ( !_nodeSearcher )
697       _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
698
699     const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
700     if ( !closeNode ) return foundElements.size();
701
702     if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
703       return foundElements.size(); // to far from any node
704
705     if ( type == SMDSAbs_Node )
706     {
707       foundElements.push_back( closeNode );
708     }
709     else
710     {
711       SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( type );
712       while ( elemIt->more() )
713         foundElements.push_back( elemIt->next() );
714     }
715   }
716   // =================================================================================
717   else // elements more complex than 0D
718   {
719     if ( !_ebbTree || _elementType != type )
720     {
721       if ( _ebbTree ) delete _ebbTree;
722       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
723     }
724     TIDSortedElemSet suspectElems;
725     _ebbTree->getElementsNearPoint( point, suspectElems );
726     TIDSortedElemSet::iterator elem = suspectElems.begin();
727     for ( ; elem != suspectElems.end(); ++elem )
728       if ( !SMESH_MeshAlgos::IsOut( *elem, point, tolerance ))
729         foundElements.push_back( *elem );
730   }
731   return foundElements.size();
732 }
733
734 //=======================================================================
735 /*!
736  * \brief Find an element of given type most close to the given point
737  *
738  * WARNING: Only face search is implemeneted so far
739  */
740 //=======================================================================
741
742 const SMDS_MeshElement*
743 SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt&       point,
744                                           SMDSAbs_ElementType type )
745 {
746   const SMDS_MeshElement* closestElem = 0;
747
748   if ( type == SMDSAbs_Face || type == SMDSAbs_Volume )
749   {
750     if ( !_ebbTree || _elementType != type )
751     {
752       if ( _ebbTree ) delete _ebbTree;
753       _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
754     }
755     TIDSortedElemSet suspectElems;
756     _ebbTree->getElementsNearPoint( point, suspectElems );
757
758     if ( suspectElems.empty() && _ebbTree->maxSize() > 0 )
759     {
760       gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox()->CornerMin() +
761                                  _ebbTree->getBox()->CornerMax() );
762       double radius;
763       if ( _ebbTree->getBox()->IsOut( point.XYZ() ))
764         radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize();
765       else
766         radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2;
767       while ( suspectElems.empty() )
768       {
769         _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
770         radius *= 1.1;
771       }
772     }
773     double minDist = std::numeric_limits<double>::max();
774     multimap< double, const SMDS_MeshElement* > dist2face;
775     TIDSortedElemSet::iterator elem = suspectElems.begin();
776     for ( ; elem != suspectElems.end(); ++elem )
777     {
778       double dist = SMESH_MeshAlgos::GetDistance( *elem, point );
779       if ( dist < minDist + 1e-10)
780       {
781         minDist = dist;
782         dist2face.insert( dist2face.begin(), make_pair( dist, *elem ));
783       }
784     }
785     if ( !dist2face.empty() )
786     {
787       multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin();
788       closestElem = d2f->second;
789       // if there are several elements at the same distance, select one
790       // with GC closest to the point
791       typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
792       double minDistToGC = 0;
793       for ( ++d2f; d2f != dist2face.end() && fabs( d2f->first - minDist ) < 1e-10; ++d2f )
794       {
795         if ( minDistToGC == 0 )
796         {
797           gp_XYZ gc(0,0,0);
798           gc = accumulate( TXyzIterator(closestElem->nodesIterator()),
799                            TXyzIterator(), gc ) / closestElem->NbNodes();
800           minDistToGC = point.SquareDistance( gc );
801         }
802         gp_XYZ gc(0,0,0);
803         gc = accumulate( TXyzIterator( d2f->second->nodesIterator()),
804                          TXyzIterator(), gc ) / d2f->second->NbNodes();
805         double d = point.SquareDistance( gc );
806         if ( d < minDistToGC )
807         {
808           minDistToGC = d;
809           closestElem = d2f->second;
810         }
811       }
812       // cout << "FindClosestTo( " <<point.X()<<", "<<point.Y()<<", "<<point.Z()<<" ) FACE "
813       //      <<closestElem->GetID() << " DIST " << minDist << endl;
814     }
815   }
816   else
817   {
818     // NOT IMPLEMENTED SO FAR
819   }
820   return closestElem;
821 }
822
823
824 //================================================================================
825 /*!
826  * \brief Classify the given point in the closed 2D mesh
827  */
828 //================================================================================
829
830 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
831 {
832   double tolerance = getTolerance();
833   if ( !_ebbTree || _elementType != SMDSAbs_Face )
834   {
835     if ( _ebbTree ) delete _ebbTree;
836     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
837   }
838   // Algo: analyse transition of a line starting at the point through mesh boundary;
839   // try three lines parallel to axis of the coordinate system and perform rough
840   // analysis. If solution is not clear perform thorough analysis.
841
842   const int nbAxes = 3;
843   gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
844   map< double, TInters >   paramOnLine2TInters[ nbAxes ];
845   list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
846   multimap< int, int > nbInt2Axis; // to find the simplest case
847   for ( int axis = 0; axis < nbAxes; ++axis )
848   {
849     gp_Ax1 lineAxis( point, axisDir[axis]);
850     gp_Lin line    ( lineAxis );
851
852     TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
853     _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
854
855     // Intersect faces with the line
856
857     map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
858     TIDSortedElemSet::iterator face = suspectFaces.begin();
859     for ( ; face != suspectFaces.end(); ++face )
860     {
861       // get face plane
862       gp_XYZ fNorm;
863       if ( !SMESH_MeshAlgos::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
864       gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
865
866       // perform intersection
867       IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
868       if ( !intersection.IsDone() )
869         continue;
870       if ( intersection.IsInQuadric() )
871       {
872         tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
873       }
874       else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
875       {
876         gp_Pnt intersectionPoint = intersection.Point(1);
877         if ( !SMESH_MeshAlgos::IsOut( *face, intersectionPoint, tolerance ))
878           u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
879       }
880     }
881     // Analyse intersections roughly
882
883     int nbInter = u2inters.size();
884     if ( nbInter == 0 )
885       return TopAbs_OUT;
886
887     double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
888     if ( nbInter == 1 ) // not closed mesh
889       return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
890
891     if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
892       return TopAbs_ON;
893
894     if ( (f<0) == (l<0) )
895       return TopAbs_OUT;
896
897     int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
898     int nbIntAfterPoint  = nbInter - nbIntBeforePoint;
899     if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
900       return TopAbs_IN;
901
902     nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
903
904     if ( _outerFacesFound ) break; // pass to thorough analysis
905
906   } // three attempts - loop on CS axes
907
908   // Analyse intersections thoroughly.
909   // We make two loops maximum, on the first one we only exclude touching intersections,
910   // on the second, if situation is still unclear, we gather and use information on
911   // position of faces (internal or outer). If faces position is already gathered,
912   // we make the second loop right away.
913
914   for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
915   {
916     multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
917     for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
918     {
919       int axis = nb_axis->second;
920       map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
921
922       gp_Ax1 lineAxis( point, axisDir[axis]);
923       gp_Lin line    ( lineAxis );
924
925       // add tangent intersections to u2inters
926       double param;
927       list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
928       for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
929         if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
930           u2inters.insert(make_pair( param, *tgtInt ));
931       tangentInters[ axis ].clear();
932
933       // Count intersections before and after the point excluding touching ones.
934       // If hasPositionInfo we count intersections of outer boundary only
935
936       int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
937       double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
938       map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
939       bool ok = ! u_int1->second._coincides;
940       while ( ok && u_int1 != u2inters.end() )
941       {
942         double u = u_int1->first;
943         bool touchingInt = false;
944         if ( ++u_int2 != u2inters.end() )
945         {
946           // skip intersections at the same point (if the line passes through edge or node)
947           int nbSamePnt = 0;
948           while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
949           {
950             ++nbSamePnt;
951             ++u_int2;
952           }
953
954           // skip tangent intersections
955           int nbTgt = 0;
956           const SMDS_MeshElement* prevFace = u_int1->second._face;
957           while ( ok && u_int2->second._coincides )
958           {
959             if ( SMESH_MeshAlgos::GetCommonNodes(prevFace , u_int2->second._face).empty() )
960               ok = false;
961             else
962             {
963               nbTgt++;
964               u_int2++;
965               ok = ( u_int2 != u2inters.end() );
966             }
967           }
968           if ( !ok ) break;
969
970           // skip intersections at the same point after tangent intersections
971           if ( nbTgt > 0 )
972           {
973             double u2 = u_int2->first;
974             ++u_int2;
975             while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
976             {
977               ++nbSamePnt;
978               ++u_int2;
979             }
980           }
981           // decide if we skipped a touching intersection
982           if ( nbSamePnt + nbTgt > 0 )
983           {
984             double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
985             map< double, TInters >::iterator u_int = u_int1;
986             for ( ; u_int != u_int2; ++u_int )
987             {
988               if ( u_int->second._coincides ) continue;
989               double dot = u_int->second._faceNorm * line.Direction();
990               if ( dot > maxDot ) maxDot = dot;
991               if ( dot < minDot ) minDot = dot;
992             }
993             touchingInt = ( minDot*maxDot < 0 );
994           }
995         }
996         if ( !touchingInt )
997         {
998           if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
999           {
1000             if ( u < 0 )
1001               ++nbIntBeforePoint;
1002             else
1003               ++nbIntAfterPoint;
1004           }
1005           if ( u < f ) f = u;
1006           if ( u > l ) l = u;
1007         }
1008
1009         u_int1 = u_int2; // to next intersection
1010
1011       } // loop on intersections with one line
1012
1013       if ( ok )
1014       {
1015         if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
1016           return TopAbs_ON;
1017
1018         if ( nbIntBeforePoint == 0  || nbIntAfterPoint == 0)
1019           return TopAbs_OUT;
1020
1021         if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
1022           return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
1023
1024         if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
1025           return TopAbs_IN;
1026
1027         if ( (f<0) == (l<0) )
1028           return TopAbs_OUT;
1029
1030         if ( hasPositionInfo )
1031           return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
1032       }
1033     } // loop on intersections of the tree lines - thorough analysis
1034
1035     if ( !hasPositionInfo )
1036     {
1037       // gather info on faces position - is face in the outer boundary or not
1038       map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
1039       findOuterBoundary( u2inters.begin()->second._face );
1040     }
1041
1042   } // two attempts - with and w/o faces position info in the mesh
1043
1044   return TopAbs_UNKNOWN;
1045 }
1046
1047 //=======================================================================
1048 /*!
1049  * \brief Return elements possibly intersecting the line
1050  */
1051 //=======================================================================
1052
1053 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1&                      line,
1054                                                      SMDSAbs_ElementType                type,
1055                                                      vector< const SMDS_MeshElement* >& foundElems)
1056 {
1057   if ( !_ebbTree || _elementType != type )
1058   {
1059     if ( _ebbTree ) delete _ebbTree;
1060     _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
1061   }
1062   TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
1063   _ebbTree->getElementsNearLine( line, suspectFaces );
1064   foundElems.assign( suspectFaces.begin(), suspectFaces.end());
1065 }
1066
1067 //=======================================================================
1068 /*!
1069  * \brief Return true if the point is IN or ON of the element
1070  */
1071 //=======================================================================
1072
1073 bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
1074 {
1075   if ( element->GetType() == SMDSAbs_Volume)
1076   {
1077     return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
1078   }
1079
1080   // get ordered nodes
1081
1082   vector< gp_XYZ > xyz;
1083   vector<const SMDS_MeshNode*> nodeList;
1084
1085   SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
1086   if ( element->IsQuadratic() ) {
1087     nodeIt = element->interlacedNodesElemIterator();
1088     // if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
1089     //   nodeIt = f->interlacedNodesElemIterator();
1090     // else if (const SMDS_VtkEdge*  e =dynamic_cast<const SMDS_VtkEdge*>(element))
1091     //   nodeIt = e->interlacedNodesElemIterator();
1092   }
1093   while ( nodeIt->more() )
1094   {
1095     SMESH_TNodeXYZ node = nodeIt->next();
1096     xyz.push_back( node );
1097     nodeList.push_back(node._node);
1098   }
1099
1100   int i, nbNodes = (int) nodeList.size(); // central node of biquadratic is missing
1101
1102   if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
1103   {
1104     // compute face normal
1105     gp_Vec faceNorm(0,0,0);
1106     xyz.push_back( xyz.front() );
1107     nodeList.push_back( nodeList.front() );
1108     for ( i = 0; i < nbNodes; ++i )
1109     {
1110       gp_Vec edge1( xyz[i+1], xyz[i]);
1111       gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
1112       faceNorm += edge1 ^ edge2;
1113     }
1114     double normSize = faceNorm.Magnitude();
1115     if ( normSize <= tol )
1116     {
1117       // degenerated face: point is out if it is out of all face edges
1118       for ( i = 0; i < nbNodes; ++i )
1119       {
1120         SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
1121         if ( !IsOut( &edge, point, tol ))
1122           return false;
1123       }
1124       return true;
1125     }
1126     faceNorm /= normSize;
1127
1128     // check if the point lays on face plane
1129     gp_Vec n2p( xyz[0], point );
1130     if ( fabs( n2p * faceNorm ) > tol )
1131       return true; // not on face plane
1132
1133     // check if point is out of face boundary:
1134     // define it by closest transition of a ray point->infinity through face boundary
1135     // on the face plane.
1136     // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
1137     // to find intersections of the ray with the boundary.
1138     gp_Vec ray = n2p;
1139     gp_Vec plnNorm = ray ^ faceNorm;
1140     normSize = plnNorm.Magnitude();
1141     if ( normSize <= tol ) return false; // point coincides with the first node
1142     plnNorm /= normSize;
1143     // for each node of the face, compute its signed distance to the plane
1144     vector<double> dist( nbNodes + 1);
1145     for ( i = 0; i < nbNodes; ++i )
1146     {
1147       gp_Vec n2p( xyz[i], point );
1148       dist[i] = n2p * plnNorm;
1149     }
1150     dist.back() = dist.front();
1151     // find the closest intersection
1152     int    iClosest = -1;
1153     double rClosest, distClosest = 1e100;;
1154     gp_Pnt pClosest;
1155     for ( i = 0; i < nbNodes; ++i )
1156     {
1157       double r;
1158       if ( fabs( dist[i]) < tol )
1159         r = 0.;
1160       else if ( fabs( dist[i+1]) < tol )
1161         r = 1.;
1162       else if ( dist[i] * dist[i+1] < 0 )
1163         r = dist[i] / ( dist[i] - dist[i+1] );
1164       else
1165         continue; // no intersection
1166       gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
1167       gp_Vec p2int ( point, pInt);
1168       if ( p2int * ray > -tol ) // right half-space
1169       {
1170         double intDist = p2int.SquareMagnitude();
1171         if ( intDist < distClosest )
1172         {
1173           iClosest = i;
1174           rClosest = r;
1175           pClosest = pInt;
1176           distClosest = intDist;
1177         }
1178       }
1179     }
1180     if ( iClosest < 0 )
1181       return true; // no intesections - out
1182
1183     // analyse transition
1184     gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
1185     gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
1186     gp_Vec p2int ( point, pClosest );
1187     bool out = (edgeNorm * p2int) < -tol;
1188     if ( rClosest > 0. && rClosest < 1. ) // not node intersection
1189       return out;
1190
1191     // ray pass through a face node; analyze transition through an adjacent edge
1192     gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
1193     gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
1194     gp_Vec edgeAdjacent( p1, p2 );
1195     gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
1196     bool out2 = (edgeNorm2 * p2int) < -tol;
1197
1198     bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
1199     return covexCorner ? (out || out2) : (out && out2);
1200   }
1201   if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
1202   {
1203     // point is out of edge if it is NOT ON any straight part of edge
1204     // (we consider quadratic edge as being composed of two straight parts)
1205     for ( i = 1; i < nbNodes; ++i )
1206     {
1207       gp_Vec edge( xyz[i-1], xyz[i]);
1208       gp_Vec n1p ( xyz[i-1], point);
1209       double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
1210       if ( dist > tol )
1211         continue;
1212       gp_Vec n2p( xyz[i], point );
1213       if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
1214         continue;
1215       return false; // point is ON this part
1216     }
1217     return true;
1218   }
1219   // Node or 0D element -------------------------------------------------------------------------
1220   {
1221     gp_Vec n2p ( xyz[0], point );
1222     return n2p.Magnitude() <= tol;
1223   }
1224   return true;
1225 }
1226
1227 //=======================================================================
1228 namespace
1229 {
1230   // Position of a point relative to a segment
1231   //            .           .
1232   //            .  LEFT     .
1233   //            .           .
1234   //  VERTEX 1  o----ON----->  VERTEX 2
1235   //            .           .
1236   //            .  RIGHT    .
1237   //            .           .
1238   enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8,
1239                       POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX };
1240   struct PointPos
1241   {
1242     PositionName _name;
1243     int          _index; // index of vertex or segment
1244
1245     PointPos( PositionName n, int i=-1 ): _name(n), _index(i) {}
1246     bool operator < (const PointPos& other ) const
1247     {
1248       if ( _name == other._name )
1249         return  ( _index < 0 || other._index < 0 ) ? false : _index < other._index;
1250       return _name < other._name;
1251     }
1252   };
1253
1254   //================================================================================
1255   /*!
1256    * \brief Return of a point relative to a segment
1257    *  \param point2D      - the point to analyze position of
1258    *  \param xyVec        - end points of segments
1259    *  \param index0       - 0-based index of the first point of segment
1260    *  \param posToFindOut - flags of positions to detect
1261    *  \retval PointPos - point position
1262    */
1263   //================================================================================
1264
1265   PointPos getPointPosition( const gp_XY& point2D,
1266                              const gp_XY* segEnds,
1267                              const int    index0 = 0,
1268                              const int    posToFindOut = POS_ALL)
1269   {
1270     const gp_XY& p1 = segEnds[ index0   ];
1271     const gp_XY& p2 = segEnds[ index0+1 ];
1272     const gp_XY grad = p2 - p1;
1273
1274     if ( posToFindOut & POS_VERTEX )
1275     {
1276       // check if the point2D is at "vertex 1" zone
1277       gp_XY pp1[2] = { p1, gp_XY( p1.X() - grad.Y(),
1278                                   p1.Y() + grad.X() ) };
1279       if ( getPointPosition( point2D, pp1, 0, POS_LEFT|POS_RIGHT )._name == POS_LEFT )
1280         return PointPos( POS_VERTEX, index0 );
1281
1282       // check if the point2D is at "vertex 2" zone
1283       gp_XY pp2[2] = { p2, gp_XY( p2.X() - grad.Y(),
1284                                   p2.Y() + grad.X() ) };
1285       if ( getPointPosition( point2D, pp2, 0, POS_LEFT|POS_RIGHT )._name == POS_RIGHT )
1286         return PointPos( POS_VERTEX, index0 + 1);
1287     }
1288     double edgeEquation =
1289       ( point2D.X() - p1.X() ) * grad.Y() - ( point2D.Y() - p1.Y() ) * grad.X();
1290     return PointPos( edgeEquation < 0 ? POS_LEFT : POS_RIGHT, index0 );
1291   }
1292 }
1293
1294 //=======================================================================
1295 /*!
1296  * \brief Return minimal distance from a point to an element
1297  *
1298  * Currently we ignore non-planarity and 2nd order of face
1299  */
1300 //=======================================================================
1301
1302 double SMESH_MeshAlgos::GetDistance( const SMDS_MeshElement* elem,
1303                                      const gp_Pnt&           point )
1304 {
1305   switch ( elem->GetType() )
1306   {
1307   case SMDSAbs_Volume:
1308     return GetDistance( dynamic_cast<const SMDS_MeshVolume*>( elem ), point);
1309   case SMDSAbs_Face:
1310     return GetDistance( dynamic_cast<const SMDS_MeshFace*>( elem ), point);
1311   case SMDSAbs_Edge:
1312     return GetDistance( dynamic_cast<const SMDS_MeshEdge*>( elem ), point);
1313   case SMDSAbs_Node:
1314     return point.Distance( SMESH_TNodeXYZ( elem ));
1315   }
1316   return -1;
1317 }
1318
1319 //=======================================================================
1320 /*!
1321  * \brief Return minimal distance from a point to a face
1322  *
1323  * Currently we ignore non-planarity and 2nd order of face
1324  */
1325 //=======================================================================
1326
1327 double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
1328                                      const gp_Pnt&        point )
1329 {
1330   double badDistance = -1;
1331   if ( !face ) return badDistance;
1332
1333   // coordinates of nodes (medium nodes, if any, ignored)
1334   typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
1335   vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
1336   xyz.resize( face->NbCornerNodes()+1 );
1337
1338   // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis,
1339   // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane.
1340   gp_Trsf trsf;
1341   gp_Vec OZ ( xyz[0], xyz[1] );
1342   gp_Vec OX ( xyz[0], xyz[2] );
1343   if ( OZ.Magnitude() < std::numeric_limits<double>::min() )
1344   {
1345     if ( xyz.size() < 4 ) return badDistance;
1346     OZ = gp_Vec ( xyz[0], xyz[2] );
1347     OX = gp_Vec ( xyz[0], xyz[3] );
1348   }
1349   gp_Ax3 tgtCS;
1350   try {
1351     tgtCS = gp_Ax3( xyz[0], OZ, OX );
1352   }
1353   catch ( Standard_Failure ) {
1354     return badDistance;
1355   }
1356   trsf.SetTransformation( tgtCS );
1357
1358   // move all the nodes to 2D
1359   vector<gp_XY> xy( xyz.size() );
1360   for ( size_t i = 0;i < xyz.size()-1; ++i )
1361   {
1362     gp_XYZ p3d = xyz[i];
1363     trsf.Transforms( p3d );
1364     xy[i].SetCoord( p3d.X(), p3d.Z() );
1365   }
1366   xyz.back() = xyz.front();
1367   xy.back() = xy.front();
1368
1369   // // move the point in 2D
1370   gp_XYZ tmpPnt = point.XYZ();
1371   trsf.Transforms( tmpPnt );
1372   gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
1373
1374   // loop on segments of the face to analyze point position ralative to the face
1375   set< PointPos > pntPosSet;
1376   for ( size_t i = 1; i < xy.size(); ++i )
1377   {
1378     PointPos pos = getPointPosition( point2D, &xy[0], i-1 );
1379     pntPosSet.insert( pos );
1380   }
1381
1382   // compute distance
1383   PointPos pos = *pntPosSet.begin();
1384   // cout << "Face " << face->GetID() << " DIST: ";
1385   switch ( pos._name )
1386   {
1387   case POS_LEFT: {
1388     // point is most close to a segment
1389     gp_Vec p0p1( point, xyz[ pos._index ] );
1390     gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector
1391     p1p2.Normalize();
1392     double projDist = p0p1 * p1p2; // distance projected to the segment
1393     gp_Vec projVec = p1p2 * projDist;
1394     gp_Vec distVec = p0p1 - projVec;
1395     // cout << distVec.Magnitude()  << ", SEG " << face->GetNode(pos._index)->GetID()
1396     //      << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl;
1397     return distVec.Magnitude();
1398   }
1399   case POS_RIGHT: {
1400     // point is inside the face
1401     double distToFacePlane = tmpPnt.Y();
1402     // cout << distToFacePlane << ", INSIDE " << endl;
1403     return Abs( distToFacePlane );
1404   }
1405   case POS_VERTEX: {
1406     // point is most close to a node
1407     gp_Vec distVec( point, xyz[ pos._index ]);
1408     // cout << distVec.Magnitude()  << " VERTEX " << face->GetNode(pos._index)->GetID() << endl;
1409     return distVec.Magnitude();
1410   }
1411   }
1412   return badDistance;
1413 }
1414
1415 //=======================================================================
1416 /*!
1417  * \brief Return minimal distance from a point to an edge
1418  */
1419 //=======================================================================
1420
1421 double SMESH_MeshAlgos::GetDistance( const SMDS_MeshEdge* edge, const gp_Pnt& point )
1422 {
1423   throw SALOME_Exception(LOCALIZED("not implemented so far"));
1424 }
1425
1426 //=======================================================================
1427 /*!
1428  * \brief Return minimal distance from a point to a volume
1429  *
1430  * Currently we ignore non-planarity and 2nd order
1431  */
1432 //=======================================================================
1433
1434 double SMESH_MeshAlgos::GetDistance( const SMDS_MeshVolume* volume, const gp_Pnt& point )
1435 {
1436   SMDS_VolumeTool vTool( volume );
1437   vTool.SetExternalNormal();
1438   const int iQ = volume->IsQuadratic() ? 2 : 1;
1439
1440   double n[3], bc[3];
1441   double minDist = 1e100, dist;
1442   for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
1443   {
1444     // skip a facet with normal not "looking at" the point
1445     if ( !vTool.GetFaceNormal( iF, n[0], n[1], n[2] ) ||
1446          !vTool.GetFaceBaryCenter( iF, bc[0], bc[1], bc[2] ))
1447       continue;
1448     gp_XYZ bcp = point.XYZ() - gp_XYZ( bc[0], bc[1], bc[2] );
1449     if ( gp_XYZ( n[0], n[1], n[2] ) * bcp < 1e-6 )
1450       continue;
1451
1452     // find distance to a facet
1453     const SMDS_MeshNode** nodes = vTool.GetFaceNodes( iF );
1454     switch ( vTool.NbFaceNodes( iF ) / iQ ) {
1455     case 3:
1456     {
1457       SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ] );
1458       dist = GetDistance( &tmpFace, point );
1459       break;
1460     }
1461     case 4:
1462     {
1463       SMDS_FaceOfNodes tmpFace( nodes[0], nodes[ 1*iQ ], nodes[ 2*iQ ], nodes[ 3*iQ ]);
1464       dist = GetDistance( &tmpFace, point );
1465       break;
1466     }
1467     default:
1468       vector<const SMDS_MeshNode *> nvec( nodes, nodes + vTool.NbFaceNodes( iF ));
1469       SMDS_PolygonalFaceOfNodes tmpFace( nvec );
1470       dist = GetDistance( &tmpFace, point );
1471     }
1472     minDist = Min( minDist, dist );
1473   }
1474   return minDist;
1475 }
1476
1477 //================================================================================
1478 /*!
1479  * \brief Returns barycentric coordinates of a point within a triangle.
1480  *        A not returned bc2 = 1. - bc0 - bc1.
1481  *        The point lies within the triangle if ( bc0 >= 0 && bc1 >= 0 && bc0+bc1 <= 1 )
1482  */
1483 //================================================================================
1484
1485 void SMESH_MeshAlgos::GetBarycentricCoords( const gp_XY& p,
1486                                             const gp_XY& t0,
1487                                             const gp_XY& t1,
1488                                             const gp_XY& t2,
1489                                             double &     bc0,
1490                                             double &     bc1)
1491 {
1492   const double // matrix 2x2
1493     T11 = t0.X()-t2.X(), T12 = t1.X()-t2.X(),
1494     T21 = t0.Y()-t2.Y(), T22 = t1.Y()-t2.Y();
1495   const double Tdet = T11*T22 - T12*T21; // matrix determinant
1496   if ( Abs( Tdet ) < std::numeric_limits<double>::min() )
1497   {
1498     bc0 = bc1 = 2.;
1499     return;
1500   }
1501   // matrix inverse
1502   const double t11 = T22, t12 = -T12, t21 = -T21, t22 = T11;
1503   // vector
1504   const double r11 = p.X()-t2.X(), r12 = p.Y()-t2.Y();
1505   // barycentric coordinates: mutiply matrix by vector
1506   bc0 = (t11 * r11 + t12 * r12)/Tdet;
1507   bc1 = (t21 * r11 + t22 * r12)/Tdet;
1508 }
1509
1510 //=======================================================================
1511 //function : FindFaceInSet
1512 //purpose  : Return a face having linked nodes n1 and n2 and which is
1513 //           - not in avoidSet,
1514 //           - in elemSet provided that !elemSet.empty()
1515 //           i1 and i2 optionally returns indices of n1 and n2
1516 //=======================================================================
1517
1518 const SMDS_MeshElement*
1519 SMESH_MeshAlgos::FindFaceInSet(const SMDS_MeshNode*    n1,
1520                                const SMDS_MeshNode*    n2,
1521                                const TIDSortedElemSet& elemSet,
1522                                const TIDSortedElemSet& avoidSet,
1523                                int*                    n1ind,
1524                                int*                    n2ind)
1525
1526 {
1527   int i1, i2;
1528   const SMDS_MeshElement* face = 0;
1529
1530   SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
1531   //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
1532   while ( invElemIt->more() && !face ) // loop on inverse faces of n1
1533   {
1534     //MESSAGE("in while ( invElemIt->more() && !face )");
1535     const SMDS_MeshElement* elem = invElemIt->next();
1536     if (avoidSet.count( elem ))
1537       continue;
1538     if ( !elemSet.empty() && !elemSet.count( elem ))
1539       continue;
1540     // index of n1
1541     i1 = elem->GetNodeIndex( n1 );
1542     // find a n2 linked to n1
1543     int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
1544     for ( int di = -1; di < 2 && !face; di += 2 )
1545     {
1546       i2 = (i1+di+nbN) % nbN;
1547       if ( elem->GetNode( i2 ) == n2 )
1548         face = elem;
1549     }
1550     if ( !face && elem->IsQuadratic())
1551     {
1552       // analysis for quadratic elements using all nodes
1553       // const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>(elem);
1554       // if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
1555       // use special nodes iterator
1556       SMDS_ElemIteratorPtr anIter = elem->interlacedNodesElemIterator();
1557       const SMDS_MeshNode* prevN = static_cast<const SMDS_MeshNode*>( anIter->next() );
1558       for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
1559       {
1560         const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( anIter->next() );
1561         if ( n1 == prevN && n2 == n )
1562         {
1563           face = elem;
1564         }
1565         else if ( n2 == prevN && n1 == n )
1566         {
1567           face = elem; swap( i1, i2 );
1568         }
1569         prevN = n;
1570       }
1571     }
1572   }
1573   if ( n1ind ) *n1ind = i1;
1574   if ( n2ind ) *n2ind = i2;
1575   return face;
1576 }
1577
1578 //================================================================================
1579 /*!
1580  * \brief Calculate normal of a mesh face
1581  */
1582 //================================================================================
1583
1584 bool SMESH_MeshAlgos::FaceNormal(const SMDS_MeshElement* F, gp_XYZ& normal, bool normalized)
1585 {
1586   if ( !F || F->GetType() != SMDSAbs_Face )
1587     return false;
1588
1589   normal.SetCoord(0,0,0);
1590   int nbNodes = F->IsQuadratic() ? F->NbNodes()/2 : F->NbNodes();
1591   for ( int i = 0; i < nbNodes-2; ++i )
1592   {
1593     gp_XYZ p[3];
1594     for ( int n = 0; n < 3; ++n )
1595     {
1596       const SMDS_MeshNode* node = F->GetNode( i + n );
1597       p[n].SetCoord( node->X(), node->Y(), node->Z() );
1598     }
1599     normal += ( p[2] - p[1] ) ^ ( p[0] - p[1] );
1600   }
1601   double size2 = normal.SquareModulus();
1602   bool ok = ( size2 > numeric_limits<double>::min() * numeric_limits<double>::min());
1603   if ( normalized && ok )
1604     normal /= sqrt( size2 );
1605
1606   return ok;
1607 }
1608
1609 //=======================================================================
1610 //function : GetCommonNodes
1611 //purpose  : Return nodes common to two elements
1612 //=======================================================================
1613
1614 vector< const SMDS_MeshNode*> SMESH_MeshAlgos::GetCommonNodes(const SMDS_MeshElement* e1,
1615                                                               const SMDS_MeshElement* e2)
1616 {
1617   vector< const SMDS_MeshNode*> common;
1618   for ( int i = 0 ; i < e1->NbNodes(); ++i )
1619     if ( e2->GetNodeIndex( e1->GetNode( i )) >= 0 )
1620       common.push_back( e1->GetNode( i ));
1621   return common;
1622 }
1623
1624 //=======================================================================
1625 /*!
1626  * \brief Return SMESH_NodeSearcher
1627  */
1628 //=======================================================================
1629
1630 SMESH_NodeSearcher* SMESH_MeshAlgos::GetNodeSearcher(SMDS_Mesh& mesh)
1631 {
1632   return new SMESH_NodeSearcherImpl( &mesh );
1633 }
1634
1635 //=======================================================================
1636 /*!
1637  * \brief Return SMESH_ElementSearcher
1638  */
1639 //=======================================================================
1640
1641 SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh)
1642 {
1643   return new SMESH_ElementSearcherImpl( mesh );
1644 }
1645
1646 //=======================================================================
1647 /*!
1648  * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
1649  */
1650 //=======================================================================
1651
1652 SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh&           mesh,
1653                                                            SMDS_ElemIteratorPtr elemIt)
1654 {
1655   return new SMESH_ElementSearcherImpl( mesh, elemIt );
1656 }