Salome HOME
In SetParametersByDefaults(), make myMinSize and myDeflection greater
[modules/smesh.git] / src / StdMeshers / StdMeshers_Adaptive1D.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   : StdMeshers_Adaptive1D.cxx
23 //  Module : SMESH
24 //
25 #include "StdMeshers_Adaptive1D.hxx"
26
27 #include "SMESH_Gen.hxx"
28 #include "SMESH_Mesh.hxx"
29 #include "SMESH_MesherHelper.hxx"
30 #include "SMESH_Octree.hxx"
31 #include "SMESH_subMesh.hxx"
32 #include "SMESH_HypoFilter.hxx"
33
34 #include <Utils_SALOME_Exception.hxx>
35
36 #include <BRepAdaptor_Curve.hxx>
37 #include <BRepAdaptor_Surface.hxx>
38 #include <BRepMesh_IncrementalMesh.hxx>
39 #include <BRep_Tool.hxx>
40 #include <Bnd_B3d.hxx>
41 #include <GCPnts_AbscissaPoint.hxx>
42 #include <GeomAdaptor_Curve.hxx>
43 #include <Geom_Curve.hxx>
44 #include <Poly_Array1OfTriangle.hxx>
45 #include <Poly_Triangulation.hxx>
46 #include <TColgp_Array1OfPnt.hxx>
47 #include <TopExp.hxx>
48 #include <TopExp_Explorer.hxx>
49 #include <TopLoc_Location.hxx>
50 #include <TopTools_IndexedMapOfShape.hxx>
51 #include <TopoDS.hxx>
52 #include <TopoDS_Edge.hxx>
53 #include <TopoDS_Face.hxx>
54 #include <TopoDS_Vertex.hxx>
55 #include <gp_Lin.hxx>
56 #include <gp_Pnt.hxx>
57
58 #include <limits>
59 #include <vector>
60 #include <set>
61
62 using namespace std;
63
64 namespace // internal utils
65 {
66   //================================================================================
67   /*!
68    * \brief Bnd_B3d with access to its center and half-size
69    */
70   struct BBox : public Bnd_B3d
71   {
72     gp_XYZ Center() const { return gp_XYZ( myCenter[0], myCenter[1], myCenter[2] ); }
73     gp_XYZ HSize()  const { return gp_XYZ( myHSize[0],  myHSize[1],  myHSize[2]  ); }
74     double Size()   const { return 2 * myHSize[0]; }
75   };
76   //================================================================================
77   /*!
78    * \brief Working data of an EDGE
79    */
80   struct EdgeData
81   {
82     struct ProbePnt
83     {
84       gp_Pnt myP;
85       double myU;
86       double mySegSize;
87       ProbePnt( gp_Pnt p, double u, double sz=1e100 ): myP( p ), myU( u ), mySegSize( sz ) {}
88     };
89     BRepAdaptor_Curve myC3d;
90     double            myLength;
91     list< ProbePnt >  myPoints;
92     BBox              myBBox;
93
94     typedef list< ProbePnt >::iterator TPntIter;
95     void AddPoint( TPntIter where, double u )
96     {
97       TPntIter it = myPoints.insert( where, ProbePnt( myC3d.Value( u ), u ));
98       myBBox.Add( it->myP.XYZ() );
99     }
100     const ProbePnt& First() const { return myPoints.front(); }
101     const ProbePnt& Last()  const { return myPoints.back(); }
102     const TopoDS_Edge& Edge() const { return myC3d.Edge(); }
103     bool IsTooDistant( const BBox& faceBox, double maxSegSize ) const
104     {
105       gp_XYZ hsize = myBBox.HSize() + gp_XYZ( maxSegSize, maxSegSize, maxSegSize );
106       return faceBox.IsOut ( Bnd_B3d( myBBox.Center(), hsize ));
107     }
108   };
109   //================================================================================
110   /*!
111    * \brief Octree of local segment size
112    */
113   class SegSizeTree : public SMESH_Octree
114   {
115     double mySegSize; // segment size
116
117     // structure holding some common parameters of SegSizeTree
118     struct _CommonData : public SMESH_TreeLimit
119     {
120       double myGrading, myMinSize, myMaxSize;
121     };
122     _CommonData* getData() const { return (_CommonData*) myLimit; }
123
124     SegSizeTree(double size): SMESH_Octree(), mySegSize(size)
125     {
126       allocateChildren();
127     }
128     void allocateChildren()
129     {
130       myChildren = new SMESH_Octree::TBaseTree*[nbChildren()];
131       for ( int i = 0; i < nbChildren(); ++i )
132         myChildren[i] = NULL;
133     }
134     virtual box_type* buildRootBox() { return 0; }
135     virtual SegSizeTree* newChild() const { return 0; }
136     virtual void buildChildrenData() {}
137
138   public:
139
140     SegSizeTree( Bnd_B3d & bb, double grading, double mixSize, double maxSize);
141     void   SetSize( const gp_Pnt& p, double size );
142     double SetSize( const gp_Pnt& p1, const gp_Pnt& p2 );
143     double GetSize( const gp_Pnt& p ) const;
144     const BBox* GetBox() const { return (BBox*) getBox(); }
145     double GetMinSize() { return getData()->myMinSize; }
146   };
147   //================================================================================
148   /*!
149    * \brief Adaptive wire discertizator.
150    */
151   class AdaptiveAlgo : public StdMeshers_Regular_1D
152   {
153   public:
154     AdaptiveAlgo(int hypId, int studyId, SMESH_Gen* gen);
155     virtual bool Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape );
156     virtual bool Evaluate(SMESH_Mesh &         theMesh,
157                           const TopoDS_Shape & theShape,
158                           MapShapeNbElems&     theResMap);
159     void SetHypothesis( const StdMeshers_Adaptive1D* hyp );
160   private:
161
162     bool makeSegments();
163
164     const StdMeshers_Adaptive1D* myHyp;
165     SMESH_Mesh*                  myMesh;
166     vector< EdgeData >           myEdges;
167     SegSizeTree*                 mySizeTree;
168   };
169
170   //================================================================================
171   /*!
172    * \brief Data of triangle used to locate it in an octree and to find distance
173    *        to a point
174    */
175   struct Triangle
176   {
177     Bnd_B3d myBox;
178     bool    myIsChecked; // to mark treated trias instead of using std::set
179     // data for DistToProjection()
180     gp_XYZ myN0, myEdge1, myEdge2, myNorm, myPVec;
181     double myInvDet, myMaxSize2;
182
183     void Init( const gp_Pnt& n1, const gp_Pnt& n2, const gp_Pnt& n3 ); 
184     bool DistToProjection( const gp_Pnt& p, double& dist ) const;
185   };
186   //================================================================================
187   /*!
188    * \brief Element data held by ElementBndBoxTree + algorithm computing a distance
189    *        from a point to element
190    */
191   class ElementBndBoxTree;
192   struct ElemTreeData : public SMESH_TreeLimit
193   {
194     vector< int >                myWorkIDs[8];// to speed up filling ElementBndBoxTree::_elementIDs
195     virtual const Bnd_B3d* GetBox(int elemID) const = 0;
196   };
197   struct TriaTreeData : public ElemTreeData
198   {
199     vector< Triangle >           myTrias;
200     double                       myFaceTol;
201     double                       myTriasDeflection;
202     BBox                         myBBox;
203     BRepAdaptor_Surface          mySurface;
204     ElementBndBoxTree*           myTree;
205     const Poly_Array1OfTriangle* myPolyTrias;
206     const TColgp_Array1OfPnt*    myNodes;
207     bool                         myOwnNodes;
208
209     typedef vector<int> IntVec;
210     IntVec                       myFoundTriaIDs;
211
212     TriaTreeData( const TopoDS_Face& face, ElementBndBoxTree* triaTree );
213     ~TriaTreeData() { if ( myOwnNodes ) delete myNodes; myNodes = NULL; }
214     virtual const Bnd_B3d* GetBox(int elemID) const { return &myTrias[elemID].myBox; }
215     void PrepareToTriaSearch();
216     void SetSizeByTrias( SegSizeTree& sizeTree, double deflection ) const;
217     double GetMinDistInSphere(const gp_Pnt& p,
218                               const double  radius,
219                               const bool    projectedOnly,
220                               const gp_Pnt* avoidP=0) const;
221   };
222   //================================================================================
223   /*!
224    * \brief Octree of triangles or segments
225    */
226   class ElementBndBoxTree : public SMESH_Octree
227   {
228   public:
229     ElementBndBoxTree(const TopoDS_Face& face);
230     void GetElementsInSphere( const gp_XYZ& center,
231                               const double  radius, vector<int> & foundElemIDs) const;
232     void FillIn();
233     ElemTreeData* GetElemData() const { return (ElemTreeData*) myLimit; }
234     TriaTreeData* GetTriaData() const { return (TriaTreeData*) myLimit; }
235
236   protected:
237     ElementBndBoxTree() {}
238     SMESH_Octree* newChild() const { return new ElementBndBoxTree; }
239     void          buildChildrenData();
240     Bnd_B3d*      buildRootBox();
241   private:
242     vector< int > _elementIDs;
243   };
244   //================================================================================
245   /*!
246    * \brief BRepMesh_IncrementalMesh with access to its protected Bnd_Box
247    */
248   struct IncrementalMesh : public BRepMesh_IncrementalMesh
249   {
250     IncrementalMesh(const TopoDS_Shape& shape,
251                     const Standard_Real deflection,
252                     const bool          relative):
253       BRepMesh_IncrementalMesh( shape, deflection, relative )
254     {
255     }
256     Bnd_B3d GetBox() const
257     {
258       Standard_Real TXmin, TYmin, TZmin, TXmax, TYmax, TZmax;
259       myBox.Get(TXmin, TYmin, TZmin, TXmax, TYmax, TZmax);
260       Bnd_B3d bb;
261       bb.Add( gp_XYZ( TXmin, TYmin, TZmin ));
262       bb.Add( gp_XYZ( TXmax, TYmax, TZmax ));
263       return bb;
264     }
265   };
266
267   //================================================================================
268   /*!
269    * \brief Initialize TriaTreeData
270    */
271   //================================================================================
272
273   TriaTreeData::TriaTreeData( const TopoDS_Face& face, ElementBndBoxTree* triaTree )
274     : myTriasDeflection(0), mySurface( face ),
275       myTree(NULL), myPolyTrias(NULL), myNodes(NULL), myOwnNodes(false)
276   {
277     TopLoc_Location loc;
278     Handle(Poly_Triangulation) tr = BRep_Tool::Triangulation( face, loc );
279     if ( !tr.IsNull() )
280     {
281       myFaceTol         = SMESH_MesherHelper::MaxTolerance( face );
282       myTree            = triaTree;
283       myNodes           = & tr->Nodes();
284       myPolyTrias       = & tr->Triangles();
285       myTriasDeflection = tr->Deflection();
286       if ( !loc.IsIdentity() ) // transform nodes if necessary
287       {
288         TColgp_Array1OfPnt* trsfNodes = new TColgp_Array1OfPnt( myNodes->Lower(), myNodes->Upper() );
289         trsfNodes->Assign( *myNodes );
290         myNodes    = trsfNodes;
291         myOwnNodes = true;
292         const gp_Trsf& trsf = loc;
293         for ( int i = trsfNodes->Lower(); i <= trsfNodes->Upper(); ++i )
294           trsfNodes->ChangeValue(i).Transform( trsf );
295       }
296       for ( int i = myNodes->Lower(); i <= myNodes->Upper(); ++i )
297         myBBox.Add( myNodes->Value(i).XYZ() );
298
299     }
300   }
301   void TriaTreeData::PrepareToTriaSearch()
302   {
303     if ( !myTrias.empty() ) return; // already done
304     if ( !myPolyTrias ) return;
305
306     myTrias.resize( myPolyTrias->Length() );
307     Standard_Integer n1,n2,n3;
308     for ( int i = 1; i <= myPolyTrias->Upper(); ++i )
309     {
310       myPolyTrias->Value( i ).Get( n1,n2,n3 );
311       myTrias[ i-1 ].Init( myNodes->Value( n1 ),
312                            myNodes->Value( n2 ),
313                            myNodes->Value( n3 ));
314     }
315     myTree->FillIn();
316
317     // TODO: mark triangles with nodes on VERTEXes to
318     // less frequently compare with avoidPnt in GetMinDistInSphere()
319     //
320     // Handle(Poly_PolygonOnTriangulation) polygon =
321     //   BRep_Tool::PolygonOnTriangulation( edge, tr, loc );
322     // if ( polygon.IsNull() || !pologon.HasParameters() )
323     //   continue;
324     // Handle(TColStd_Array1OfInteger) nodeIDs = polygon->Nodes();
325   }
326
327   //================================================================================
328   /*!
329    * \brief Set size of segments by size of triangles
330    */
331   //================================================================================
332
333   void TriaTreeData::SetSizeByTrias( SegSizeTree& sizeTree, double hypDeflection ) const
334   {
335     if ( mySurface.GetType() == GeomAbs_Plane ||
336          myTriasDeflection   <= 1e-100 )
337       return;
338     const double factor = hypDeflection / myTriasDeflection;
339
340     bool isConstSize;
341     switch( mySurface.GetType() ) {
342     case GeomAbs_Cylinder:
343     case GeomAbs_Sphere:
344     case GeomAbs_Torus:
345       isConstSize = true; break;
346     default:
347       isConstSize = false;
348     }
349
350     typedef std::pair<int,int> TLink;
351     TLink link;
352     map< TLink, double >           lenOfDoneLink;
353     map< TLink, double >::iterator link2len;
354
355     Standard_Integer n[4];
356     gp_Pnt p[4];
357     double a[3];
358     bool   isDone[3];
359     double size = -1., maxLinkLen;
360     int    jLongest;
361
362     //int nbLinks = 0;
363     for ( int i = 1; i <= myPolyTrias->Upper(); ++i )
364     {
365       // get corners of a triangle
366       myPolyTrias->Value( i ).Get( n[0],n[1],n[2] );
367       n[3] = n[0];
368       p[0] = myNodes->Value( n[0] );
369       p[1] = myNodes->Value( n[1] );
370       p[2] = myNodes->Value( n[2] );
371       p[3] = p[0];
372       // get length of links and find the longest one
373       maxLinkLen = 0;
374       for ( int j = 0; j < 3; ++j )
375       {
376         if ( n[j] < n[j+1] )
377           link = TLink( n[j], n[j+1] );
378         else
379           link = TLink( n[j+1], n[j] );
380         link2len  = lenOfDoneLink.insert( make_pair( link, -1. )).first;
381         isDone[j] = !((*link2len).second < 0 );
382         a[j]      = isDone[j] ? (*link2len).second : (*link2len).second = p[j].Distance( p[j+1] );
383         if ( isDone[j] )
384           lenOfDoneLink.erase( link2len );
385         if ( a[j] > maxLinkLen )
386         {
387           maxLinkLen = a[j];
388           jLongest   = j;
389         }
390       }
391       // compute minimal altitude of a triangle
392       if ( !isConstSize || size < 0. )
393       {
394         double s    = 0.5 * ( a[0] + a[1] + a[2] );
395         double area = sqrt( s * (s - a[0]) * (s - a[1]) * (s - a[2]));
396         size        = 2 * area / maxLinkLen; // minimal altitude
397       }
398       // set size to the size tree
399       if ( !isDone[ jLongest ] || !isConstSize )
400       {
401         //++nbLinks;
402         int nb = Max( 1, int( maxLinkLen / size / 2 ));
403         for ( int k = 0; k <= nb; ++k )
404         {
405           double r = double( k ) / nb;
406           sizeTree.SetSize( r * p[ jLongest ].XYZ() + ( 1-r ) * p[ jLongest+1 ].XYZ(),
407                             size * factor );
408         }
409       }
410       //cout << "SetSizeByTrias, i="<< i << " " << sz * factor << endl;
411     }
412     // cout << "SetSizeByTrias, nn tria="<< myPolyTrias->Upper()
413     //      << " nb links" << nbLinks << " isConstSize="<<isConstSize
414     //      << " " << size * factor << endl;
415   }
416   //================================================================================
417   /*!
418    * \brief Return minimal distance from a given point to a trinangle but not more
419    *        distant than a given radius. Triangles with a node at avoidPnt are ignored.
420    *        If projectedOnly, 
421    */
422   //================================================================================
423
424   double TriaTreeData::GetMinDistInSphere(const gp_Pnt& p,
425                                           const double  radius,
426                                           const bool    projectedOnly,
427                                           const gp_Pnt* avoidPnt) const
428   {
429     double minDist2 = 1e100;
430     const double tol2 = myFaceTol * myFaceTol;
431
432     TriaTreeData* me = const_cast<TriaTreeData*>( this );
433     me->myFoundTriaIDs.clear();
434     myTree->GetElementsInSphere( p.XYZ(), radius, me->myFoundTriaIDs );
435
436     Standard_Integer n[ 3 ];
437     for ( size_t i = 0; i < myFoundTriaIDs.size(); ++i )
438     {
439       Triangle& t = me->myTrias[ myFoundTriaIDs[i] ];
440       if ( t.myIsChecked )
441         continue;
442       t.myIsChecked = true;
443
444       double d, minD2 = minDist2;
445       bool avoidTria = false;
446       myPolyTrias->Value( myFoundTriaIDs[i]+1 ).Get( n[0],n[1],n[2] );
447       for ( int i = 0; i < 3; ++i )
448       {
449         const gp_Pnt& pn = myNodes->Value(n[i]);
450         if ( avoidTria = ( avoidPnt && pn.SquareDistance(*avoidPnt) <= tol2 ))
451           break;
452         if ( !projectedOnly )
453           minD2 = Min( minD2, pn.SquareDistance( p ));
454       }
455       if ( !avoidTria )
456       {
457         if ( minD2 < t.myMaxSize2 && t.DistToProjection( p, d ))
458           minD2 = Min( minD2, d*d );
459         minDist2 = Min( minDist2, minD2 );
460       }
461     }
462
463     for ( size_t i = 0; i < myFoundTriaIDs.size(); ++i )
464       me->myTrias[ myFoundTriaIDs[i] ].myIsChecked = false;
465
466     return sqrt( minDist2 );
467   }
468   //================================================================================
469   /*!
470    * \brief Prepare Triangle data
471    */
472   //================================================================================
473
474   void Triangle::Init( const gp_Pnt& p1, const gp_Pnt& p2, const gp_Pnt& p3 )
475   {
476     myBox.Add( p1 );
477     myBox.Add( p2 );
478     myBox.Add( p3 );
479     myN0 = p1.XYZ();
480     myEdge1 = p2.XYZ() - myN0;
481     myEdge2 = p3.XYZ() - myN0;
482     myNorm = myEdge1 ^ myEdge2;
483     double normSize = myNorm.Modulus();
484     if ( normSize > std::numeric_limits<double>::min() )
485     {
486       myNorm /= normSize;
487       myPVec = myNorm ^ myEdge2;
488       myInvDet = 1. / ( myEdge1 * myPVec );
489     }
490     else
491     {
492       myInvDet = 0.;
493     }
494     myMaxSize2 = Max( p2.SquareDistance( p3 ),
495                       Max( myEdge2.SquareModulus(), myEdge1.SquareModulus() ));
496   }
497   //================================================================================
498   /*!
499    * \brief Compute distance from a point to the triangle. Return false if the point
500    *        is not projected inside the triangle
501    */
502   //================================================================================
503
504   bool Triangle::DistToProjection( const gp_Pnt& p, double& dist ) const
505   {
506     if ( myInvDet == 0 )
507       return false; // degenerated triangle
508
509     /* distance from n0 to the point */
510     gp_XYZ tvec = p.XYZ() - myN0;
511
512     /* calculate U parameter and test bounds */
513     double u = ( tvec * myPVec ) * myInvDet;
514     if (u < 0.0 || u > 1.0)
515       return false; // projected outside the triangle
516
517     /* calculate V parameter and test bounds */
518     gp_XYZ qvec = tvec ^ myEdge1;
519     double v = ( myNorm * qvec) * myInvDet;
520     if ( v < 0.0 || u + v > 1.0 )
521       return false; // projected outside the triangle
522
523     dist = ( myEdge2 * qvec ) * myInvDet;
524     return true;
525   }
526
527   //================================================================================
528   /*!
529    * \brief Consturct ElementBndBoxTree of Poly_Triangulation of a FACE
530    */
531   //================================================================================
532
533   ElementBndBoxTree::ElementBndBoxTree(const TopoDS_Face& face)
534     :SMESH_Octree()
535   {
536     TriaTreeData* data = new TriaTreeData( face, this );
537     data->myMaxLevel = 5;
538     myLimit = data;
539   }
540   //================================================================================
541   /*!
542    * \brief Fill all levels of octree of Poly_Triangulation of a FACE
543    */
544   //================================================================================
545
546   void ElementBndBoxTree::FillIn()
547   {
548     if ( myChildren ) return;
549     TriaTreeData* data = GetTriaData();
550     if ( !data->myTrias.empty() )
551     {
552       for ( size_t i = 0; i < data->myTrias.size(); ++i )
553         _elementIDs.push_back( i );
554
555       compute();
556     }
557   }
558   //================================================================================
559   /*!
560    * \brief Return the maximal box
561    */
562   //================================================================================
563
564   Bnd_B3d* ElementBndBoxTree::buildRootBox()
565   {
566     TriaTreeData* data = GetTriaData();
567     Bnd_B3d*       box = new Bnd_B3d( data->myBBox );
568     return box;
569   }
570   //================================================================================
571   /*!
572    * \brief Redistrubute element boxes among children
573    */
574   //================================================================================
575
576   void ElementBndBoxTree::buildChildrenData()
577   {
578     ElemTreeData* data = GetElemData();
579     for ( int i = 0; i < _elementIDs.size(); ++i )
580     {
581       const Bnd_B3d* elemBox = data->GetBox( _elementIDs[i] );
582       for (int j = 0; j < 8; j++)
583         if ( !elemBox->IsOut( *myChildren[ j ]->getBox() ))
584           data->myWorkIDs[ j ].push_back( _elementIDs[i] );
585     }
586     SMESHUtils::FreeVector( _elementIDs ); // = _elements.clear() + free memory
587
588     const int theMaxNbElemsInLeaf = 7;
589
590     for (int j = 0; j < 8; j++)
591     {
592       ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j] );
593       child->_elementIDs = data->myWorkIDs[ j ];
594       if ( child->_elementIDs.size() <= theMaxNbElemsInLeaf )
595         child->myIsLeaf = true;
596       data->myWorkIDs[ j ].clear();
597     }
598   }
599   //================================================================================
600   /*!
601    * \brief Return elements from leaves intersecting the sphere
602    */
603   //================================================================================
604
605   void ElementBndBoxTree::GetElementsInSphere( const gp_XYZ& center,
606                                                const double  radius,
607                                                vector<int> & foundElemIDs) const
608   {
609     if ( const box_type* box = getBox() )
610     {
611       if ( box->IsOut( center, radius ))
612         return;
613
614       if ( isLeaf() )
615       {
616         ElemTreeData* data = GetElemData();
617         for ( int i = 0; i < _elementIDs.size(); ++i )
618           if ( !data->GetBox( _elementIDs[i] )->IsOut( center, radius ))
619             foundElemIDs.push_back( _elementIDs[i] );
620       }
621       else
622       {
623         for (int i = 0; i < 8; i++)
624           ((ElementBndBoxTree*) myChildren[i])->GetElementsInSphere( center, radius, foundElemIDs );
625       }
626     }
627   }
628
629   //================================================================================
630   /*!
631    * \brief Constructor of SegSizeTree
632    *  \param [in,out] bb - bounding box enclosing all EDGEs to discretize 
633    *  \param [in] grading - factor to get max size of the neighbour segment by 
634    *         size of a current one.
635    */
636   //================================================================================
637
638   SegSizeTree::SegSizeTree( Bnd_B3d & bb, double grading, double minSize, double maxSize )
639     : SMESH_Octree( new _CommonData() )
640   {
641     // make cube myBox from the box bb
642     gp_XYZ pmin = bb.CornerMin(), pmax = bb.CornerMax();
643     double maxBoxHSize = 0.5 * Max( pmax.X()-pmin.X(), Max( pmax.Y()-pmin.Y(), pmax.Z()-pmin.Z() ));
644     maxBoxHSize *= 1.01;
645     bb.SetHSize( gp_XYZ( maxBoxHSize, maxBoxHSize, maxBoxHSize ));
646     myBox = new box_type( bb );
647
648     mySegSize = Min( 2 * maxBoxHSize, maxSize );
649
650     getData()->myGrading = grading;
651     getData()->myMinSize = Max( minSize, 2*maxBoxHSize / 1.e6 );
652     getData()->myMaxSize = maxSize;
653     allocateChildren();
654   }
655
656   //================================================================================
657   /*!
658    * \brief Set segment size at a given point
659    */
660   //================================================================================
661
662   void SegSizeTree::SetSize( const gp_Pnt& p, double size )
663   {
664     // check if the point is out of the largest cube
665     SegSizeTree* root = this;
666     while ( root->myFather )
667       root = (SegSizeTree*) root->myFather;
668     if ( root->getBox()->IsOut( p.XYZ() ))
669       return;
670
671     // keep size whthin the valid range
672     size = Max( size, getData()->myMinSize );
673     //size = Min( size, getData()->myMaxSize );
674
675     // find an existing leaf at the point
676     SegSizeTree* leaf = (SegSizeTree*) root;
677     int iChild;
678     while ( true )
679     {
680       iChild = SMESH_Octree::getChildIndex( p.X(), p.Y(), p.Z(), leaf->GetBox()->Center() );
681       if ( leaf->myChildren[ iChild ] )
682         leaf = (SegSizeTree*) leaf->myChildren[ iChild ];
683       else
684         break;
685     }
686     // don't increase the current size
687     if ( leaf->mySegSize <= 1.1 * size )
688       return;
689
690     // split the found leaf until its box size is less than the given size
691     const double rootSize = root->GetBox()->Size();
692     while ( leaf->GetBox()->Size() > size )
693     {
694       const BBox* bb = leaf->GetBox();
695       iChild   = SMESH_Octree::getChildIndex( p.X(), p.Y(), p.Z(), bb->Center() );
696       SegSizeTree* newLeaf = new SegSizeTree( bb->Size() / 2 );
697       leaf->myChildren[iChild] = newLeaf;
698       newLeaf->myFather = leaf;
699       newLeaf->myLimit  = leaf->myLimit;
700       newLeaf->myLevel  = leaf->myLevel + 1;
701       newLeaf->myBox    = leaf->newChildBox( iChild );
702       newLeaf->myBox->Enlarge( rootSize * 1e-10 );
703       //newLeaf->myIsLeaf = ( newLeaf->mySegSize <= size );
704       leaf = newLeaf;
705     }
706     leaf->mySegSize = size;
707
708     // propagate increased size out from the leaf
709     double boxSize = leaf->GetBox()->Size();
710     double sizeInc = size + boxSize * getData()->myGrading;
711     for ( int iDir = 1; iDir <= 3; ++iDir )
712     {
713       gp_Pnt outPnt = p;
714       outPnt.SetCoord( iDir, p.Coord( iDir ) + boxSize );
715       SetSize( outPnt, sizeInc );
716       outPnt.SetCoord( iDir, p.Coord( iDir ) - boxSize );
717       SetSize( outPnt, sizeInc );
718     }
719   }
720   //================================================================================
721   /*!
722    * \brief Set size of a segment given by two end points
723    */
724   //================================================================================
725
726   double SegSizeTree::SetSize( const gp_Pnt& p1, const gp_Pnt& p2 )
727   {
728     const double size = p1.Distance( p2 );
729     gp_XYZ p = 0.5 * ( p1.XYZ() + p2.XYZ() );
730     SetSize( p, size );
731     SetSize( p1, size );
732     SetSize( p2, size );
733     //cout << "SetSize " << p1.Distance( p2 ) << " at " << p.X() <<", "<< p.Y()<<", "<<p.Z()<< endl;
734     return GetSize( p );
735   }
736
737   //================================================================================
738   /*!
739    * \brief Return segment size at a point
740    */
741   //================================================================================
742
743   double SegSizeTree::GetSize( const gp_Pnt& p ) const
744   {
745     const SegSizeTree* leaf = this;
746     while ( true )
747     {
748       int iChild = SMESH_Octree::getChildIndex( p.X(), p.Y(), p.Z(), leaf->GetBox()->Center() );
749       if ( leaf->myChildren[ iChild ] )
750         leaf = (SegSizeTree*) leaf->myChildren[ iChild ];
751       else
752         return leaf->mySegSize;
753     }
754     return mySegSize; // just to return anything
755   }
756
757   //================================================================================
758   /*!
759    * \brief Evaluate curve deflection between two points
760    * \param theCurve - the curve
761    * \param theU1 - the parameter of the first point
762    * \param theU2 - the parameter of the second point
763    * \retval double - square deflection value
764    */
765   //================================================================================
766
767   double deflection2(const BRepAdaptor_Curve & theCurve,
768                      double                    theU1,
769                      double                    theU2)
770   {
771     // line between theU1 and theU2
772     gp_Pnt p1 = theCurve.Value( theU1 ), p2 = theCurve.Value( theU2 );
773     gp_Lin segment( p1, gp_Vec( p1, p2 ));
774
775     // evaluate square distance of theCurve from the segment
776     Standard_Real dist2 = 0;
777     const int nbPnt = 5;
778     const double step = ( theU2 - theU1 ) / nbPnt;
779     while (( theU1 += step ) < theU2 )
780       dist2 = Max( dist2, segment.SquareDistance( theCurve.Value( theU1 )));
781
782     return dist2;
783   }
784
785 } // namespace
786
787 //=======================================================================
788 //function : StdMeshers_Adaptive1D
789 //purpose  : Constructor
790 StdMeshers_Adaptive1D::StdMeshers_Adaptive1D(int         hypId,
791                                              int         studyId,
792                                              SMESH_Gen * gen)
793   :SMESH_Hypothesis(hypId, studyId, gen)
794 {
795   myMinSize       = 1e-10;
796   myMaxSize       = 1e+10;
797   myDeflection    = 1e-2;
798   myAlgo          = NULL;
799   _name           = "Adaptive1D";
800   _param_algo_dim = 1; // is used by SMESH_Regular_1D
801 }
802 //=======================================================================
803 //function : ~StdMeshers_Adaptive1D
804 //purpose  : Destructor
805 StdMeshers_Adaptive1D::~StdMeshers_Adaptive1D()
806 {
807   delete myAlgo; myAlgo = NULL;
808 }
809 //=======================================================================
810 //function : SetDeflection
811 //purpose  : 
812 void StdMeshers_Adaptive1D::SetDeflection(double value)
813   throw(SALOME_Exception)
814 {
815   if (value <= std::numeric_limits<double>::min() )
816     throw SALOME_Exception("Deflection must be greater that zero");
817   if (myDeflection != value)
818   {
819     myDeflection = value;
820     NotifySubMeshesHypothesisModification();
821   }
822 }
823 //=======================================================================
824 //function : SetMinSize
825 //purpose  : Sets minimal allowed segment length
826 void StdMeshers_Adaptive1D::SetMinSize(double minSize)
827   throw(SALOME_Exception)
828 {
829   if (minSize <= std::numeric_limits<double>::min() )
830     throw SALOME_Exception("Min size must be greater that zero");
831
832   if (myMinSize != minSize )
833   {
834     myMinSize = minSize;
835     NotifySubMeshesHypothesisModification();
836   }
837 }
838 //=======================================================================
839 //function : SetMaxSize
840 //purpose  : Sets maximal allowed segment length
841 void StdMeshers_Adaptive1D::SetMaxSize(double maxSize)
842   throw(SALOME_Exception)
843 {
844   if (maxSize <= std::numeric_limits<double>::min() )
845     throw SALOME_Exception("Max size must be greater that zero");
846
847   if (myMaxSize != maxSize )
848   {
849     myMaxSize = maxSize;
850     NotifySubMeshesHypothesisModification();
851   }
852 }
853 //=======================================================================
854 //function : SaveTo
855 //purpose  : Persistence
856 ostream & StdMeshers_Adaptive1D::SaveTo(ostream & save)
857 {
858   save << myMinSize << " " << myMaxSize << " " << myDeflection;
859   save << " " << -1 << " " << -1; // preview addition of parameters
860   return save;
861 }
862 //=======================================================================
863 //function : LoadFrom
864 //purpose  : Persistence
865 istream & StdMeshers_Adaptive1D::LoadFrom(istream & load)
866 {
867   int dummyParam;
868   bool isOK = (load >> myMinSize >> myMaxSize >> myDeflection >> dummyParam >> dummyParam);
869   if (!isOK)
870     load.clear(ios::badbit | load.rdstate());
871   return load;
872 }
873 //=======================================================================
874 //function : SetParametersByMesh
875 //purpose  : Initialize parameters by the mesh built on the geometry
876 //param theMesh - the built mesh
877 //param theShape - the geometry of interest
878 //retval bool - true if parameter values have been successfully defined
879 bool StdMeshers_Adaptive1D::SetParametersByMesh(const SMESH_Mesh*   theMesh,
880                                                 const TopoDS_Shape& theShape)
881 {
882   if ( !theMesh || theShape.IsNull() )
883     return false;
884
885   int nbEdges = 0;
886   TopTools_IndexedMapOfShape edgeMap;
887   TopExp::MapShapes( theShape, TopAbs_EDGE, edgeMap );
888
889   SMESH_MesherHelper helper( (SMESH_Mesh&) *theMesh );
890   double minSz2 = 1e100, maxSz2 = 0, sz2, maxDefl2 = 0;
891   for ( int iE = 1; iE <= edgeMap.Extent(); ++iE )
892   {
893     const TopoDS_Edge& edge = TopoDS::Edge( edgeMap( iE ));
894     SMESHDS_SubMesh* smDS = theMesh->GetMeshDS()->MeshElements( edge );
895     if ( !smDS ) continue;
896     ++nbEdges;
897
898     helper.SetSubShape( edge );
899     BRepAdaptor_Curve curve( edge );
900
901     SMDS_ElemIteratorPtr segIt = smDS->GetElements();
902     while ( segIt->more() )
903     {
904       const SMDS_MeshElement* seg = segIt->next();
905       const SMDS_MeshNode* n1 = seg->GetNode(0);
906       const SMDS_MeshNode* n2 = seg->GetNode(1);
907       sz2 = SMESH_TNodeXYZ( n1 ).SquareDistance( n2 );
908       minSz2 = Min( minSz2, sz2 );
909       maxSz2 = Max( maxSz2, sz2 );
910       if ( curve.GetType() != GeomAbs_Line )
911       {
912         double u1 = helper.GetNodeU( edge, n1, n2 );
913         double u2 = helper.GetNodeU( edge, n2, n1 );
914         maxDefl2 = Max( maxDefl2, deflection2( curve, u1, u2 ));
915       }
916     }
917   }
918   if ( nbEdges )
919   {
920     myMinSize = sqrt( minSz2 );
921     myMaxSize = sqrt( maxSz2 );
922     if ( maxDefl2 > 0 )
923       myDeflection = maxDefl2;
924   }
925   return nbEdges;
926 }
927
928 //=======================================================================
929 //function : SetParametersByDefaults
930 //purpose  : Initialize my parameter values by default parameters.
931 //retval   : bool - true if parameter values have been successfully defined
932 bool StdMeshers_Adaptive1D::SetParametersByDefaults(const TDefaults&  dflts,
933                                                     const SMESH_Mesh* /*theMesh*/)
934 {
935   myMinSize = dflts._elemLength / 10;
936   myMaxSize = dflts._elemLength * 2;
937   myDeflection = myMinSize / 7;
938   return true;
939 }
940
941 //=======================================================================
942 //function : GetAlgo
943 //purpose  : Returns an algorithm that works using this hypothesis
944 //=======================================================================
945
946 SMESH_Algo* StdMeshers_Adaptive1D::GetAlgo() const
947 {
948   if ( !myAlgo )
949   {
950     AdaptiveAlgo* newAlgo = 
951       new AdaptiveAlgo( _gen->GetANewId(), _studyId, _gen );
952     newAlgo->SetHypothesis( this );
953
954     ((StdMeshers_Adaptive1D*) this)->myAlgo = newAlgo;
955   }
956   return myAlgo;
957 }
958
959 //================================================================================
960 /*!
961  * \brief Constructor
962  */
963 //================================================================================
964
965 AdaptiveAlgo::AdaptiveAlgo(int        hypId,
966                            int        studyId,
967                            SMESH_Gen* gen)
968   : StdMeshers_Regular_1D( hypId, studyId, gen ),
969     myHyp(NULL)
970 {
971   _name = "AdaptiveAlgo_1D";
972 }
973
974 //================================================================================
975 /*!
976  * \brief Sets the hypothesis
977  */
978 //================================================================================
979
980 void AdaptiveAlgo::SetHypothesis( const StdMeshers_Adaptive1D* hyp )
981 {
982   myHyp = hyp;
983 }
984
985 //================================================================================
986 /*!
987  * \brief Creates segments on all given EDGEs
988  */
989 //================================================================================
990
991 bool AdaptiveAlgo::Compute(SMESH_Mesh &         theMesh,
992                            const TopoDS_Shape & theShape)
993 {
994   //*theProgress = 0.01;
995
996   if ( myHyp->GetMinSize() > myHyp->GetMaxSize() )
997     return error( "Bad parameters: min size > max size" );
998
999   myMesh = &theMesh;
1000   SMESH_MesherHelper helper( theMesh );
1001   const double grading = 0.7;
1002
1003   TopTools_IndexedMapOfShape edgeMap, faceMap;
1004   TopExp::MapShapes( theShape,                 TopAbs_EDGE, edgeMap );
1005   TopExp::MapShapes( theMesh.GetShapeToMesh(), TopAbs_FACE, faceMap );
1006
1007   // Triangulate the shape with the given deflection ?????????
1008   Bnd_B3d box;
1009   {
1010     IncrementalMesh im( theMesh.GetShapeToMesh(), myHyp->GetDeflection(), /*Relatif=*/false);
1011     box = im.GetBox();
1012   }
1013   //*theProgress = 0.3;
1014
1015   // holder of segment size at each point
1016   SegSizeTree sizeTree( box, grading, myHyp->GetMinSize(), myHyp->GetMaxSize() );
1017   mySizeTree = & sizeTree;
1018
1019   // minimal segment size that sizeTree can store with reasonable tree height
1020   const double minSize = Max( myHyp->GetMinSize(), 1.1 * sizeTree.GetMinSize() );
1021
1022
1023   // fill myEdges - working data of EDGEs
1024   {
1025     // sort EDGEs by length
1026     multimap< double, TopoDS_Edge > edgeOfLength;
1027     for ( int iE = 1; iE <= edgeMap.Extent(); ++iE )
1028     {
1029       const TopoDS_Edge & edge = TopoDS::Edge( edgeMap( iE ));
1030       if ( !SMESH_Algo::isDegenerated( edge) )
1031         edgeOfLength.insert( make_pair( EdgeLength( edge ), edge ));
1032     }
1033     myEdges.clear();
1034     myEdges.resize( edgeOfLength.size() );
1035     multimap< double, TopoDS_Edge >::const_iterator len2edge = edgeOfLength.begin();
1036     for ( int iE = 0; len2edge != edgeOfLength.end(); ++len2edge, ++iE )
1037     {
1038       const TopoDS_Edge & edge = len2edge->second;
1039       EdgeData& eData = myEdges[ iE ];
1040       eData.myC3d.Initialize( edge );
1041       eData.myLength  = EdgeLength( edge );
1042       eData.AddPoint( eData.myPoints.end(), eData.myC3d.FirstParameter() );
1043       eData.AddPoint( eData.myPoints.end(), eData.myC3d.LastParameter() );
1044     }
1045   }
1046   if ( _computeCanceled ) return false;
1047
1048   // Take into account size of already existing segments
1049   SMDS_EdgeIteratorPtr segIterator = theMesh.GetMeshDS()->edgesIterator();
1050   while ( segIterator->more() )
1051   {
1052     const SMDS_MeshElement* seg = segIterator->next();
1053     sizeTree.SetSize( SMESH_TNodeXYZ( seg->GetNode( 0 )), SMESH_TNodeXYZ( seg->GetNode( 1 )));
1054   }
1055   if ( _computeCanceled ) return false;
1056
1057   // Set size of segments according to the deflection
1058
1059   StdMeshers_Regular_1D::_hypType = DEFLECTION;
1060   StdMeshers_Regular_1D::_value[ DEFLECTION_IND ] = myHyp->GetDeflection();
1061
1062   list< double > params;
1063   for ( int iE = 0; iE < myEdges.size(); ++iE )
1064   {
1065     EdgeData& eData = myEdges[ iE ];
1066     //cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() ) << endl;
1067
1068     double f = eData.First().myU, l = eData.Last().myU;
1069     if ( !computeInternalParameters( theMesh, eData.myC3d, eData.myLength, f,l, params, false, false ))
1070       continue;
1071     if ( params.size() <= 1 && helper.IsClosedEdge( eData.Edge() ) ) // 2 segments on a circle
1072     {
1073       params.clear();
1074       for ( int i = 1; i < 6; ++i )
1075         params.push_back(( l - f ) * i/6. );
1076     }
1077     EdgeData::TPntIter where = --eData.myPoints.end();
1078     list< double >::const_iterator param = params.begin();
1079     for ( ; param != params.end(); ++param )
1080       eData.AddPoint( where, *param );
1081
1082     EdgeData::TPntIter pIt2 = eData.myPoints.begin(), pIt1 = pIt2++;
1083     for ( ; pIt2 != eData.myPoints.end(); ++pIt1, ++pIt2 )
1084     {
1085       double sz = sizeTree.SetSize( (*pIt1).myP, (*pIt2).myP );
1086       sz = Min( sz, myHyp->GetMaxSize() );
1087       pIt1->mySegSize = Min( sz, pIt1->mySegSize );
1088       pIt2->mySegSize = Min( sz, pIt2->mySegSize );
1089     }
1090
1091     if ( _computeCanceled ) return false;
1092   }
1093
1094   // Limit size of segments according to distance to closest FACE
1095
1096   for ( int iF = 1; iF <= faceMap.Extent(); ++iF )
1097   {
1098     if ( _computeCanceled ) return false;
1099
1100     const TopoDS_Face & face = TopoDS::Face( faceMap( iF ));
1101     // cout << "FACE " << iF << "/" << faceMap.Extent()
1102     //      << " id-" << theMesh.GetMeshDS()->ShapeToIndex( face ) << endl;
1103
1104     ElementBndBoxTree triaTree( face ); // tree of FACE triangulation
1105     TriaTreeData*     triaSearcher = triaTree.GetTriaData();
1106
1107     triaSearcher->SetSizeByTrias( sizeTree, myHyp->GetDeflection() );
1108
1109     for ( int iE = 0; iE < myEdges.size(); ++iE )
1110     {
1111       EdgeData& eData = myEdges[ iE ];
1112
1113       // check if the face is in topological contact with the edge
1114       bool isAdjFace = ( helper.IsSubShape( helper.IthVertex( 0, eData.Edge()), face ) ||
1115                          helper.IsSubShape( helper.IthVertex( 1, eData.Edge()), face ));
1116
1117       if ( isAdjFace && triaSearcher->mySurface.GetType() == GeomAbs_Plane )
1118         continue;
1119
1120       bool sizeDecreased = true;
1121       for (int iLoop = 0; sizeDecreased; ++iLoop ) //repeat until segment size along the edge becomes stable
1122       {
1123         double maxSegSize = 0;
1124
1125         // get points to check distance to the face
1126         EdgeData::TPntIter pIt2 = eData.myPoints.begin(), pIt1 = pIt2++;
1127         maxSegSize = pIt1->mySegSize = Min( pIt1->mySegSize, sizeTree.GetSize( pIt1->myP ));
1128         for ( ; pIt2 != eData.myPoints.end(); )
1129         {
1130           pIt2->mySegSize = Min( pIt2->mySegSize, sizeTree.GetSize( pIt2->myP ));
1131           double curSize  = Min( pIt1->mySegSize, pIt2->mySegSize );
1132           maxSegSize      = Max( pIt2->mySegSize, maxSegSize );
1133           if ( pIt1->myP.Distance( pIt2->myP ) > curSize )
1134           {
1135             double midU  = 0.5*( pIt1->myU + pIt2->myU );
1136             gp_Pnt midP  = eData.myC3d.Value( midU );
1137             double midSz = sizeTree.GetSize( midP );
1138             pIt2 = eData.myPoints.insert( pIt2, EdgeData::ProbePnt( midP, midU, midSz ));
1139             eData.myBBox.Add( midP.XYZ() );
1140           }
1141           else
1142           {
1143             ++pIt1, ++pIt2;
1144           }
1145         }
1146         // check if the face is more distant than a half of the current segment size,
1147         // if not, segment size is decreased
1148
1149         if ( iLoop == 0 && eData.IsTooDistant( triaSearcher->myBBox, maxSegSize ))
1150           break;
1151         triaSearcher->PrepareToTriaSearch();
1152
1153         //cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() ) << endl;
1154         sizeDecreased = false;
1155         const gp_Pnt* avoidPnt = & eData.First().myP;
1156         for ( pIt1 = eData.myPoints.begin(); pIt1 != eData.myPoints.end();  )
1157         {
1158           double distToFace =
1159             triaSearcher->GetMinDistInSphere( pIt1->myP, pIt1->mySegSize, isAdjFace, avoidPnt );
1160           double allowedSize = Max( minSize, distToFace*( 1. + grading ));
1161           if ( 1.1 * allowedSize < pIt1->mySegSize  )
1162           {
1163             sizeDecreased = true;
1164             sizeTree.SetSize( pIt1->myP, allowedSize );
1165             // cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() )
1166             //      << "\t SetSize " << allowedSize << " at "
1167             //      << pIt1->myP.X() <<", "<< pIt1->myP.Y()<<", "<<pIt1->myP.Z() << endl;
1168             pIt2 = pIt1;
1169             if ( --pIt2 != eData.myPoints.end() && pIt2->mySegSize > allowedSize )
1170               sizeTree.SetSize( eData.myC3d.Value( 0.6*pIt2->myU + 0.4*pIt1->myU ), allowedSize );
1171             pIt2 = pIt1;
1172             if ( ++pIt2 != eData.myPoints.end() && pIt2->mySegSize > allowedSize )
1173               sizeTree.SetSize( eData.myC3d.Value( 0.6*pIt2->myU + 0.4*pIt1->myU ), allowedSize );
1174             pIt1->mySegSize = allowedSize;
1175           }
1176           ++pIt1;
1177           if ( & (*pIt1) == & eData.Last() )
1178             avoidPnt = & eData.Last().myP;
1179           else
1180             avoidPnt = NULL;
1181
1182           if ( iLoop > 20 )
1183           {
1184 #ifdef _DEBUG_
1185             cout << "Infinite loop in AdaptiveAlgo::Compute()" << endl;
1186 #endif
1187             sizeDecreased = false;
1188             break;
1189           }
1190         }
1191       } // while ( sizeDecreased )
1192     } // loop on myEdges
1193
1194     //*theProgress = 0.3 + 0.3 * iF / double( faceMap.Extent() );
1195
1196   } // loop on faceMap
1197
1198   return makeSegments();
1199 }
1200
1201 //================================================================================
1202 /*!
1203  * \brief Create segments
1204  */
1205 //================================================================================
1206
1207 bool AdaptiveAlgo::makeSegments()
1208 {
1209   SMESH_HypoFilter quadHyp( SMESH_HypoFilter::HasName( "QuadraticMesh" ));
1210   _quadraticMesh = myMesh->GetHypothesis( myEdges[0].Edge(), quadHyp, /*andAncestors=*/true );
1211
1212   SMESH_MesherHelper helper( *myMesh );
1213   helper.SetIsQuadratic( _quadraticMesh );
1214
1215   vector< double > nbSegs, params;
1216
1217   for ( int iE = 0; iE < myEdges.size(); ++iE )
1218   {
1219     EdgeData& eData = myEdges[ iE ];
1220
1221     // estimate roughly min segement size on the EDGE
1222     double edgeMinSize = myHyp->GetMaxSize();
1223     EdgeData::TPntIter pIt1 = eData.myPoints.begin();
1224     for ( ; pIt1 != eData.myPoints.end(); ++pIt1 )
1225       edgeMinSize = Min( edgeMinSize, mySizeTree->GetSize( pIt1->myP ));
1226
1227     const double f = eData.myC3d.FirstParameter(), l = eData.myC3d.LastParameter();
1228     const double parLen = l - f;
1229     const int  nbDivSeg = 5;
1230     int           nbDiv = Max( 1, int ( eData.myLength / edgeMinSize * nbDivSeg ));
1231
1232     // compute nb of segments
1233     bool toRecompute = true;
1234     double maxSegSize = 0;
1235     //cout << "E " << theMesh.GetMeshDS()->ShapeToIndex( eData.Edge() ) << endl;
1236     while ( toRecompute ) // recompute if segment size at some point is less than edgeMinSize/nbDivSeg
1237     {
1238       nbSegs.resize( nbDiv + 1 );
1239       nbSegs[0] = 0;
1240       toRecompute = false;
1241
1242       gp_Pnt p1 = eData.First().myP, p2, pDiv = p1;
1243       for ( size_t i = 1, segCount = 1; i < nbSegs.size(); ++i )
1244       {
1245         p2 = eData.myC3d.Value( f + parLen * i / nbDiv );
1246         double locSize = Min( mySizeTree->GetSize( p2 ), myHyp->GetMaxSize() );
1247         double nb      = p1.Distance( p2 ) / locSize;
1248         // if ( nbSegs.size() < 30 )
1249         //   cout << "locSize " << locSize << " nb " << nb << endl;
1250         if ( nb > 1. )
1251         {
1252           toRecompute = true;
1253           edgeMinSize = locSize;
1254           nbDiv = int ( eData.myLength / edgeMinSize * nbDivSeg );
1255           break;
1256         }
1257         nbSegs[i] = nbSegs[i-1] + nb;
1258         p1 = p2;
1259         if ( nbSegs[i] >= segCount )
1260         {
1261           maxSegSize = Max( maxSegSize, pDiv.Distance( p2 ));
1262           pDiv = p2;
1263           ++segCount;
1264         }
1265       }
1266     }
1267
1268     // compute parameters of nodes
1269     int nbSegFinal = Max( 1, int(floor( nbSegs.back() + 0.5 )));
1270     double fact = nbSegFinal / nbSegs.back();
1271     if ( maxSegSize / fact > myHyp->GetMaxSize() )
1272       fact = ++nbSegFinal / nbSegs.back();
1273     //cout << "nbSegs.back() " << nbSegs.back() << " nbSegFinal " << nbSegFinal << endl;
1274     params.clear();
1275     for ( int i = 0, segCount = 1; segCount < nbSegFinal; ++segCount )
1276     {
1277       while ( nbSegs[i] * fact < segCount )
1278         ++i;
1279       if ( i < nbDiv )
1280       {
1281         double d = i - ( nbSegs[i] - segCount/fact ) / ( nbSegs[i] - nbSegs[i-1] );
1282         params.push_back( f + parLen * d / nbDiv );
1283         //params.push_back( f + parLen * i / nbDiv );
1284       }
1285       else
1286         break;
1287     }
1288     // get nodes on VERTEXes
1289     TopoDS_Vertex vf = helper.IthVertex( 0, eData.Edge(), false );
1290     TopoDS_Vertex vl = helper.IthVertex( 1, eData.Edge(), false );
1291     myMesh->GetSubMesh( vf )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
1292     myMesh->GetSubMesh( vl )->ComputeStateEngine( SMESH_subMesh::COMPUTE );
1293     const SMDS_MeshNode * nf = VertexNode( vf, myMesh->GetMeshDS() );
1294     const SMDS_MeshNode * nl = VertexNode( vl, myMesh->GetMeshDS() );
1295     if ( !nf || !nl )
1296       return error("No node on vertex");
1297
1298     // create segments
1299     helper.SetSubShape( eData.Edge() );
1300     helper.SetElementsOnShape( true );
1301     const int ID = 0;
1302     const SMDS_MeshNode *n1 = nf, *n2;
1303     for ( size_t i = 0; i < params.size(); ++i, n1 = n2 )
1304     {
1305       gp_Pnt p2 = eData.myC3d.Value( params[i] );
1306       n2 = helper.AddNode( p2.X(), p2.Y(), p2.Z(), ID, params[i] );
1307       helper.AddEdge( n1, n2, ID, /*force3d=*/false );
1308     }
1309     helper.AddEdge( n1, nl, ID, /*force3d=*/false );
1310
1311     eData.myPoints.clear();
1312
1313     //*theProgress = 0.6 + 0.4 * iE / double( myEdges.size() );
1314     if ( _computeCanceled )
1315       return false;
1316
1317   } // loop on EDGEs
1318
1319   SMESHUtils::FreeVector( myEdges );
1320
1321   return true;
1322 }
1323
1324 //================================================================================
1325 /*!
1326  * \brief Predict number of segments on all given EDGEs
1327  */
1328 //================================================================================
1329
1330 bool AdaptiveAlgo::Evaluate(SMESH_Mesh &         theMesh,
1331                             const TopoDS_Shape & theShape,
1332                             MapShapeNbElems&     theResMap)
1333 {
1334   // initialize fields of inherited StdMeshers_Regular_1D
1335   StdMeshers_Regular_1D::_hypType = DEFLECTION;
1336   StdMeshers_Regular_1D::_value[ DEFLECTION_IND ] = myHyp->GetDeflection();
1337
1338   TopExp_Explorer edExp( theShape, TopAbs_EDGE );
1339
1340   for ( ; edExp.More(); edExp.Next() )
1341   {
1342     const TopoDS_Edge & edge = TopoDS::Edge( edExp.Current() );
1343     StdMeshers_Regular_1D::Evaluate( theMesh, theShape, theResMap );
1344   }
1345   return true;
1346 }
1347