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