Salome HOME
2257104eb46aaf861e6ed28511368cd3bc8f489a
[modules/smesh.git] / src / StdMeshers / StdMeshers_ViscousLayers2D.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File      : StdMeshers_ViscousLayers2D.cxx
21 // Created   : 23 Jul 2012
22 // Author    : Edward AGAPOV (eap)
23
24 #include "StdMeshers_ViscousLayers2D.hxx"
25
26 #include "SMDS_EdgePosition.hxx"
27 #include "SMDS_FaceOfNodes.hxx"
28 #include "SMDS_FacePosition.hxx"
29 #include "SMDS_MeshNode.hxx"
30 #include "SMDS_SetIterator.hxx"
31 #include "SMESHDS_Group.hxx"
32 #include "SMESHDS_Hypothesis.hxx"
33 #include "SMESH_Algo.hxx"
34 #include "SMESH_ComputeError.hxx"
35 #include "SMESH_ControlsDef.hxx"
36 #include "SMESH_Gen.hxx"
37 #include "SMESH_Group.hxx"
38 #include "SMESH_HypoFilter.hxx"
39 #include "SMESH_Mesh.hxx"
40 #include "SMESH_MesherHelper.hxx"
41 #include "SMESH_ProxyMesh.hxx"
42 #include "SMESH_Quadtree.hxx"
43 #include "SMESH_subMesh.hxx"
44 #include "SMESH_subMeshEventListener.hxx"
45 #include "StdMeshers_FaceSide.hxx"
46
47 #include "utilities.h"
48
49 #include <BRepAdaptor_Curve.hxx>
50 #include <BRepAdaptor_Curve2d.hxx>
51 #include <BRep_Tool.hxx>
52 #include <Bnd_B2d.hxx>
53 #include <Bnd_B3d.hxx>
54 #include <ElCLib.hxx>
55 #include <GCPnts_AbscissaPoint.hxx>
56 #include <Geom2d_Circle.hxx>
57 #include <Geom2d_Line.hxx>
58 #include <Geom2d_TrimmedCurve.hxx>
59 #include <GeomAdaptor_Curve.hxx>
60 #include <Geom_Circle.hxx>
61 #include <Geom_Curve.hxx>
62 #include <Geom_Line.hxx>
63 #include <Geom_TrimmedCurve.hxx>
64 #include <Precision.hxx>
65 #include <Standard_ErrorHandler.hxx>
66 #include <TColStd_Array1OfReal.hxx>
67 #include <TopExp.hxx>
68 #include <TopExp_Explorer.hxx>
69 #include <TopTools_IndexedMapOfShape.hxx>
70 #include <TopTools_MapOfShape.hxx>
71 #include <TopoDS.hxx>
72 #include <TopoDS_Edge.hxx>
73 #include <TopoDS_Face.hxx>
74 #include <TopoDS_Vertex.hxx>
75 #include <gp_Ax1.hxx>
76 #include <gp_Vec.hxx>
77 #include <gp_XY.hxx>
78
79 #include <list>
80 #include <string>
81 #include <cmath>
82 #include <limits>
83
84 #define __myDEBUG
85
86 using namespace std;
87
88 //================================================================================
89 namespace VISCOUS_2D
90 {
91   typedef int TGeomID;
92
93   //--------------------------------------------------------------------------------
94   /*!
95    * \brief Proxy Mesh of FACE with viscous layers. It's needed only to 
96    *        redefine newSubmesh().
97    */
98   struct _ProxyMeshOfFace : public SMESH_ProxyMesh
99   {
100     //---------------------------------------------------
101     // Proxy sub-mesh of an EDGE. It contains nodes in _uvPtStructVec.
102     struct _EdgeSubMesh : public SMESH_ProxyMesh::SubMesh
103     {
104       _EdgeSubMesh(int index=0): SubMesh(index) {}
105       //virtual int NbElements() const { return _elements.size()+1; }
106       virtual int NbNodes() const { return Max( 0, _uvPtStructVec.size()-2 ); }
107       void SetUVPtStructVec(UVPtStructVec& vec) { _uvPtStructVec.swap( vec ); }
108     };
109     _ProxyMeshOfFace(const SMESH_Mesh& mesh): SMESH_ProxyMesh(mesh) {}
110     _EdgeSubMesh* GetEdgeSubMesh(int ID) { return (_EdgeSubMesh*) getProxySubMesh(ID); }
111     virtual SubMesh* newSubmesh(int index=0) const { return new _EdgeSubMesh(index); }
112   };
113   //--------------------------------------------------------------------------------
114   /*!
115    * \brief SMESH_subMeshEventListener used to store _ProxyMeshOfFace, computed
116    *        by _ViscousBuilder2D, in a SMESH_subMesh of the FACE.
117    *        This is to delete _ProxyMeshOfFace when StdMeshers_ViscousLayers2D
118    *        hypothesis is modified
119    */
120   struct _ProxyMeshHolder : public SMESH_subMeshEventListener
121   {
122     _ProxyMeshHolder( const TopoDS_Face&    face,
123                       SMESH_ProxyMesh::Ptr& mesh)
124       : SMESH_subMeshEventListener( /*deletable=*/true, Name() )
125     {
126       SMESH_subMesh* faceSM = mesh->GetMesh()->GetSubMesh( face );
127       faceSM->SetEventListener( this, new _Data( mesh ), faceSM );
128     }
129     // Finds a proxy mesh of face
130     static SMESH_ProxyMesh::Ptr FindProxyMeshOfFace( const TopoDS_Shape& face,
131                                                      SMESH_Mesh&         mesh )
132     {
133       SMESH_ProxyMesh::Ptr proxy;
134       SMESH_subMesh* faceSM = mesh.GetSubMesh( face );
135       if ( EventListenerData* ld = faceSM->GetEventListenerData( Name() ))
136         proxy = static_cast< _Data* >( ld )->_mesh;
137       return proxy;
138     }
139     // Treat events
140     void ProcessEvent(const int          event,
141                       const int          eventType,
142                       SMESH_subMesh*     subMesh,
143                       EventListenerData* data,
144                       const SMESH_Hypothesis*  /*hyp*/)
145     {
146       if ( event == SMESH_subMesh::CLEAN && eventType == SMESH_subMesh::COMPUTE_EVENT)
147         ((_Data*) data)->_mesh.reset();
148     }
149   private:
150     // holder of a proxy mesh
151     struct _Data : public SMESH_subMeshEventListenerData
152     {
153       SMESH_ProxyMesh::Ptr _mesh;
154       _Data( SMESH_ProxyMesh::Ptr& mesh )
155         :SMESH_subMeshEventListenerData( /*isDeletable=*/true), _mesh( mesh )
156       {}
157     };
158     // Returns identifier string
159     static const char* Name() { return "VISCOUS_2D::_ProxyMeshHolder"; }
160   };
161   
162   struct _PolyLine;
163   //--------------------------------------------------------------------------------
164   /*!
165    * \brief Segment connecting inner ends of two _LayerEdge's.
166    */
167   struct _Segment
168   {
169     const gp_XY* _uv[2];       // poiter to _LayerEdge::_uvIn
170     int          _indexInLine; // position in _PolyLine
171
172     _Segment() {}
173     _Segment(const gp_XY& p1, const gp_XY& p2):_indexInLine(-1) { _uv[0] = &p1; _uv[1] = &p2; }
174     const gp_XY& p1() const { return *_uv[0]; }
175     const gp_XY& p2() const { return *_uv[1]; }
176   };
177   //--------------------------------------------------------------------------------
178   /*!
179    * \brief Tree of _Segment's used for a faster search of _Segment's.
180    */
181   struct _SegmentTree : public SMESH_Quadtree
182   {
183     typedef boost::shared_ptr< _SegmentTree > Ptr;
184
185     _SegmentTree( const vector< _Segment >& segments );
186     void GetSegmentsNear( const _Segment& seg, vector< const _Segment* >& found );
187     void GetSegmentsNear( const gp_Ax2d& ray, vector< const _Segment* >& found );
188   protected:
189     _SegmentTree() {}
190     _SegmentTree* newChild() const { return new _SegmentTree; }
191     void          buildChildrenData();
192     Bnd_B2d*      buildRootBox();
193   private:
194     static int    maxNbSegInLeaf() { return 5; }
195     struct _SegBox
196     {
197       const _Segment* _seg;
198       bool            _iMin[2];
199       void Set( const _Segment& seg )
200       {
201         _seg = &seg;
202         _iMin[0] = ( seg._uv[1]->X() < seg._uv[0]->X() );
203         _iMin[1] = ( seg._uv[1]->Y() < seg._uv[0]->Y() );
204       }
205       bool IsOut( const _Segment& seg ) const;
206       bool IsOut( const gp_Ax2d& ray ) const;
207     };
208     vector< _SegBox > _segments;
209   };
210   //--------------------------------------------------------------------------------
211   /*!
212    * \brief Edge normal to FACE boundary, connecting a point on EDGE (_uvOut)
213    * and a point of a layer internal boundary (_uvIn)
214    */
215   struct _LayerEdge
216   {
217     gp_XY         _uvOut;    // UV on the FACE boundary
218     gp_XY         _uvIn;     // UV inside the FACE
219     double        _length2D; // distance between _uvOut and _uvIn
220
221     bool          _isBlocked;// is more inflation possible or not
222
223     gp_XY         _normal2D; // to pcurve
224     double        _len2dTo3dRatio; // to pass 2D <--> 3D
225     gp_Ax2d       _ray;      // a ray starting at _uvOut
226
227     vector<gp_XY> _uvRefined; // divisions by layers
228
229     void SetNewLength( const double length );
230   };
231   //--------------------------------------------------------------------------------
232   /*!
233    * \brief Poly line composed of _Segment's of one EDGE.
234    *        It's used to detect intersection of inflated layers by intersecting
235    *        _Segment's in 2D.
236    */
237   struct _PolyLine
238   {
239     StdMeshers_FaceSide* _wire;
240     int                  _edgeInd;     // index of my EDGE in _wire
241     bool                 _advancable;  // true if there is a viscous layer on my EDGE
242     _PolyLine*           _leftLine;    // lines of neighbour EDGE's
243     _PolyLine*           _rightLine;
244     int                  _firstPntInd; // index in vector<UVPtStruct> of _wire
245     int                  _lastPntInd;
246
247     vector< _LayerEdge > _lEdges;      /* _lEdges[0] is usually is not treated
248                                           as it is equal to the last one of the _leftLine */
249     vector< _Segment >   _segments;    // segments connecting _uvIn's of _lEdges
250     _SegmentTree::Ptr    _segTree;
251
252     vector< _PolyLine* > _reachableLines;       // lines able to interfere with my layer
253
254     vector< const SMDS_MeshNode* > _leftNodes;  // nodes built from a left VERTEX
255     vector< const SMDS_MeshNode* > _rightNodes; // nodes built from a right VERTEX
256
257     typedef vector< _Segment >::iterator   TSegIterator;
258     typedef vector< _LayerEdge >::iterator TEdgeIterator;
259
260     bool IsCommonEdgeShared( const _PolyLine& other );
261     size_t FirstLEdge() const { return _leftLine->_advancable ? 1 : 0; }
262     bool IsAdjacent( const _Segment& seg ) const
263     {
264       return ( & seg == &_leftLine->_segments.back() ||
265                & seg == &_rightLine->_segments[0] );
266     }
267   };
268   //--------------------------------------------------------------------------------
269   /*!
270    * \brief Intersector of _Segment's
271    */
272   struct _SegmentIntersection
273   {
274     gp_XY    _vec1, _vec2;     // Vec( _seg.p1(), _seg.p2() )
275     gp_XY    _vec21;           // Vec( _seg2.p1(), _seg1.p1() )
276     double   _D;               // _vec1.Crossed( _vec2 )
277     double   _param1, _param2; // intersection param on _seg1 and _seg2
278
279     bool Compute(const _Segment& seg1, const _Segment& seg2, bool seg2IsRay = false )
280     {
281       _vec1  = seg1.p2() - seg1.p1(); 
282       _vec2  = seg2.p2() - seg2.p1(); 
283       _vec21 = seg1.p1() - seg2.p1(); 
284       _D = _vec1.Crossed(_vec2);
285       if ( fabs(_D) < std::numeric_limits<double>::min())
286         return false;
287       _param1 = _vec2.Crossed(_vec21) / _D; 
288       if (_param1 < 0 || _param1 > 1 )
289         return false;
290       _param2 = _vec1.Crossed(_vec21) / _D; 
291       if (_param2 < 0 || ( !seg2IsRay && _param2 > 1 ))
292         return false;
293       return true;
294     }
295     bool Compute( const _Segment& seg1, const gp_Ax2d& ray )
296     {
297       gp_XY segEnd = ray.Location().XY() + ray.Direction().XY();
298       _Segment seg2( ray.Location().XY(), segEnd );
299       return Compute( seg1, seg2, true );
300     }
301     //gp_XY GetPoint() { return _seg1.p1() + _param1 * _vec1; }
302   };
303   //--------------------------------------------------------------------------------
304
305   typedef map< const SMDS_MeshNode*, _LayerEdge*, TIDCompare > TNode2Edge;
306   
307   //--------------------------------------------------------------------------------
308   /*!
309    * \brief Builder of viscous layers
310    */
311   class _ViscousBuilder2D
312   {
313   public:
314     _ViscousBuilder2D(SMESH_Mesh&                       theMesh,
315                       const TopoDS_Face&                theFace,
316                       const StdMeshers_ViscousLayers2D* theHyp);
317     SMESH_ComputeErrorPtr GetError() const { return _error; }
318     // does it's job
319     SMESH_ProxyMesh::Ptr  Compute();
320
321   private:
322
323     bool findEdgesWithLayers();
324     bool makePolyLines();
325     bool inflate();
326     double fixCollisions( const int stepNb );
327     bool refine();
328     bool shrink();
329     void setLenRatio( _LayerEdge& LE, const gp_Pnt& pOut );
330     void adjustCommonEdge( _PolyLine& LL, _PolyLine& LR );
331     void calcLayersHeight(const double    totalThick,
332                           vector<double>& heights);
333     void removeMeshFaces(const TopoDS_Shape& face);
334
335     bool              error( const string& text );
336     SMESHDS_Mesh*     getMeshDS() { return _mesh->GetMeshDS(); }
337     _ProxyMeshOfFace* getProxyMesh();
338
339     // debug
340     //void makeGroupOfLE();
341
342   private:
343
344     // input data
345     SMESH_Mesh*                 _mesh;
346     TopoDS_Face                 _face;
347     const StdMeshers_ViscousLayers2D* _hyp;
348
349     // result data
350     SMESH_ProxyMesh::Ptr        _proxyMesh;
351     SMESH_ComputeErrorPtr       _error;
352
353     // working data
354     Handle(Geom_Surface)        _surface;
355     SMESH_MesherHelper          _helper;
356     TSideVector                 _faceSideVec; // wires (StdMeshers_FaceSide) of _face
357     vector<_PolyLine>           _polyLineVec; // fronts to advance
358
359     double                      _fPowN; // to compute thickness of layers
360     double                      _thickness; // required or possible layers thickness
361
362     // sub-shapes of _face 
363     set<TGeomID>                _ignoreShapeIds; // ids of EDGEs w/o layers
364     set<TGeomID>                _noShrinkVert;   // ids of VERTEXes that are extremities
365     // of EDGEs along which _LayerEdge can't be inflated because no viscous layers
366     // defined on neighbour FACEs sharing an EDGE. Nonetheless _LayerEdge's
367     // are inflated along such EDGEs but then such _LayerEdge's are turned into
368     // a node on VERTEX, i.e. all nodes on a _LayerEdge are melded into one node.
369     
370   };
371
372 } // namespace VISCOUS_2D
373
374 //================================================================================
375 // StdMeshers_ViscousLayers hypothesis
376 //
377 StdMeshers_ViscousLayers2D::StdMeshers_ViscousLayers2D(int hypId, int studyId, SMESH_Gen* gen)
378   :StdMeshers_ViscousLayers(hypId, studyId, gen)
379 {
380   _name = StdMeshers_ViscousLayers2D::GetHypType();
381   _param_algo_dim = -2; // auxiliary hyp used by 2D algos
382 }
383 // --------------------------------------------------------------------------------
384 bool StdMeshers_ViscousLayers2D::SetParametersByMesh(const SMESH_Mesh*   theMesh,
385                                                      const TopoDS_Shape& theShape)
386 {
387   // TODO ???
388   return false;
389 }
390 // --------------------------------------------------------------------------------
391 SMESH_ProxyMesh::Ptr
392 StdMeshers_ViscousLayers2D::Compute(SMESH_Mesh&        theMesh,
393                                     const TopoDS_Face& theFace)
394 {
395   SMESH_ProxyMesh::Ptr pm;
396
397   SMESH_HypoFilter hypFilter( SMESH_HypoFilter::HasName( GetHypType() ));
398   const SMESH_Hypothesis * hyp = theMesh.GetHypothesis( theFace, hypFilter, /*ancestors=*/true );
399   const StdMeshers_ViscousLayers2D* vlHyp =
400     dynamic_cast< const StdMeshers_ViscousLayers2D* > ( hyp );
401   if ( vlHyp )
402   {
403     VISCOUS_2D::_ViscousBuilder2D builder( theMesh, theFace, vlHyp );
404     pm = builder.Compute();
405     SMESH_ComputeErrorPtr error = builder.GetError();
406     if ( error && !error->IsOK() )
407       theMesh.GetSubMesh( theFace )->GetComputeError() = error;
408     else if ( !pm )
409       pm.reset( new SMESH_ProxyMesh( theMesh ));
410   }
411   else
412   {
413     pm.reset( new SMESH_ProxyMesh( theMesh ));
414   }
415   return pm;
416 }
417 // --------------------------------------------------------------------------------
418 void StdMeshers_ViscousLayers2D::RestoreListeners() const
419 {
420   StudyContextStruct* sc = _gen->GetStudyContext( _studyId );
421   std::map < int, SMESH_Mesh * >::iterator i_smesh = sc->mapMesh.begin();
422   for ( ; i_smesh != sc->mapMesh.end(); ++i_smesh )
423   {
424     SMESH_Mesh* smesh = i_smesh->second;
425     if ( !smesh ||
426          !smesh->HasShapeToMesh() ||
427          !smesh->GetMeshDS() ||
428          !smesh->GetMeshDS()->IsUsedHypothesis( this ))
429       continue;
430
431     // set event listeners to EDGE's of FACE where this hyp is used
432     TopoDS_Shape shape = i_smesh->second->GetShapeToMesh();
433     for ( TopExp_Explorer face( shape, TopAbs_FACE); face.More(); face.Next() )
434       if ( SMESH_Algo* algo = _gen->GetAlgo( *smesh, face.Current() ))
435       {
436         const std::list <const SMESHDS_Hypothesis *> & usedHyps =
437           algo->GetUsedHypothesis( *smesh, face.Current(), /*ignoreAuxiliary=*/false );
438         if ( std::find( usedHyps.begin(), usedHyps.end(), this ) != usedHyps.end() )
439           for ( TopExp_Explorer edge( face.Current(), TopAbs_EDGE); edge.More(); edge.Next() )
440             VISCOUS_3D::ToClearSubWithMain( smesh->GetSubMesh( edge.Current() ), face.Current() );
441       }
442   }
443 }
444 // END StdMeshers_ViscousLayers2D hypothesis
445 //================================================================================
446
447 using namespace VISCOUS_2D;
448
449 //================================================================================
450 /*!
451  * \brief Constructor of _ViscousBuilder2D
452  */
453 //================================================================================
454
455 _ViscousBuilder2D::_ViscousBuilder2D(SMESH_Mesh&                       theMesh,
456                                      const TopoDS_Face&                theFace,
457                                      const StdMeshers_ViscousLayers2D* theHyp):
458   _mesh( &theMesh ), _face( theFace ), _hyp( theHyp ), _helper( theMesh )
459 {
460   _helper.SetSubShape( _face );
461   _helper.SetElementsOnShape(true);
462
463   _surface = BRep_Tool::Surface( theFace );
464
465   if ( _hyp )
466     _fPowN = pow( _hyp->GetStretchFactor(), _hyp->GetNumberLayers() );
467 }
468
469 //================================================================================
470 /*!
471  * \brief Stores error description and returns false
472  */
473 //================================================================================
474
475 bool _ViscousBuilder2D::error(const string& text )
476 {
477   cout << "_ViscousBuilder2D::error " << text << endl;
478   _error->myName    = COMPERR_ALGO_FAILED;
479   _error->myComment = string("Viscous layers builder 2D: ") + text;
480   if ( SMESH_subMesh* sm = _mesh->GetSubMesh( _face ) )
481   {
482     SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
483     if ( smError && smError->myAlgo )
484       _error->myAlgo = smError->myAlgo;
485     smError = _error;
486   }
487   //makeGroupOfLE(); // debug
488
489   return false;
490 }
491
492 //================================================================================
493 /*!
494  * \brief Does its job
495  */
496 //================================================================================
497
498 SMESH_ProxyMesh::Ptr _ViscousBuilder2D::Compute()
499 {
500   _error       = SMESH_ComputeError::New(COMPERR_OK);
501   _faceSideVec = StdMeshers_FaceSide::GetFaceWires( _face, *_mesh, true, _error );
502   if ( !_error->IsOK() )
503     return _proxyMesh;
504
505   //PyDump debugDump;
506
507   if ( !findEdgesWithLayers() ) // analysis of a shape
508     return _proxyMesh;
509
510   if ( ! makePolyLines() ) // creation of fronts
511     return _proxyMesh;
512     
513   if ( ! inflate() ) // advance fronts
514     return _proxyMesh;
515
516   if ( !shrink() ) // shrink segments on edges w/o layers
517     return _proxyMesh;
518
519   if ( ! refine() ) // make faces
520     return _proxyMesh;
521
522   //makeGroupOfLE(); // debug
523   //debugDump.Finish();
524
525   return _proxyMesh;
526 }
527
528 //================================================================================
529 /*!
530  * \brief Finds EDGE's to make viscous layers on.
531  */
532 //================================================================================
533
534 bool _ViscousBuilder2D::findEdgesWithLayers()
535 {
536   // collect all EDGEs to ignore defined by hyp
537   vector<TGeomID> ids = _hyp->GetBndShapesToIgnore();
538   for ( size_t i = 0; i < ids.size(); ++i )
539   {
540     const TopoDS_Shape& s = getMeshDS()->IndexToShape( ids[i] );
541     if ( !s.IsNull() && s.ShapeType() == TopAbs_EDGE )
542       _ignoreShapeIds.insert( ids[i] );
543   }
544
545   // check all EDGEs of the _face
546   int totalNbEdges = 0;
547   for ( size_t iWire = 0; iWire < _faceSideVec.size(); ++iWire )
548   {
549     StdMeshers_FaceSidePtr wire = _faceSideVec[ iWire ];
550     totalNbEdges += wire->NbEdges();
551     for ( int iE = 0; iE < wire->NbEdges(); ++iE )
552       if ( _helper.NbAncestors( wire->Edge( iE ), *_mesh, TopAbs_FACE ) > 1 )
553       {
554         // ignore internal EDGEs (shared by several FACEs)
555         TGeomID edgeID = getMeshDS()->ShapeToIndex( wire->Edge( iE ));
556         _ignoreShapeIds.insert( edgeID );
557
558         // check if ends of an EDGE are to be added to _noShrinkVert
559         PShapeIteratorPtr faceIt = _helper.GetAncestors( wire->Edge( iE ), *_mesh, TopAbs_FACE );
560         while ( const TopoDS_Shape* neighbourFace = faceIt->next() )
561         {
562           if ( neighbourFace->IsSame( _face )) continue;
563           SMESH_Algo* algo = _mesh->GetGen()->GetAlgo( *_mesh, *neighbourFace );
564           if ( !algo ) continue;
565
566           const StdMeshers_ViscousLayers2D* viscHyp = 0;
567           const list <const SMESHDS_Hypothesis *> & allHyps =
568             algo->GetUsedHypothesis(*_mesh, *neighbourFace, /*noAuxiliary=*/false);
569           list< const SMESHDS_Hypothesis *>::const_iterator hyp = allHyps.begin();
570           for ( ; hyp != allHyps.end() && !viscHyp; ++hyp )
571             viscHyp = dynamic_cast<const StdMeshers_ViscousLayers2D*>( *hyp );
572
573           set<TGeomID> neighbourIgnoreEdges;
574           if (viscHyp) {
575             vector<TGeomID> ids = _hyp->GetBndShapesToIgnore();
576             neighbourIgnoreEdges.insert( ids.begin(), ids.end() );
577           }
578           for ( int iV = 0; iV < 2; ++iV )
579           {
580             TopoDS_Vertex vertex = iV ? wire->LastVertex(iE) : wire->FirstVertex(iE);
581             if ( !viscHyp )
582               _noShrinkVert.insert( getMeshDS()->ShapeToIndex( vertex ));
583             else
584             {
585               PShapeIteratorPtr edgeIt = _helper.GetAncestors( vertex, *_mesh, TopAbs_EDGE );
586               while ( const TopoDS_Shape* edge = edgeIt->next() )
587                 if ( !edge->IsSame( wire->Edge( iE )) &&
588                      neighbourIgnoreEdges.count( getMeshDS()->ShapeToIndex( *edge )))
589                   _noShrinkVert.insert( getMeshDS()->ShapeToIndex( vertex ));
590             }
591           }
592         }
593       }
594   }
595   return ( totalNbEdges > _ignoreShapeIds.size() );
596 }
597
598 //================================================================================
599 /*!
600  * \brief Create the inner front of the viscous layers and prepare data for infation
601  */
602 //================================================================================
603
604 bool _ViscousBuilder2D::makePolyLines()
605 {
606   // Create _PolyLines and _LayerEdge's
607
608   // count total nb of EDGEs to allocate _polyLineVec
609   int nbEdges = 0;
610   for ( size_t iWire = 0; iWire < _faceSideVec.size(); ++iWire )
611     nbEdges += _faceSideVec[ iWire ]->NbEdges();
612   _polyLineVec.resize( nbEdges );
613
614   // Assign data to _PolyLine's
615   // ---------------------------
616
617   size_t iPoLine = 0;
618   for ( size_t iWire = 0; iWire < _faceSideVec.size(); ++iWire )
619   {
620     StdMeshers_FaceSidePtr      wire = _faceSideVec[ iWire ];
621     const vector<UVPtStruct>& points = wire->GetUVPtStruct();
622     int iPnt = 0;
623     for ( int iE = 0; iE < wire->NbEdges(); ++iE )
624     {
625       _PolyLine& L  = _polyLineVec[ iPoLine++ ];
626       L._wire       = wire.get();
627       L._edgeInd    = iE;
628       L._advancable = !_ignoreShapeIds.count( wire->EdgeID( iE ));
629
630       int iRight    = iPoLine - (( iE+1 < wire->NbEdges() ) ? 0 : wire->NbEdges() );
631       L._rightLine  = &_polyLineVec[ iRight ];
632       _polyLineVec[ iRight ]._leftLine = &L;
633
634       L._firstPntInd = iPnt;
635       double lastNormPar = wire->LastParameter( iE ) - 1e-10;
636       while ( points[ iPnt ].normParam < lastNormPar )
637         ++iPnt;
638       L._lastPntInd = iPnt;
639       L._lEdges.resize( L._lastPntInd - L._firstPntInd + 1 );
640
641       // TODO: add more _LayerEdge's to strongly curved EDGEs
642       // in order not to miss collisions
643
644       Handle(Geom2d_Curve) pcurve = L._wire->Curve2d( L._edgeInd );
645       gp_Pnt2d uv; gp_Vec2d tangent;
646       for ( int i = L._firstPntInd; i <= L._lastPntInd; ++i )
647       {
648         _LayerEdge& lEdge = L._lEdges[ i - L._firstPntInd ];
649         const double u = ( i == L._firstPntInd ? wire->FirstU(iE) : points[ i ].param );
650         pcurve->D1( u , uv, tangent );
651         tangent.Normalize();
652         if ( L._wire->Edge( iE ).Orientation() == TopAbs_REVERSED )
653           tangent.Reverse();
654         lEdge._uvOut = lEdge._uvIn = uv.XY();
655         lEdge._normal2D.SetCoord( -tangent.Y(), tangent.X() );
656         lEdge._ray.SetLocation( lEdge._uvOut );
657         lEdge._ray.SetDirection( lEdge._normal2D );
658         lEdge._isBlocked = false;
659         lEdge._length2D  = 0;
660
661         setLenRatio( lEdge, SMESH_TNodeXYZ( points[ i ].node ) );
662       }
663     }
664   }
665
666   // Fill _PolyLine's with _segments
667   // --------------------------------
668
669   double maxLen2dTo3dRatio = 0;
670   for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine )
671   {
672     _PolyLine& L = _polyLineVec[ iPoLine ];
673     L._segments.resize( L._lEdges.size() - 1 );
674     for ( size_t i = 1; i < L._lEdges.size(); ++i )
675     {
676       _Segment & S   = L._segments[i-1];
677       S._uv[0]       = & L._lEdges[i-1]._uvIn;
678       S._uv[1]       = & L._lEdges[i  ]._uvIn;
679       S._indexInLine = i-1;
680       if ( maxLen2dTo3dRatio < L._lEdges[i]._len2dTo3dRatio )
681         maxLen2dTo3dRatio = L._lEdges[i]._len2dTo3dRatio;
682     }
683     // // connect _PolyLine's with segments, the 1st _LayerEdge of every _PolyLine
684     // // becomes not connected to any segment
685     // if ( L._leftLine->_advancable )
686     //   L._segments[0]._uv[0] = & L._leftLine->_lEdges.back()._uvIn;
687
688     L._segTree.reset( new _SegmentTree( L._segments ));
689   }
690
691   // Evaluate possible _thickness if required layers thickness seems too high
692   // -------------------------------------------------------------------------
693
694   _thickness = _hyp->GetTotalThickness();
695   _SegmentTree::box_type faceBndBox2D;
696   for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine )
697     faceBndBox2D.Add( *_polyLineVec[ iPoLine]._segTree->getBox() );
698   //
699   if ( _thickness * maxLen2dTo3dRatio > sqrt( faceBndBox2D.SquareExtent() ) / 10 )
700   {
701     vector< const _Segment* > foundSegs;
702     double maxPossibleThick = 0;
703     _SegmentIntersection intersection;
704     for ( size_t iL1 = 0; iL1 < _polyLineVec.size(); ++iL1 )
705     {
706       _PolyLine& L1 = _polyLineVec[ iL1 ];
707       for ( size_t iL2 = iL1+1; iL2 < _polyLineVec.size(); ++iL2 )
708       {
709         _PolyLine& L2 = _polyLineVec[ iL2 ];
710         for ( size_t iLE = 1; iLE < L1._lEdges.size(); ++iLE )
711         {
712           foundSegs.clear();
713           L2._segTree->GetSegmentsNear( L1._lEdges[iLE]._ray, foundSegs );
714           for ( size_t i = 0; i < foundSegs.size(); ++i )
715             if ( intersection.Compute( *foundSegs[i], L1._lEdges[iLE]._ray ))
716             {
717               double  distToL2 = intersection._param2 / L1._lEdges[iLE]._len2dTo3dRatio;
718               double psblThick = distToL2 / ( 1 + L1._advancable + L2._advancable );
719               if ( maxPossibleThick < psblThick )
720                 maxPossibleThick = psblThick;
721             }
722         }
723       }
724     }
725     _thickness = Min( _hyp->GetTotalThickness(), maxPossibleThick );
726   }
727
728   // Adjust _LayerEdge's at _PolyLine's extremities
729   // -----------------------------------------------
730
731   for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine )
732   {
733     _PolyLine& LL = _polyLineVec[ iPoLine ];
734     _PolyLine& LR = *LL._rightLine;
735     adjustCommonEdge( LL, LR );
736   }
737   // recreate _segments if some _LayerEdge's have been removed by adjustCommonEdge()
738   for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine )
739   {
740     _PolyLine& L = _polyLineVec[ iPoLine ];
741     // if ( L._segments.size() ==  L._lEdges.size() - 1 )
742     //   continue;
743     L._segments.resize( L._lEdges.size() - 1 );
744     for ( size_t i = 1; i < L._lEdges.size(); ++i )
745     {
746       _Segment & S   = L._segments[i-1];
747       S._uv[0]       = & L._lEdges[i-1]._uvIn;
748       S._uv[1]       = & L._lEdges[i  ]._uvIn;
749       S._indexInLine = i-1;
750     }
751     L._segTree.reset( new _SegmentTree( L._segments ));
752   }
753   // connect _PolyLine's with segments, the 1st _LayerEdge of every _PolyLine
754   // becomes not connected to any segment
755   for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine )
756   {
757     _PolyLine& L = _polyLineVec[ iPoLine ];
758     if ( L._leftLine->_advancable )
759       L._segments[0]._uv[0] = & L._leftLine->_lEdges.back()._uvIn;
760   }
761
762   // Fill _reachableLines.
763   // ----------------------
764
765   // compute bnd boxes taking into account the layers total thickness
766   vector< _SegmentTree::box_type > lineBoxes( _polyLineVec.size() );
767   for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine )
768   {
769     lineBoxes[ iPoLine ] = *_polyLineVec[ iPoLine ]._segTree->getBox();
770     if ( _polyLineVec[ iPoLine ]._advancable )
771       lineBoxes[ iPoLine ].Enlarge( maxLen2dTo3dRatio * _thickness );
772   }
773   // _reachableLines
774   for ( iPoLine = 0; iPoLine < _polyLineVec.size(); ++iPoLine )
775   {
776     _PolyLine& L1 = _polyLineVec[ iPoLine ];
777     for ( size_t i = 0; i < _polyLineVec.size(); ++i )
778     {
779       _PolyLine& L2 = _polyLineVec[ i ];
780       if ( iPoLine == i || lineBoxes[ iPoLine ].IsOut( lineBoxes[ i ]))
781         continue;
782       if ( !L1._advancable && ( L1._leftLine == &L2 || L1._rightLine == &L2 ))
783         continue;
784       // check reachability by _LayerEdge's
785       int iDelta = 1; //Max( 1, L1._lEdges.size() / 100 );
786       for ( size_t iLE = 1; iLE < L1._lEdges.size(); iLE += iDelta )
787       {
788         _LayerEdge& LE = L1._lEdges[iLE];
789         if ( !lineBoxes[ i ].IsOut ( LE._uvOut,
790                                      LE._uvOut + LE._normal2D * _thickness * LE._len2dTo3dRatio )
791              &&
792              !L1.IsAdjacent( L2._segments[0] ))
793         {
794           L1._reachableLines.push_back( & L2 );
795           break;
796         }
797       }
798     }
799     // add self to _reachableLines
800     Geom2dAdaptor_Curve pcurve( L1._wire->Curve2d( L1._edgeInd ));
801     if ( pcurve.GetType() != GeomAbs_Line )
802     {
803       // TODO: check carefully
804       L1._reachableLines.push_back( & L1 );
805     }
806   }
807
808   return true;
809 }
810
811 //================================================================================
812 /*!
813  * \brief adjust common _LayerEdge of two adjacent _PolyLine's
814  *  \param LL - left _PolyLine
815  *  \param LR - right _PolyLine
816  */
817 //================================================================================
818
819 void _ViscousBuilder2D::adjustCommonEdge( _PolyLine& LL, _PolyLine& LR )
820 {
821   int nbAdvancableL = LL._advancable + LR._advancable;
822   if ( nbAdvancableL == 0 )
823     return;
824
825   _LayerEdge& EL = LL._lEdges.back();
826   _LayerEdge& ER = LR._lEdges.front();
827   gp_XY normL    = EL._normal2D;
828   gp_XY normR    = ER._normal2D;
829   gp_XY tangL ( normL.Y(), -normL.X() );
830   //gp_XY tangR ( normR.Y(), -normR.X() );
831
832   gp_XY normCommon = ( normL + normR ).Normalized(); // average normal at VERTEX
833
834   EL._normal2D = normCommon;
835   EL._ray.SetLocation ( EL._uvOut );
836   EL._ray.SetDirection( EL._normal2D );
837
838   // update _LayerEdge::_len2dTo3dRatio according to a new direction
839   const vector<UVPtStruct>& points = LL._wire->GetUVPtStruct();
840   setLenRatio( EL, SMESH_TNodeXYZ( points[ LL._lastPntInd ].node ));
841
842   ER = EL;
843
844   const double dotNormTang = normR * tangL;
845   const bool    largeAngle = Abs( dotNormTang ) > 0.2;
846   if ( largeAngle )
847   {
848     // recompute _len2dTo3dRatio to take into account angle between EDGEs
849     gp_Vec2d oldNorm( LL._advancable ? normL : normR );
850     double fact = 1. / Max( 0.3, Cos( oldNorm.Angle(  normCommon )));
851     EL._len2dTo3dRatio *= fact;
852     ER._len2dTo3dRatio  = EL._len2dTo3dRatio;
853
854     if ( dotNormTang < 0. ) // ---------------------------- CONVEX ANGLE
855     {
856       // Remove _LayerEdge's intersecting the normCommon
857       //
858       const gp_XY& pCommOut = ER._uvOut;
859       gp_XY pCommIn( pCommOut + normCommon * _thickness * EL._len2dTo3dRatio );
860       _Segment segCommon( pCommOut, pCommIn );
861       _SegmentIntersection intersection;
862       for ( int isR = 0; isR < 2; ++isR ) // loop on [ LL, LR ]
863       {
864         _PolyLine&                 L = isR ? LR : LL;
865         _PolyLine::TEdgeIterator eIt = isR ? L._lEdges.begin()+1 : L._lEdges.end()-2;
866         int                      dIt = isR ? +1 : -1;
867         // at least 2 _LayerEdge's should remain in a _PolyLine (if _advancable)
868         if ( L._lEdges.size() < 3 ) continue;
869         size_t iLE = 1;
870         for ( ; iLE < L._lEdges.size(); ++iLE, eIt += dIt )
871         {
872           gp_XY uvIn = eIt->_uvOut + eIt->_normal2D * _thickness * eIt->_len2dTo3dRatio;
873           _Segment segOfEdge( eIt->_uvOut, uvIn );
874           if ( !intersection.Compute( segCommon, segOfEdge ))
875             break;
876         }
877         if ( iLE >= L._lEdges.size () - 1 )
878         {
879           // all _LayerEdge's intersect the segCommon, limit inflation
880           // of remaining 2 _LayerEdge's
881           vector< _LayerEdge > newEdgeVec( 2 );
882           newEdgeVec.front() = L._lEdges.front();
883           newEdgeVec.back()  = L._lEdges.back();
884           L._lEdges.swap( newEdgeVec );
885           if ( !isR ) std::swap( intersection._param1 , intersection._param2 );
886           L._lEdges.front()._len2dTo3dRatio *= intersection._param1;
887           L._lEdges.back ()._len2dTo3dRatio *= intersection._param2;
888         }
889         else if ( iLE != 1 )
890         {
891           // eIt points to the _LayerEdge not intersecting with segCommon
892           if ( isR )
893             LR._lEdges.erase( LR._lEdges.begin()+1, eIt );
894           else
895             LL._lEdges.erase( eIt, --LL._lEdges.end() );
896         }
897       }
898     }
899     else // ------------------------------------------ CONCAVE ANGLE
900     {
901       if ( nbAdvancableL == 1 )
902       {
903         // make that the _LayerEdge at VERTEX is not shared by LL and LR
904         _LayerEdge& notSharedEdge = LL._advancable ? LR._lEdges[0] : LL._lEdges.back();
905         notSharedEdge._normal2D.SetCoord( 0.,0. );
906       }
907     }
908   }
909 }
910
911 //================================================================================
912 /*!
913  * \brief Compute and set _LayerEdge::_len2dTo3dRatio
914  */
915 //================================================================================
916
917 void _ViscousBuilder2D::setLenRatio( _LayerEdge& LE, const gp_Pnt& pOut )
918 {
919   const double probeLen2d = 1e-3;
920
921   gp_Pnt2d p2d = LE._uvOut + LE._normal2D * probeLen2d;
922   gp_Pnt   p3d = _surface->Value( p2d.X(), p2d.Y() );
923   double len3d = p3d.Distance( pOut );
924   if ( len3d < std::numeric_limits<double>::min() )
925     LE._len2dTo3dRatio = std::numeric_limits<double>::min();
926   else
927     LE._len2dTo3dRatio = probeLen2d / len3d;
928 }
929
930 //================================================================================
931 /*!
932  * \brief Increase length of _LayerEdge's to reach the required thickness of layers
933  */
934 //================================================================================
935
936 bool _ViscousBuilder2D::inflate()
937 {
938   // Limit size of inflation step by geometry size found by
939   // itersecting _LayerEdge's with _Segment's
940   double minStepSize = _thickness;
941   vector< const _Segment* > foundSegs;
942   _SegmentIntersection intersection;
943   for ( size_t iL1 = 0; iL1 < _polyLineVec.size(); ++iL1 )
944   {
945     _PolyLine& L1 = _polyLineVec[ iL1 ];
946     for ( size_t iL2 = 0; iL2 < L1._reachableLines.size(); ++iL2 )
947     {
948       _PolyLine& L2 = * L1._reachableLines[ iL2 ];
949       for ( size_t iLE = 1; iLE < L1._lEdges.size(); ++iLE )
950       {
951         foundSegs.clear();
952         L2._segTree->GetSegmentsNear( L1._lEdges[iLE]._ray, foundSegs );
953         for ( size_t i = 0; i < foundSegs.size(); ++i )
954           if ( ! L1.IsAdjacent( *foundSegs[i] ) &&
955                intersection.Compute( *foundSegs[i], L1._lEdges[iLE]._ray ))
956           {
957             double distToL2 = intersection._param2 / L1._lEdges[iLE]._len2dTo3dRatio;
958             double     step = distToL2 / ( 1 + L1._advancable + L2._advancable );
959             if ( step < minStepSize )
960               minStepSize = step;
961           }
962       }
963     }
964   }
965 #ifdef __myDEBUG
966   cout << "-- minStepSize = " << minStepSize << endl;
967 #endif
968
969   double curThick = 0, stepSize = minStepSize;
970   int nbSteps = 0;
971   while ( curThick < _thickness )
972   {
973     curThick += stepSize * 1.25;
974     if ( curThick > _thickness )
975       curThick = _thickness;
976
977     // Elongate _LayerEdge's
978     for ( size_t iL = 0; iL < _polyLineVec.size(); ++iL )
979     {
980       _PolyLine& L = _polyLineVec[ iL ];
981       if ( !L._advancable ) continue;
982       //dumpFunction(SMESH_Comment("inflate")<<data._index<<"_step"<<nbSteps); // debug
983       for ( size_t iLE = L.FirstLEdge(); iLE < L._lEdges.size(); ++iLE )
984         L._lEdges[iLE].SetNewLength( curThick );
985       // for ( int k=0; k<L._segments.size(); ++k)
986       //   cout << "( " << L._segments[k].p1().X() << ", " <<L._segments[k].p1().Y() << " ) "
987       //        << "( " << L._segments[k].p2().X() << ", " <<L._segments[k].p2().Y() << " ) "
988       //        << endl;
989       L._segTree.reset( new _SegmentTree( L._segments ));
990       //dumpFunctionEnd();
991     }
992
993     // Avoid intersection of _Segment's
994     minStepSize = fixCollisions( nbSteps );
995
996 #ifdef __myDEBUG
997   cout << "-- minStepSize = " << minStepSize << endl;
998 #endif
999     if ( minStepSize <= 0 )
1000     {
1001       break; // no more inflating possible
1002     }
1003     stepSize = minStepSize;
1004     nbSteps++;
1005   }
1006
1007   if (nbSteps == 0 )
1008     return error("failed at the very first inflation step");
1009
1010   return true;
1011 }
1012
1013 //================================================================================
1014 /*!
1015  * \brief Remove intersection of _PolyLine's
1016  *  \param stepNb - current step nb
1017  *  \retval double - next step size
1018  */
1019 //================================================================================
1020
1021 double _ViscousBuilder2D::fixCollisions( const int stepNb )
1022 {
1023   // look for intersections of _Segment's by intersecting _LayerEdge's with
1024   // _Segment's
1025   double newStep = 1e+100;
1026   vector< const _Segment* > foundSegs;
1027   _SegmentIntersection intersection;
1028   for ( size_t iL1 = 0; iL1 < _polyLineVec.size(); ++iL1 )
1029   {
1030     _PolyLine& L1 = _polyLineVec[ iL1 ];
1031     //if ( !L1._advancable ) continue;
1032     for ( size_t iL2 = 0; iL2 < L1._reachableLines.size(); ++iL2 )
1033     {
1034       _PolyLine& L2 = * L1._reachableLines[ iL2 ];
1035       for ( size_t iLE = L1.FirstLEdge(); iLE < L1._lEdges.size(); ++iLE )
1036       {
1037         _LayerEdge& LE1 = L1._lEdges[iLE];
1038         foundSegs.clear();
1039         L2._segTree->GetSegmentsNear( LE1._ray, foundSegs );
1040         for ( size_t i = 0; i < foundSegs.size(); ++i )
1041           if ( ! L1.IsAdjacent( *foundSegs[i] ) &&
1042                intersection.Compute( *foundSegs[i], LE1._ray ))
1043           {
1044             const double dist2DToL2 = intersection._param2;
1045             double         newLen2D = dist2DToL2 / 2;
1046             if ( newLen2D < 1.1 * LE1._length2D ) // collision!
1047             {
1048               if ( newLen2D < LE1._length2D )
1049               {
1050                 if ( L1._advancable )
1051                 {
1052                   LE1.SetNewLength( newLen2D / LE1._len2dTo3dRatio );
1053                   L2._lEdges[ foundSegs[i]->_indexInLine     ]._isBlocked = true;
1054                   L2._lEdges[ foundSegs[i]->_indexInLine + 1 ]._isBlocked = true;
1055                 }
1056                 else // here dist2DToL2 < 0 and LE1._length2D == 0
1057                 {
1058                   _LayerEdge LE2[2] = { L2._lEdges[ foundSegs[i]->_indexInLine     ],
1059                                         L2._lEdges[ foundSegs[i]->_indexInLine + 1 ] };
1060                   _Segment outSeg2( LE2[0]._uvOut, LE2[1]._uvOut );
1061                   intersection.Compute( outSeg2, LE1._ray );
1062                   newLen2D = intersection._param2 / 2;
1063
1064                   LE2[0].SetNewLength( newLen2D / LE2[0]._len2dTo3dRatio );
1065                   LE2[0]._isBlocked = true;
1066                   LE2[1].SetNewLength( newLen2D / LE2[1]._len2dTo3dRatio );
1067                   LE2[1]._isBlocked = true;
1068                 }
1069               }
1070               LE1._isBlocked = true; // !! after SetNewLength()
1071             }
1072             else
1073             {
1074               double step2D = newLen2D - LE1._length2D;
1075               double step   = step2D / LE1._len2dTo3dRatio;
1076               if ( step < newStep )
1077                 newStep = step;
1078             }
1079           }
1080       }
1081     }
1082   }
1083   return newStep;
1084 }
1085
1086 //================================================================================
1087 /*!
1088  * \brief Create new edges and shrink edges existing on a non-advancable _PolyLine
1089  *        adjacent to an advancable one.
1090  */
1091 //================================================================================
1092
1093 bool _ViscousBuilder2D::shrink()
1094 {
1095   gp_Pnt2d uv; gp_Vec2d tangent;
1096   _SegmentIntersection intersection;
1097   double sign;
1098
1099   for ( size_t iL1 = 0; iL1 < _polyLineVec.size(); ++iL1 )
1100   {
1101     _PolyLine& L = _polyLineVec[ iL1 ]; // line with no layers
1102     if ( L._advancable )
1103       continue;
1104     if ( !L._rightLine->_advancable && !L._leftLine->_advancable )
1105       continue;
1106
1107     const TopoDS_Edge&        E = L._wire->Edge      ( L._edgeInd );
1108     const int            edgeID = L._wire->EdgeID    ( L._edgeInd );
1109     const double        edgeLen = L._wire->EdgeLength( L._edgeInd );
1110     Handle(Geom2d_Curve) pcurve = L._wire->Curve2d   ( L._edgeInd );
1111     const bool     edgeReversed = ( E.Orientation() == TopAbs_REVERSED );
1112
1113     SMESH_MesherHelper helper( *_mesh ); // to create nodes and edges on E
1114     helper.SetSubShape( E );
1115     helper.SetElementsOnShape( true );
1116
1117     // Check a FACE adjacent to _face by E
1118     bool existingNodesFound = false;
1119     PShapeIteratorPtr faceIt = _helper.GetAncestors( E, *_mesh, TopAbs_FACE );
1120     while ( const TopoDS_Shape* f = faceIt->next() )
1121       if ( !_face.IsSame( *f ))
1122       {
1123         SMESH_ProxyMesh::Ptr pm = _ProxyMeshHolder::FindProxyMeshOfFace( *f, *_mesh );
1124         if ( !pm || pm->NbProxySubMeshes() == 0 )
1125         {
1126           // There are no viscous layers on an adjacent FACE, clear it's 2D mesh
1127           removeMeshFaces( *f );
1128         }
1129         else
1130         {
1131           // There are viscous layers on the adjacent FACE;
1132           // look for already shrinked segments on E
1133           const SMESH_ProxyMesh::SubMesh* adjEdgeSM = pm->GetProxySubMesh( E );
1134           if ( adjEdgeSM && adjEdgeSM->NbElements() > 0 )
1135           {
1136             existingNodesFound = true;
1137
1138             // copy data of moved nodes to my _ProxyMeshOfFace
1139             const UVPtStructVec& adjNodeData = adjEdgeSM->GetUVPtStructVec();
1140             UVPtStructVec nodeDataVec( adjNodeData.size() );
1141             for ( size_t iP = 0, iAdj = adjNodeData.size(); iP < nodeDataVec.size(); ++iP )
1142             {
1143               nodeDataVec[ iP ] = adjNodeData[ --iAdj ];
1144               gp_Pnt2d uv = pcurve->Value( nodeDataVec[ iP ].param );
1145               nodeDataVec[iP].u = uv.X();
1146               nodeDataVec[iP].v = uv.Y();
1147               nodeDataVec[iP].normParam = 1 - nodeDataVec[iP].normParam;
1148             }
1149             _ProxyMeshOfFace::_EdgeSubMesh* myEdgeSM = getProxyMesh()->GetEdgeSubMesh( edgeID );
1150             myEdgeSM->SetUVPtStructVec( nodeDataVec );
1151
1152             // copy layer nodes
1153             map< double, const SMDS_MeshNode* > u2layerNodes;
1154             SMESH_Algo::GetSortedNodesOnEdge( getMeshDS(), E, /*skipMedium=*/true, u2layerNodes );
1155             // u2layerNodes includes nodes on vertices, layer nodes and shrinked nodes
1156             vector< std::pair< double, const SMDS_MeshNode* > > layerUNodes;
1157             layerUNodes.resize( u2layerNodes.size() - 2 ); // skip vertex nodes
1158             map< double, const SMDS_MeshNode* >::iterator u2n = u2layerNodes.begin();
1159             size_t iBeg = 0, iEnd = layerUNodes.size() - 1, *pIndex = edgeReversed ? &iEnd : &iBeg;
1160             for ( ++u2n; iBeg < u2layerNodes.size()-2; ++u2n, ++iBeg, --iEnd ) {
1161               layerUNodes[ *pIndex ] = *u2n;
1162             }
1163             if ( L._leftLine->_advancable && layerUNodes.size() >= _hyp->GetNumberLayers() )
1164             {
1165               vector<gp_XY>& uvVec = L._lEdges.front()._uvRefined;
1166               for ( int i = 0; i < _hyp->GetNumberLayers(); ++i ) {
1167                 L._leftNodes.push_back( layerUNodes[i].second );
1168                 uvVec.push_back ( pcurve->Value( layerUNodes[i].first ).XY() );
1169               }
1170             }
1171             if ( L._rightLine->_advancable && layerUNodes.size() >= 2*_hyp->GetNumberLayers() )
1172             {
1173               vector<gp_XY>& uvVec = L._lEdges.back()._uvRefined;
1174               for ( int i = 0, j = layerUNodes.size()-1; i < _hyp->GetNumberLayers(); ++i, --j ) {
1175                 L._rightNodes.push_back( layerUNodes[j].second );
1176                 uvVec.push_back ( pcurve->Value( layerUNodes[j].first ).XY() );
1177               }
1178             }
1179           }
1180         }
1181       } // loop on FACEs sharing E
1182
1183     if ( existingNodesFound )
1184       continue; // nothing more to do in this case
1185
1186     double u1 = L._wire->FirstU( L._edgeInd ), uf = u1;
1187     double u2 = L._wire->LastU ( L._edgeInd ), ul = u2;
1188
1189     // Get length of existing segments (from edge start to node) and their nodes
1190     const vector<UVPtStruct>& points = L._wire->GetUVPtStruct();
1191     UVPtStructVec nodeDataVec( & points[ L._firstPntInd ],
1192                                & points[ L._lastPntInd + 1 ]);
1193     nodeDataVec.front().param = u1; // U on vertex is correct on only one of shared edges
1194     nodeDataVec.back ().param = u2;
1195     nodeDataVec.front().normParam = 0;
1196     nodeDataVec.back ().normParam = 1;
1197     vector< double > segLengths( nodeDataVec.size() - 1 );
1198     BRepAdaptor_Curve curve( E );
1199     for ( size_t iP = 1; iP < nodeDataVec.size(); ++iP )
1200     {
1201       const double len = GCPnts_AbscissaPoint::Length( curve, uf, nodeDataVec[iP].param );
1202       segLengths[ iP-1 ] = len;
1203     }
1204
1205     // Before
1206     //  n1    n2    n3    n4
1207     //  x-----x-----x-----x-----
1208     //  |  e1    e2    e3    e4
1209
1210     // After
1211     //  n1          n2    n3
1212     //  x-x-x-x-----x-----x----
1213     //  | | | |  e1    e2    e3
1214
1215     // Move first and last parameters on EDGE (U of n1) according to layers' thickness
1216     // and create nodes of layers on EDGE ( -x-x-x )
1217     for ( int isR = 0; isR < 2; ++isR )
1218     {
1219       _PolyLine* L2 = isR ? L._rightLine : L._leftLine; // line with layers
1220       if ( !L2->_advancable ) continue;
1221
1222       double & u = isR ? u2 : u1; // param to move
1223       double  u0 = isR ? ul : uf; // init value of the param to move
1224       int  iPEnd = isR ? nodeDataVec.size() - 1 : 0;
1225
1226       // try to find length of advancement along L by intersecting L with
1227       // an adjacent _Segment of L2
1228
1229       double length2D;
1230       sign = ( isR ^ edgeReversed ) ? -1. : 1.;
1231       pcurve->D1( u, uv, tangent );
1232
1233       gp_Ax2d      edgeRay( uv, tangent * sign );
1234       const _Segment& seg2( isR ? L2->_segments.front() : L2->_segments.back() );
1235       // make an elongated seg2
1236       gp_XY seg2Vec( seg2.p2() - seg2.p1() );
1237       gp_XY longSeg2p1 = seg2.p1() - 1000 * seg2Vec;
1238       gp_XY longSeg2p2 = seg2.p2() + 1000 * seg2Vec;
1239       _Segment longSeg2( longSeg2p1, longSeg2p2 );
1240       if ( intersection.Compute( longSeg2, edgeRay )) // convex VERTEX
1241       {
1242         length2D = intersection._param2; // |L  seg2     
1243                                          // |  o---o--- 
1244                                          // | /    |    
1245                                          // |/     |  L2
1246                                          // x------x--- 
1247       }
1248       else  // concave VERTEX            //  o-----o--- 
1249       {                                  //   \    |    
1250                                          //    \   |  L2
1251                                          //     x--x--- 
1252                                          //    /        
1253                                          // L /         
1254         length2D = ( isR ? L2->_lEdges.front() : L2->_lEdges.back() )._length2D;
1255       }
1256        // move u to the internal boundary of layers
1257       u += length2D * sign;
1258       nodeDataVec[ iPEnd ].param = u;
1259
1260       gp_Pnt2d newUV = pcurve->Value( u );
1261       nodeDataVec[ iPEnd ].u = newUV.X();
1262       nodeDataVec[ iPEnd ].v = newUV.Y();
1263
1264       // compute params of layers on L
1265       vector<double> heights;
1266       calcLayersHeight( u - u0, heights );
1267       //
1268       vector< double > params( heights.size() );
1269       for ( size_t i = 0; i < params.size(); ++i )
1270         params[ i ] = u0 + heights[ i ];
1271
1272       // create nodes of layers and edges between them
1273       vector< const SMDS_MeshNode* >& layersNode = isR ? L._rightNodes : L._leftNodes;
1274       vector<gp_XY>& nodeUV = ( isR ? L._lEdges.back() : L._lEdges[0] )._uvRefined;
1275       nodeUV.resize    ( _hyp->GetNumberLayers() );
1276       layersNode.resize( _hyp->GetNumberLayers() );
1277       const SMDS_MeshNode* vertexNode = nodeDataVec[ iPEnd ].node;
1278       const SMDS_MeshNode *  prevNode = vertexNode;
1279       for ( size_t i = 0; i < params.size(); ++i )
1280       {
1281         gp_Pnt p        = curve.Value( params[i] );
1282         layersNode[ i ] = helper.AddNode( p.X(), p.Y(), p.Z(), /*id=*/0, params[i] );
1283         nodeUV    [ i ] = pcurve->Value( params[i] ).XY();
1284         helper.AddEdge( prevNode, layersNode[ i ] );
1285         prevNode = layersNode[ i ];
1286       }
1287
1288       // replace a node on vertex by a node of last (most internal) layer
1289       // in a segment on E
1290       SMDS_ElemIteratorPtr segIt = vertexNode->GetInverseElementIterator( SMDSAbs_Edge );
1291       const SMDS_MeshNode* segNodes[3];
1292       while ( segIt->more() )
1293       {
1294         const SMDS_MeshElement* segment = segIt->next();
1295         if ( segment->getshapeId() != edgeID ) continue;
1296         
1297         const int nbNodes = segment->NbNodes();
1298         for ( int i = 0; i < nbNodes; ++i )
1299         {
1300           const SMDS_MeshNode* n = segment->GetNode( i );
1301           segNodes[ i ] = ( n == vertexNode ? layersNode.back() : n );
1302         }
1303         getMeshDS()->ChangeElementNodes( segment, segNodes, nbNodes );
1304         break;
1305       }
1306       nodeDataVec[ iPEnd ].node = layersNode.back();
1307
1308     } // loop on the extremities of L
1309
1310     // Shrink edges to fit in between the layers at EDGE ends
1311
1312     const double newLength = GCPnts_AbscissaPoint::Length( curve, u1, u2 );
1313     const double lenRatio  = newLength / edgeLen * ( edgeReversed ? -1. : 1. );
1314     for ( size_t iP = 1; iP < nodeDataVec.size()-1; ++iP )
1315     {
1316       const SMDS_MeshNode* oldNode = nodeDataVec[iP].node;
1317
1318       GCPnts_AbscissaPoint discret( curve, segLengths[iP-1] * lenRatio, u1 );
1319       if ( !discret.IsDone() )
1320         throw SALOME_Exception(LOCALIZED("GCPnts_AbscissaPoint failed"));
1321
1322       nodeDataVec[iP].param = discret.Parameter();
1323       if ( oldNode->GetPosition()->GetTypeOfPosition() != SMDS_TOP_EDGE )
1324         throw SALOME_Exception(SMESH_Comment("ViscousBuilder2D: not SMDS_TOP_EDGE node position: ")
1325                                << oldNode->GetPosition()->GetTypeOfPosition()
1326                                << " of node " << oldNode->GetID());
1327       SMDS_EdgePosition* pos = static_cast<SMDS_EdgePosition*>( oldNode->GetPosition() );
1328       pos->SetUParameter( nodeDataVec[iP].param );
1329
1330       gp_Pnt newP = curve.Value( nodeDataVec[iP].param );
1331       getMeshDS()->MoveNode( oldNode, newP.X(), newP.Y(), newP.Z() );
1332
1333       gp_Pnt2d newUV = pcurve->Value( nodeDataVec[iP].param ).XY();
1334       nodeDataVec[iP].u         = newUV.X();
1335       nodeDataVec[iP].v         = newUV.Y();
1336       nodeDataVec[iP].normParam = segLengths[iP-1] / edgeLen;
1337       nodeDataVec[iP].x         = segLengths[iP-1] / edgeLen;
1338       nodeDataVec[iP].y         = segLengths[iP-1] / edgeLen;
1339     }
1340
1341     // create a proxy sub-mesh containing the moved nodes
1342     _ProxyMeshOfFace::_EdgeSubMesh* edgeSM = getProxyMesh()->GetEdgeSubMesh( edgeID );
1343     edgeSM->SetUVPtStructVec( nodeDataVec );
1344
1345     // set a sub-mesh event listener to remove just created edges when
1346     // "ViscousLayers2D" hypothesis is modified
1347     VISCOUS_3D::ToClearSubWithMain( _mesh->GetSubMesh( E ), _face );
1348
1349   } // loop on _polyLineVec
1350
1351   return true;
1352 }
1353
1354 //================================================================================
1355 /*!
1356  * \brief Make faces
1357  */
1358 //================================================================================
1359
1360 bool _ViscousBuilder2D::refine()
1361 {
1362   // remove elements and nodes from _face
1363   removeMeshFaces( _face );
1364
1365   // store a proxyMesh in a sub-mesh
1366   // make faces on each _PolyLine
1367   vector< double > layersHeight;
1368   double prevLen2D = -1;
1369   for ( size_t iL = 0; iL < _polyLineVec.size(); ++iL )
1370   {
1371     _PolyLine& L = _polyLineVec[ iL ];
1372     if ( !L._advancable ) continue;
1373
1374     //if ( L._leftLine->_advancable ) L._lEdges[0] = L._leftLine->_lEdges.back();
1375
1376     // calculate intermediate UV on _LayerEdge's ( _LayerEdge::_uvRefined )
1377     size_t iLE = 0, nbLE = L._lEdges.size();
1378     if ( /*!L._leftLine->_advancable &&*/ L.IsCommonEdgeShared( *L._leftLine ))
1379     {
1380       L._lEdges[0] = L._leftLine->_lEdges.back();
1381       iLE += int( !L._leftLine->_advancable );
1382     }
1383     if ( !L._rightLine->_advancable && L.IsCommonEdgeShared( *L._rightLine ))
1384     {
1385       L._lEdges.back() = L._rightLine->_lEdges[0];
1386       --nbLE;
1387     }
1388     for ( ; iLE < nbLE; ++iLE )
1389     {
1390       _LayerEdge& LE = L._lEdges[iLE];
1391       if ( fabs( LE._length2D - prevLen2D ) > LE._length2D / 100. )
1392       {
1393         calcLayersHeight( LE._length2D, layersHeight );
1394         prevLen2D = LE._length2D;
1395       }
1396       for ( size_t i = 0; i < layersHeight.size(); ++i )
1397         LE._uvRefined.push_back( LE._uvOut + LE._normal2D * layersHeight[i] );
1398     }
1399
1400     // nodes to create 1 layer of faces
1401     vector< const SMDS_MeshNode* > outerNodes( L._lastPntInd - L._firstPntInd + 1 );
1402     vector< const SMDS_MeshNode* > innerNodes( L._lastPntInd - L._firstPntInd + 1 );
1403
1404     // initialize outerNodes by node on the L._wire
1405     const vector<UVPtStruct>& points = L._wire->GetUVPtStruct();
1406     for ( int i = L._firstPntInd; i <= L._lastPntInd; ++i )
1407       outerNodes[ i-L._firstPntInd ] = points[i].node;
1408
1409     // compute normalized [0;1] node parameters of outerNodes
1410     vector< double > normPar( L._lastPntInd - L._firstPntInd + 1 );
1411     const double
1412       normF    = L._wire->FirstParameter( L._edgeInd ),
1413       normL    = L._wire->LastParameter ( L._edgeInd ),
1414       normDist = normL - normF;
1415     for ( int i = L._firstPntInd; i <= L._lastPntInd; ++i )
1416       normPar[ i - L._firstPntInd ] = ( points[i].normParam - normF ) / normDist;
1417
1418     // Create layers of faces
1419
1420     int hasLeftNode  = ( !L._leftLine->_rightNodes.empty() );
1421     int hasRightNode = ( !L._rightLine->_leftNodes.empty() );
1422     size_t iS, iN0 = hasLeftNode, nbN = innerNodes.size() - hasRightNode;
1423     L._leftNodes .resize( _hyp->GetNumberLayers() );
1424     L._rightNodes.resize( _hyp->GetNumberLayers() );
1425     vector< double > segLen( L._lEdges.size() );
1426     segLen[0] = 0.0;
1427     for ( int iF = 0; iF < _hyp->GetNumberLayers(); ++iF ) // loop on layers of faces
1428     {
1429       // get accumulated length of intermediate segments
1430       for ( iS = 1; iS < segLen.size(); ++iS )
1431       {
1432         double sLen = (L._lEdges[iS-1]._uvRefined[iF] - L._lEdges[iS]._uvRefined[iF] ).Modulus();
1433         segLen[iS] = segLen[iS-1] + sLen;
1434       }
1435       // normalize the accumulated length
1436       for ( iS = 1; iS < segLen.size(); ++iS )
1437         segLen[iS] /= segLen.back();
1438
1439       // create innerNodes
1440       iS = 0;
1441       for ( size_t i = iN0; i < nbN; ++i )
1442       {
1443         while ( normPar[i] > segLen[iS+1] )
1444           ++iS;
1445         double r = ( normPar[i] - segLen[iS] ) / ( segLen[iS+1] - segLen[iS] );
1446         gp_XY uv = r * L._lEdges[iS+1]._uvRefined[iF] + (1-r) * L._lEdges[iS]._uvRefined[iF];
1447         gp_Pnt p = _surface->Value( uv.X(), uv.Y() );
1448         innerNodes[i] = _helper.AddNode( p.X(), p.Y(), p.Z(), /*id=*/0, uv.X(), uv.Y() );
1449       }
1450       if ( hasLeftNode ) innerNodes.front() = L._leftLine->_rightNodes[ iF ];
1451       if ( hasRightNode ) innerNodes.back() = L._rightLine->_leftNodes[ iF ];
1452       L._rightNodes[ iF ] = innerNodes.back();
1453       L._leftNodes [ iF ] = innerNodes.front();
1454
1455       // create faces
1456       // TODO care of orientation
1457       for ( size_t i = 1; i < innerNodes.size(); ++i )
1458         _helper.AddFace( outerNodes[ i-1 ], outerNodes[ i ],
1459                          innerNodes[ i ],   innerNodes[ i-1 ]);
1460
1461       outerNodes.swap( innerNodes );
1462     }
1463
1464     // Fill the _ProxyMeshOfFace
1465
1466     UVPtStructVec nodeDataVec( outerNodes.size() ); // outerNodes swapped with innerNodes
1467     for ( size_t i = 0; i < outerNodes.size(); ++i )
1468     {
1469       gp_XY uv = _helper.GetNodeUV( _face, outerNodes[i] );
1470       nodeDataVec[i].u         = uv.X();
1471       nodeDataVec[i].v         = uv.Y();
1472       nodeDataVec[i].node      = outerNodes[i];
1473       nodeDataVec[i].param     = points [i + L._firstPntInd].param;
1474       nodeDataVec[i].normParam = normPar[i];
1475       nodeDataVec[i].x         = normPar[i];
1476       nodeDataVec[i].y         = normPar[i];
1477     }
1478     nodeDataVec.front().param = L._wire->FirstU( L._edgeInd );
1479     nodeDataVec.back() .param = L._wire->LastU ( L._edgeInd );
1480
1481     _ProxyMeshOfFace::_EdgeSubMesh* edgeSM
1482       = getProxyMesh()->GetEdgeSubMesh( L._wire->EdgeID( L._edgeInd ));
1483     edgeSM->SetUVPtStructVec( nodeDataVec );
1484
1485   } // loop on _PolyLine's
1486
1487   return true;
1488 }
1489
1490 //================================================================================
1491 /*!
1492  * \brief Remove elements and nodes from a face
1493  */
1494 //================================================================================
1495
1496 void _ViscousBuilder2D::removeMeshFaces(const TopoDS_Shape& face)
1497 {
1498   // we don't use SMESH_subMesh::ComputeStateEngine() because of a listener
1499   // which clears EDGEs together with _face.
1500   SMESH_subMesh* sm = _mesh->GetSubMesh( face );
1501   if ( SMESHDS_SubMesh* smDS = sm->GetSubMeshDS() )
1502   {
1503     SMDS_ElemIteratorPtr eIt = smDS->GetElements();
1504     while ( eIt->more() ) getMeshDS()->RemoveFreeElement( eIt->next(), smDS );
1505     SMDS_NodeIteratorPtr nIt = smDS->GetNodes();
1506     while ( nIt->more() ) getMeshDS()->RemoveFreeNode( nIt->next(), smDS );
1507   }
1508   sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
1509 }
1510
1511 //================================================================================
1512 /*!
1513  * \brief Creates a _ProxyMeshOfFace and store it in a sub-mesh of FACE
1514  */
1515 //================================================================================
1516
1517 _ProxyMeshOfFace* _ViscousBuilder2D::getProxyMesh()
1518 {
1519   if ( _proxyMesh.get() )
1520     return (_ProxyMeshOfFace*) _proxyMesh.get();
1521
1522   _ProxyMeshOfFace* proxyMeshOfFace = new _ProxyMeshOfFace( *_mesh );
1523   _proxyMesh.reset( proxyMeshOfFace );
1524   new _ProxyMeshHolder( _face, _proxyMesh );
1525
1526   return proxyMeshOfFace;
1527 }
1528
1529 //================================================================================
1530 /*!
1531  * \brief Calculate height of layers for the given thickness. Height is measured
1532  *        from the outer boundary
1533  */
1534 //================================================================================
1535
1536 void _ViscousBuilder2D::calcLayersHeight(const double    totalThick,
1537                                          vector<double>& heights)
1538 {
1539   heights.resize( _hyp->GetNumberLayers() );
1540   double h0;
1541   if ( _fPowN - 1 <= numeric_limits<double>::min() )
1542     h0 = totalThick / _hyp->GetNumberLayers();
1543   else
1544     h0 = totalThick * ( _hyp->GetStretchFactor() - 1 )/( _fPowN - 1 );
1545
1546   double hSum = 0, hi = h0;
1547   for ( int i = 0; i < _hyp->GetNumberLayers(); ++i )
1548   {
1549     hSum += hi;
1550     heights[ i ] = hSum;
1551     hi *= _hyp->GetStretchFactor();
1552   }
1553 }
1554
1555 //================================================================================
1556 /*!
1557  * \brief Elongate this _LayerEdge
1558  */
1559 //================================================================================
1560
1561 void _LayerEdge::SetNewLength( const double length3D )
1562 {
1563   if ( _isBlocked ) return;
1564
1565   //_uvInPrev = _uvIn;
1566   _length2D = length3D * _len2dTo3dRatio;
1567   _uvIn     = _uvOut + _normal2D * _length2D;
1568 }
1569
1570 //================================================================================
1571 /*!
1572  * \brief Return true if _LayerEdge at a common VERTEX between EDGEs with
1573  *  and w/o layer is common to the both _PolyLine's. If this is true, nodes
1574  *  of this _LayerEdge are inflated along a _PolyLine w/o layer, else the nodes
1575  *  are inflated along _normal2D of _LayerEdge of EDGE with layer
1576  */
1577 //================================================================================
1578
1579 bool _PolyLine::IsCommonEdgeShared( const _PolyLine& other )
1580 {
1581   const double tol = 1e-30;
1582
1583   if ( & other == _leftLine )
1584     return _lEdges[0]._normal2D.IsEqual( _leftLine->_lEdges.back()._normal2D, tol );
1585
1586   if ( & other == _rightLine )
1587     return _lEdges.back()._normal2D.IsEqual( _rightLine->_lEdges[0]._normal2D, tol );
1588
1589   return false;
1590 }
1591
1592 //================================================================================
1593 /*!
1594  * \brief Constructor of SegmentTree
1595  */
1596 //================================================================================
1597
1598 _SegmentTree::_SegmentTree( const vector< _Segment >& segments ):
1599   SMESH_Quadtree()
1600 {
1601   _segments.resize( segments.size() );
1602   for ( size_t i = 0; i < segments.size(); ++i )
1603     _segments[i].Set( segments[i] );
1604
1605   compute();
1606 }
1607
1608 //================================================================================
1609 /*!
1610  * \brief Return the maximal bnd box
1611  */
1612 //================================================================================
1613
1614 _SegmentTree::box_type* _SegmentTree::buildRootBox()
1615 {
1616   _SegmentTree::box_type* box = new _SegmentTree::box_type;
1617   for ( size_t i = 0; i < _segments.size(); ++i )
1618   {
1619     box->Add( *_segments[i]._seg->_uv[0] );
1620     box->Add( *_segments[i]._seg->_uv[1] );
1621   }
1622   return box;
1623 }
1624
1625 //================================================================================
1626 /*!
1627  * \brief Redistrubute _segments among children
1628  */
1629 //================================================================================
1630
1631 void _SegmentTree::buildChildrenData()
1632 {
1633   for ( int i = 0; i < _segments.size(); ++i )
1634     for (int j = 0; j < nbChildren(); j++)
1635       if ( !myChildren[j]->getBox()->IsOut( *_segments[i]._seg->_uv[0],
1636                                             *_segments[i]._seg->_uv[1] ))
1637         ((_SegmentTree*)myChildren[j])->_segments.push_back( _segments[i]);
1638
1639   SMESHUtils::FreeVector( _segments ); // = _elements.clear() + free memory
1640
1641   for (int j = 0; j < nbChildren(); j++)
1642   {
1643     _SegmentTree* child = static_cast<_SegmentTree*>( myChildren[j]);
1644     child->myIsLeaf = ( child->_segments.size() <= maxNbSegInLeaf() );
1645   }
1646 }
1647
1648 //================================================================================
1649 /*!
1650  * \brief Return elements which can include the point
1651  */
1652 //================================================================================
1653
1654 void _SegmentTree::GetSegmentsNear( const _Segment&            seg,
1655                                     vector< const _Segment* >& found )
1656 {
1657   if ( getBox()->IsOut( *seg._uv[0], *seg._uv[1] ))
1658     return;
1659
1660   if ( isLeaf() )
1661   {
1662     for ( int i = 0; i < _segments.size(); ++i )
1663       if ( !_segments[i].IsOut( seg ))
1664         found.push_back( _segments[i]._seg );
1665   }
1666   else
1667   {
1668     for (int i = 0; i < nbChildren(); i++)
1669       ((_SegmentTree*) myChildren[i])->GetSegmentsNear( seg, found );
1670   }
1671 }
1672
1673
1674 //================================================================================
1675 /*!
1676  * \brief Return segments intersecting a ray
1677  */
1678 //================================================================================
1679
1680 void _SegmentTree::GetSegmentsNear( const gp_Ax2d&             ray,
1681                                     vector< const _Segment* >& found )
1682 {
1683   if ( getBox()->IsOut( ray ))
1684     return;
1685
1686   if ( isLeaf() )
1687   {
1688     for ( int i = 0; i < _segments.size(); ++i )
1689       if ( !_segments[i].IsOut( ray ))
1690         found.push_back( _segments[i]._seg );
1691   }
1692   else
1693   {
1694     for (int i = 0; i < nbChildren(); i++)
1695       ((_SegmentTree*) myChildren[i])->GetSegmentsNear( ray, found );
1696   }
1697 }
1698
1699 //================================================================================
1700 /*!
1701  * \brief Classify a _Segment
1702  */
1703 //================================================================================
1704
1705 bool _SegmentTree::_SegBox::IsOut( const _Segment& seg ) const
1706 {
1707   const double eps = std::numeric_limits<double>::min();
1708   for ( int iC = 0; iC < 2; ++iC )
1709   {
1710     if ( seg._uv[0]->Coord(iC+1) < _seg->_uv[ _iMin[iC]]->Coord(iC+1)+eps &&
1711          seg._uv[1]->Coord(iC+1) < _seg->_uv[ _iMin[iC]]->Coord(iC+1)+eps )
1712       return true;
1713     if ( seg._uv[0]->Coord(iC+1) > _seg->_uv[ 1-_iMin[iC]]->Coord(iC+1)-eps &&
1714          seg._uv[1]->Coord(iC+1) > _seg->_uv[ 1-_iMin[iC]]->Coord(iC+1)-eps )
1715       return true;
1716   }
1717   return false;
1718 }
1719
1720 //================================================================================
1721 /*!
1722  * \brief Classify a ray
1723  */
1724 //================================================================================
1725
1726 bool _SegmentTree::_SegBox::IsOut( const gp_Ax2d& ray ) const
1727 {
1728   double distBoxCenter2Ray =
1729     ray.Direction().XY() ^ ( ray.Location().XY() - 0.5 * (*_seg->_uv[0] + *_seg->_uv[1]));
1730
1731   double boxSectionDiam =
1732     Abs( ray.Direction().X() ) * ( _seg->_uv[1-_iMin[1]]->Y() - _seg->_uv[_iMin[1]]->Y() ) +
1733     Abs( ray.Direction().Y() ) * ( _seg->_uv[1-_iMin[0]]->X() - _seg->_uv[_iMin[0]]->X() );
1734
1735   return Abs( distBoxCenter2Ray ) > 0.5 * boxSectionDiam;
1736 }