Salome HOME
PAL10173. Protect computeParamByFunc() against divisionby zero when f(0)=0 and agains...
[modules/smesh.git] / src / StdMeshers / StdMeshers_Regular_1D.cxx
1 //  SMESH SMESH : implementaion of SMESH idl descriptions
2 //
3 //  Copyright (C) 2003  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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : StdMeshers_Regular_1D.cxx
25 //           Moved here from SMESH_Regular_1D.cxx
26 //  Author : Paul RASCLE, EDF
27 //  Module : SMESH
28 //  $Header$
29
30 using namespace std;
31
32 #include "StdMeshers_Regular_1D.hxx"
33 #include "SMESH_Gen.hxx"
34 #include "SMESH_Mesh.hxx"
35
36 #include "StdMeshers_LocalLength.hxx"
37 #include "StdMeshers_NumberOfSegments.hxx"
38 #include "StdMeshers_Arithmetic1D.hxx"
39 #include "StdMeshers_StartEndLength.hxx"
40 #include "StdMeshers_Deflection1D.hxx"
41 #include <StdMeshers_AutomaticLength.hxx>
42
43 #include "SMDS_MeshElement.hxx"
44 #include "SMDS_MeshNode.hxx"
45 #include "SMDS_EdgePosition.hxx"
46 #include "SMESH_subMesh.hxx"
47
48 #include "Utils_SALOME_Exception.hxx"
49 #include "utilities.h"
50
51 #include <BRep_Tool.hxx>
52 #include <TopoDS_Edge.hxx>
53 #include <TopoDS_Shape.hxx>
54 #include <TopTools_ListIteratorOfListOfShape.hxx>
55 #include <GeomAdaptor_Curve.hxx>
56 #include <GCPnts_AbscissaPoint.hxx>
57 #include <GCPnts_UniformAbscissa.hxx>
58 #include <GCPnts_UniformDeflection.hxx>
59 #include <Standard_ErrorHandler.hxx>
60 #include <Precision.hxx>
61 #include <Expr_GeneralExpression.hxx>
62 #include <Expr_NamedUnknown.hxx>
63 #include <Expr_Array1OfNamedUnknown.hxx>
64 #include <TColStd_Array1OfReal.hxx>
65 #include <ExprIntrp_GenExp.hxx>
66
67 #include <string>
68 #include <math.h>
69
70 //=============================================================================
71 /*!
72  *  
73  */
74 //=============================================================================
75
76 StdMeshers_Regular_1D::StdMeshers_Regular_1D(int hypId, int studyId,
77         SMESH_Gen * gen):SMESH_1D_Algo(hypId, studyId, gen)
78 {
79         MESSAGE("StdMeshers_Regular_1D::StdMeshers_Regular_1D");
80         _name = "Regular_1D";
81         _shapeType = (1 << TopAbs_EDGE);
82
83         _compatibleHypothesis.push_back("LocalLength");
84         _compatibleHypothesis.push_back("NumberOfSegments");
85         _compatibleHypothesis.push_back("StartEndLength");
86         _compatibleHypothesis.push_back("Deflection1D");
87         _compatibleHypothesis.push_back("Arithmetic1D");
88         _compatibleHypothesis.push_back("AutomaticLength");
89 }
90
91 //=============================================================================
92 /*!
93  *  
94  */
95 //=============================================================================
96
97 StdMeshers_Regular_1D::~StdMeshers_Regular_1D()
98 {
99 }
100
101 //=============================================================================
102 /*!
103  *  
104  */
105 //=============================================================================
106
107 bool StdMeshers_Regular_1D::CheckHypothesis
108                          (SMESH_Mesh& aMesh,
109                           const TopoDS_Shape& aShape,
110                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
111 {
112   _hypType = NONE;
113
114   const list <const SMESHDS_Hypothesis * >&hyps = GetUsedHypothesis(aMesh, aShape);
115   if (hyps.size() == 0)
116   {
117     aStatus = SMESH_Hypothesis::HYP_MISSING;
118     return false;  // can't work without a hypothesis
119   }
120
121   // use only the first hypothesis
122   const SMESHDS_Hypothesis *theHyp = hyps.front();
123
124   string hypName = theHyp->GetName();
125
126   if (hypName == "LocalLength")
127   {
128     const StdMeshers_LocalLength * hyp =
129       dynamic_cast <const StdMeshers_LocalLength * >(theHyp);
130     ASSERT(hyp);
131     _value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength();
132     ASSERT( _value[ BEG_LENGTH_IND ] > 0 );
133     _hypType = LOCAL_LENGTH;
134     aStatus = SMESH_Hypothesis::HYP_OK;
135   }
136
137   else if (hypName == "NumberOfSegments")
138   {
139     const StdMeshers_NumberOfSegments * hyp =
140       dynamic_cast <const StdMeshers_NumberOfSegments * >(theHyp);
141     ASSERT(hyp);
142     _ivalue[ NB_SEGMENTS_IND  ] = hyp->GetNumberOfSegments();
143     ASSERT( _ivalue[ NB_SEGMENTS_IND ] > 0 );
144     _ivalue[ DISTR_TYPE_IND ] = (int) hyp->GetDistrType();
145     switch (_ivalue[ DISTR_TYPE_IND ])
146     {
147     case StdMeshers_NumberOfSegments::DT_Scale:
148       _value[ SCALE_FACTOR_IND ] = hyp->GetScaleFactor();
149       break;
150     case StdMeshers_NumberOfSegments::DT_TabFunc:
151       _vvalue[ TAB_FUNC_IND ] = hyp->GetTableFunction();
152       break;
153     case StdMeshers_NumberOfSegments::DT_ExprFunc:
154       _svalue[ EXPR_FUNC_IND ] = hyp->GetExpressionFunction();
155       break;
156     case StdMeshers_NumberOfSegments::DT_Regular:
157       break;
158     default:
159       ASSERT(0);
160       break;
161     }
162     if (_ivalue[ DISTR_TYPE_IND ] == StdMeshers_NumberOfSegments::DT_TabFunc ||
163         _ivalue[ DISTR_TYPE_IND ] == StdMeshers_NumberOfSegments::DT_ExprFunc)
164       _ivalue[ EXP_MODE_IND ] = (int) hyp->IsExponentMode();
165     _hypType = NB_SEGMENTS;
166     aStatus = SMESH_Hypothesis::HYP_OK;
167   }
168
169   else if (hypName == "Arithmetic1D")
170   {
171     const StdMeshers_Arithmetic1D * hyp =
172       dynamic_cast <const StdMeshers_Arithmetic1D * >(theHyp);
173     ASSERT(hyp);
174     _value[ BEG_LENGTH_IND ] = hyp->GetLength( true );
175     _value[ END_LENGTH_IND ] = hyp->GetLength( false );
176     ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 );
177     _hypType = ARITHMETIC_1D;
178     aStatus = SMESH_Hypothesis::HYP_OK;
179   }
180
181   else if (hypName == "StartEndLength")
182   {
183     const StdMeshers_StartEndLength * hyp =
184       dynamic_cast <const StdMeshers_StartEndLength * >(theHyp);
185     ASSERT(hyp);
186     _value[ BEG_LENGTH_IND ] = hyp->GetLength( true );
187     _value[ END_LENGTH_IND ] = hyp->GetLength( false );
188     ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 );
189     _hypType = BEG_END_LENGTH;
190     aStatus = SMESH_Hypothesis::HYP_OK;
191   }
192
193   else if (hypName == "Deflection1D")
194   {
195     const StdMeshers_Deflection1D * hyp =
196       dynamic_cast <const StdMeshers_Deflection1D * >(theHyp);
197     ASSERT(hyp);
198     _value[ DEFLECTION_IND ] = hyp->GetDeflection();
199     ASSERT( _value[ DEFLECTION_IND ] > 0 );
200     _hypType = DEFLECTION;
201     aStatus = SMESH_Hypothesis::HYP_OK;
202   }
203
204   else if (hypName == "AutomaticLength")
205   {
206     StdMeshers_AutomaticLength * hyp = const_cast<StdMeshers_AutomaticLength *>
207       (dynamic_cast <const StdMeshers_AutomaticLength * >(theHyp));
208     ASSERT(hyp);
209     _value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape );
210     ASSERT( _value[ BEG_LENGTH_IND ] > 0 );
211     _hypType = LOCAL_LENGTH;
212     aStatus = SMESH_Hypothesis::HYP_OK;
213   }
214   else
215     aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
216
217   return ( _hypType != NONE );
218 }
219
220 //=======================================================================
221 //function : compensateError
222 //purpose  : adjust theParams so that the last segment length == an
223 //=======================================================================
224
225 static void compensateError(double a1, double an,
226                             double U1, double Un,
227                             double             length,
228                             GeomAdaptor_Curve& C3d,
229                             list<double> &     theParams)
230 {
231   int i, nPar = theParams.size();
232   if ( a1 + an < length && nPar > 1 )
233   {
234     list<double>::reverse_iterator itU = theParams.rbegin();
235     double Ul = *itU++;
236     // dist from the last point to the edge end <Un>, it should be equal <an>
237     double Ln = GCPnts_AbscissaPoint::Length( C3d, Ul, Un );
238     double dLn = an - Ln; // error of <an>
239     if ( Abs( dLn ) <= Precision::Confusion() )
240       return;
241     double dU = Abs( Ul - *itU ); // parametric length of the last but one segment
242     double dUn = dLn * Abs( Un - U1 ) / length; // parametric error of <an>
243     if ( dUn < 0.5 * dU ) { // last segment is a bit shorter than it should
244       dUn = -dUn; // move the last parameter to the edge beginning
245     }
246     else {  // last segment is much shorter than it should -> remove the last param and
247       theParams.pop_back(); nPar--; // move the rest points toward the edge end
248       Ln = GCPnts_AbscissaPoint::Length( C3d, theParams.back(), Un );
249       dUn = ( an - Ln ) * Abs( Un - U1 ) / length;
250       if ( dUn < 0.5 * dU )
251         dUn = -dUn;
252     }
253     if ( U1 > Un )
254       dUn = -dUn;
255     double q  = dUn / ( nPar - 1 );
256     for ( itU = theParams.rbegin(), i = 1; i < nPar; itU++, i++ ) {
257       (*itU) += dUn;
258       dUn -= q;
259     }
260   }
261 }
262
263 /*!
264  * \brief This class provides interface for a density function
265  */
266 class Function
267 {
268 public:
269   Function(bool expMode) : _expMode(expMode) {}
270   double operator() (double t) const;
271   virtual bool IsReady() const = 0;
272 protected:
273   virtual double compute(double t) const = 0;
274 private:
275   bool _expMode;
276 };
277
278 /*!
279  * \brief This class provides computation of density function given by a table
280  */
281 class TabFunction: public Function
282 {
283 public:
284   TabFunction(const vector<double>& table, bool expMode);
285   virtual bool IsReady() const;
286 protected:
287   virtual double compute(double t) const;
288 private:
289   const vector<double>& _table;
290 };
291
292 /*!
293  * \brief This class provides computation of density function given by an expression
294  */
295 class ExprFunction: public Function
296 {
297 public:
298   ExprFunction(const char* expr, bool expMode);
299   virtual bool IsReady() const;
300 protected:
301   virtual double compute(double t) const;
302 private:
303   Handle(Expr_GeneralExpression) _expression;
304   Expr_Array1OfNamedUnknown _var;
305   mutable TColStd_Array1OfReal _val;
306 };
307
308 double Function::operator() (double t) const
309 {
310   double res = compute(t);
311   if (_expMode)
312     res = pow(10, res);
313   return res;
314 }
315
316 TabFunction::TabFunction(const vector<double>& table, bool expMode)
317   : Function(expMode),
318     _table(table)
319 {
320 }
321
322 bool TabFunction::IsReady() const
323 {
324   return true;
325 }
326
327 double TabFunction::compute (double t) const
328 {
329   //find place of <t> in table
330   int i;
331   for (i=0; i < _table.size()/2; i++)
332     if (_table[i*2] > t)
333       break;
334   if (i >= _table.size()/2)
335     i = _table.size()/2 - 1;
336
337   if (i == 0)
338     return _table[1];
339
340   // interpolate function value on found interval
341   // (t - x[i-1]) / (x[i] - x[i-1]) = (y - f[i-1]) / (f[i] - f[i-1])
342   // => y = f[i-1] + (f[i] - f[i-1]) * (t - x[i-1]) / (x[i] - x[i-1])
343   double x1 = _table[(i-1)*2];
344   double x2 = _table[i*2];
345   double y1 = _table[(i-1)*2+1];
346   double y2 = _table[i*2+1];
347   if (x2 - x1 < Precision::Confusion())
348     throw SALOME_Exception("TabFunction::compute : confused points");
349   return y1 + (y2 - y1) * ((t - x1) / (x2 - x1));
350 }
351
352 ExprFunction::ExprFunction(const char* expr, bool expMode)
353   : Function(expMode),
354     _var(1,1),
355     _val(1,1)
356 {
357   Handle( ExprIntrp_GenExp ) gen = ExprIntrp_GenExp::Create();
358   gen->Process(TCollection_AsciiString((char*)expr));
359   if (gen->IsDone())
360   {
361     _expression = gen->Expression();
362     _var(1) = new Expr_NamedUnknown("t");
363   }
364 }
365
366 bool ExprFunction::IsReady() const
367 {
368   return !_expression.IsNull();
369 }
370
371 double ExprFunction::compute (double t) const
372 {
373   ASSERT(!_expression.IsNull());
374   _val(1) = t;
375   return _expression->Evaluate(_var, _val);
376 }
377
378 //================================================================================
379 /*!
380  * \brief Compute next abscissa when two previous ones are given
381   * \param sm2 - before previous abscissa
382   * \param sm1 - previous abscissa
383   * \param func - function of density
384   * \param reverse - the direction of next abscissa, increase (0) or decrease (1)
385   * \retval double - the new abscissa
386  * 
387  * The abscissa s is given by the formulae
388  *
389  * ....|--------|----------------|.....
390  *    sm2      sm1               s
391  *
392  *    func(sm2) / func(sm1)  = (sm1-sm2) / (s-sm1)
393  * => (s-sm1) * func(sm2) = (sm1-sm2) * func(sm1)
394  * => s = sm1 + (sm1-sm2) * func(sm1) / func(sm2)
395  */
396 //================================================================================
397
398 static double nextAbscissa(double sm2, double sm1, const Function& func, int reverse)
399 {
400   if (reverse)
401   {
402     sm1 = 1.0 - sm1;
403     sm2 = 1.0 - sm2;
404   }
405   return sm1 + (sm1-sm2) * func(sm1) / func(sm2);
406 }
407
408 //================================================================================
409 /*!
410  * \brief Compute distribution of points on a curve following the law of a function
411   * \param C3d - the curve to discretize
412   * \param first - the first parameter on the curve 
413   * \param last - the last parameter on the curve 
414   * \param theReverse - flag indicating that the curve must be reversed
415   * \param nbSeg - number of output segments
416   * \param func - the function f(t)
417   * \param theParams - output points
418   * \retval bool  - true if success
419  */
420 //================================================================================
421
422 static bool computeParamByFunc(Adaptor3d_Curve& C3d, double first, double last,
423                                double length, bool theReverse, 
424                                int nbSeg, const Function& func,
425                                list<double>& theParams)
426 {
427   if (!func.IsReady())
428     return false;
429
430   // ########## TMP until pb division by zero when func(0.0)==0 is fixed #########
431   if (::Abs(func(0.0)) <= ::RealSmall() ) return false;
432   // ########## TMP until pb division by zero when func(0.0)==0 is fixed #########
433
434   vector<double> xxx[2];
435   int nbPnt = 1 + nbSeg;
436   int rev, i;
437   for (rev=0; rev < 2; rev++)
438   {
439     // curv abscisses initialisation
440     vector<double> x(nbPnt, 0.);
441     // the first abscissa is 0.0
442
443     // The aim of the algorithm is to find a second abscisse x[1] such as the last
444     // one x[nbSeg] is very close to 1.0 with the epsilon precision
445
446     double x1_too_small = 0.0;
447     double x1_too_large = RealLast();
448     double x1 = 1.0/nbSeg;
449     while (1)
450     {
451       x[1] = x1;
452
453       // Check if the abscissa of the point 2 to N-1
454       // are in the segment ...
455
456       bool ok = true;
457       for (i=2; i <= nbSeg; i++)
458       {
459         x[i] = nextAbscissa(x[i-2], x[i-1], func, rev);
460         if (x[i] - 1.0 > Precision::Confusion())
461         {
462           x[nbSeg] = x[i];
463           ok = false;
464           break;
465         }
466       }
467       if (!ok)
468       {
469         // The segments are to large
470         // Decrease x1 ...
471         x1_too_large = x1;
472         x1 = (x1_too_small+x1_too_large)/2;
473         if ( x1 <= ::RealSmall() )
474           return false; // break infinite loop
475         continue;
476       }
477
478       // Look at the abscissa of the point N
479       // which is to be close to 1.0
480
481       // break condition --> algo converged !!
482
483       if (1.0 - x[nbSeg] < Precision::Confusion())
484         break;
485
486       // not ok ...
487
488       x1_too_small = x1;
489
490       // Modify x1 value
491
492       if (x1_too_large > 1e100)
493         x1 = 2*x1;
494       else
495         x1 = (x1_too_small+x1_too_large)/2;
496     }
497     xxx[rev] = x;
498   }
499
500   // average
501   vector<double> x(nbPnt, 0.);
502   for (i=0; i < nbPnt; i++)
503     x[i] = (xxx[0][i] + (1.0 - xxx[1][nbPnt-i])) / 2;
504
505   // apply parameters in range [0,1] to the space of the curve
506   double prevU = first;
507   double sign = 1.;
508   if (theReverse)
509   {
510     prevU = last;
511     sign = -1.;
512   }
513   for (i = 1; i < nbSeg; i++)
514   {
515     double curvLength = length * (x[i] - x[i-1]) * sign;
516     GCPnts_AbscissaPoint Discret( C3d, curvLength, prevU );
517     if ( !Discret.IsDone() )
518       return false;
519     double U = Discret.Parameter();
520     if ( U > first && U < last )
521       theParams.push_back( U );
522     else
523       return false;
524     prevU = U;
525   }
526   return true;
527 }
528
529 //=============================================================================
530 /*!
531  *  
532  */
533 //=============================================================================
534 bool StdMeshers_Regular_1D::computeInternalParameters(const TopoDS_Edge& theEdge,
535                                                       list<double> &     theParams,
536                                                       const bool         theReverse) const
537 {
538   theParams.clear();
539
540   double f, l;
541   Handle(Geom_Curve) Curve = BRep_Tool::Curve(theEdge, f, l);
542   GeomAdaptor_Curve C3d(Curve);
543
544   double length = EdgeLength(theEdge);
545
546   switch( _hypType )
547   {
548   case LOCAL_LENGTH:
549   case NB_SEGMENTS: {
550
551     double eltSize = 1;
552     if ( _hypType == LOCAL_LENGTH )
553     {
554       // Local Length hypothesis
555       double nbseg = ceil(length / _value[ BEG_LENGTH_IND ]); // integer sup
556       if (nbseg <= 0)
557         nbseg = 1;                        // degenerated edge
558       eltSize = length / nbseg;
559     }
560     else
561     {
562       // Number Of Segments hypothesis
563       switch (_ivalue[ DISTR_TYPE_IND ])
564       {
565       case StdMeshers_NumberOfSegments::DT_Scale:
566         {
567           double scale = _value[ SCALE_FACTOR_IND ];
568           if ( theReverse )
569             scale = 1. / scale;
570           double alpha = pow( scale , 1.0 / (_ivalue[ NB_SEGMENTS_IND ] - 1));
571           double factor = (l - f) / (1 - pow( alpha,_ivalue[ NB_SEGMENTS_IND ]));
572
573           int i, NbPoints = 1 + _ivalue[ NB_SEGMENTS_IND ];
574           for ( i = 2; i < NbPoints; i++ )
575           {
576             double param = f + factor * (1 - pow(alpha, i - 1));
577             theParams.push_back( param );
578           }
579           return true;
580         }
581         break;
582       case StdMeshers_NumberOfSegments::DT_TabFunc:
583         {
584           TabFunction func(_vvalue[ TAB_FUNC_IND ], (bool)_ivalue[ EXP_MODE_IND ]);
585           return computeParamByFunc(C3d, f, l, length, theReverse,
586                                     _ivalue[ NB_SEGMENTS_IND ], func,
587                                     theParams);
588         }
589         break;
590       case StdMeshers_NumberOfSegments::DT_ExprFunc:
591         {
592           ExprFunction func(_svalue[ EXPR_FUNC_IND ].c_str(), (bool)_ivalue[ EXP_MODE_IND ]);
593           return computeParamByFunc(C3d, f, l, length, theReverse,
594                                     _ivalue[ NB_SEGMENTS_IND ], func,
595                                     theParams);
596         }
597         break;
598       case StdMeshers_NumberOfSegments::DT_Regular:
599         eltSize = length / _ivalue[ NB_SEGMENTS_IND ];
600         break;
601       default:
602         return false;
603       }
604     }
605
606     GCPnts_UniformAbscissa Discret(C3d, eltSize, f, l);
607     if ( !Discret.IsDone() )
608       return false;
609
610     int NbPoints = Discret.NbPoints();
611     for ( int i = 2; i < NbPoints; i++ )
612     {
613       double param = Discret.Parameter(i);
614       theParams.push_back( param );
615     }
616     return true;
617   }
618
619   case BEG_END_LENGTH: {
620
621     // geometric progression: SUM(n) = ( a1 - an * q ) / ( 1 - q ) = length
622
623     double a1 = _value[ BEG_LENGTH_IND ];
624     double an = _value[ END_LENGTH_IND ];
625     double q  = ( length - a1 ) / ( length - an );
626
627     double U1 = theReverse ? l : f;
628     double Un = theReverse ? f : l;
629     double param = U1;
630     double eltSize = theReverse ? -a1 : a1;
631     while ( 1 ) {
632       // computes a point on a curve <C3d> at the distance <eltSize>
633       // from the point of parameter <param>.
634       GCPnts_AbscissaPoint Discret( C3d, eltSize, param );
635       if ( !Discret.IsDone() ) break;
636       param = Discret.Parameter();
637       if ( param > f && param < l )
638         theParams.push_back( param );
639       else
640         break;
641       eltSize *= q;
642     }
643     compensateError( a1, an, U1, Un, length, C3d, theParams );
644     return true;
645   }
646
647   case ARITHMETIC_1D: {
648
649     // arithmetic progression: SUM(n) = ( an - a1 + q ) * ( a1 + an ) / ( 2 * q ) = length
650
651     double a1 = _value[ BEG_LENGTH_IND ];
652     double an = _value[ END_LENGTH_IND ];
653
654     double  q = ( an - a1 ) / ( 2 *length/( a1 + an ) - 1 );
655     int     n = int( 1 + ( an - a1 ) / q );
656
657     double U1 = theReverse ? l : f;
658     double Un = theReverse ? f : l;
659     double param = U1;
660     double eltSize = a1;
661     if ( theReverse ) {
662       eltSize = -eltSize;
663       q = -q;
664     }
665     while ( n-- > 0 && eltSize * ( Un - U1 ) > 0 ) {
666       // computes a point on a curve <C3d> at the distance <eltSize>
667       // from the point of parameter <param>.
668       GCPnts_AbscissaPoint Discret( C3d, eltSize, param );
669       if ( !Discret.IsDone() ) break;
670       param = Discret.Parameter();
671       if ( param > f && param < l )
672         theParams.push_back( param );
673       else
674         break;
675       eltSize += q;
676     }
677     compensateError( a1, an, U1, Un, length, C3d, theParams );
678
679     return true;
680   }
681
682   case DEFLECTION: {
683
684     GCPnts_UniformDeflection Discret(C3d, _value[ DEFLECTION_IND ], true);
685     if ( !Discret.IsDone() )
686       return false;
687
688     int NbPoints = Discret.NbPoints();
689     for ( int i = 2; i < NbPoints; i++ )
690     {
691       double param = Discret.Parameter(i);
692       theParams.push_back( param );
693     }
694     return true;
695     
696   }
697
698   default:;
699   }
700
701   return false;
702 }
703
704 //=============================================================================
705 /*!
706  *  
707  */
708 //=============================================================================
709
710 bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape)
711 {
712   MESSAGE("StdMeshers_Regular_1D::Compute");
713
714   if ( _hypType == NONE )
715     return false;
716
717   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
718   aMesh.GetSubMesh(aShape);
719
720   const TopoDS_Edge & EE = TopoDS::Edge(aShape);
721   TopoDS_Edge E = TopoDS::Edge(EE.Oriented(TopAbs_FORWARD));
722   int shapeID = meshDS->ShapeToIndex( E );
723
724   double f, l;
725   Handle(Geom_Curve) Curve = BRep_Tool::Curve(E, f, l);
726
727   TopoDS_Vertex VFirst, VLast;
728   TopExp::Vertices(E, VFirst, VLast);   // Vfirst corresponds to f and Vlast to l
729
730   ASSERT(!VFirst.IsNull());
731   SMDS_NodeIteratorPtr lid= aMesh.GetSubMesh(VFirst)->GetSubMeshDS()->GetNodes();
732   if (!lid->more())
733   {
734     MESSAGE (" NO NODE BUILT ON VERTEX ");
735     return false;
736   }
737   const SMDS_MeshNode * idFirst = lid->next();
738
739   ASSERT(!VLast.IsNull());
740   lid=aMesh.GetSubMesh(VLast)->GetSubMeshDS()->GetNodes();
741   if (!lid->more())
742   {
743     MESSAGE (" NO NODE BUILT ON VERTEX ");
744     return false;
745   }
746   const SMDS_MeshNode * idLast = lid->next();
747
748   if (!Curve.IsNull())
749   {
750     list< double > params;
751     bool reversed = false;
752     if ( !_mainEdge.IsNull() )
753       reversed = aMesh.IsReversedInChain( EE, _mainEdge );
754     try {
755       if ( ! computeInternalParameters( E, params, reversed ))
756         return false;
757     }
758     catch ( Standard_Failure ) {
759       return false;
760     }
761
762     // edge extrema (indexes : 1 & NbPoints) already in SMDS (TopoDS_Vertex)
763     // only internal nodes receive an edge position with param on curve
764
765     const SMDS_MeshNode * idPrev = idFirst;
766     
767     for (list<double>::iterator itU = params.begin(); itU != params.end(); itU++)
768     {
769       double param = *itU;
770       gp_Pnt P = Curve->Value(param);
771
772       //Add the Node in the DataStructure
773       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
774       meshDS->SetNodeOnEdge(node, shapeID, param);
775
776       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
777       meshDS->SetMeshElementOnShape(edge, shapeID);
778       idPrev = node;
779     }
780     SMDS_MeshEdge* edge = meshDS->AddEdge(idPrev, idLast);
781     meshDS->SetMeshElementOnShape(edge, shapeID);
782   }
783   else
784   {
785     // Edge is a degenerated Edge : We put n = 5 points on the edge.
786     int NbPoints = 5;
787     BRep_Tool::Range(E, f, l);
788     double du = (l - f) / (NbPoints - 1);
789     //MESSAGE("************* Degenerated edge! *****************");
790
791     TopoDS_Vertex V1, V2;
792     TopExp::Vertices(E, V1, V2);
793     gp_Pnt P = BRep_Tool::Pnt(V1);
794
795     const SMDS_MeshNode * idPrev = idFirst;
796     for (int i = 2; i < NbPoints; i++)
797     {
798       double param = f + (i - 1) * du;
799       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
800       meshDS->SetNodeOnEdge(node, shapeID, param);
801
802       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
803       meshDS->SetMeshElementOnShape(edge, shapeID);
804       idPrev = node;
805     }
806     SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast);
807     meshDS->SetMeshElementOnShape(edge, shapeID);
808   }
809   return true;
810 }
811
812 //=============================================================================
813 /*!
814  *  See comments in SMESH_Algo.cxx
815  */
816 //=============================================================================
817
818 const list <const SMESHDS_Hypothesis *> & StdMeshers_Regular_1D::GetUsedHypothesis(
819         SMESH_Mesh & aMesh, const TopoDS_Shape & aShape)
820 {
821   _usedHypList.clear();
822   _usedHypList = GetAppliedHypothesis(aMesh, aShape);   // copy
823   int nbHyp = _usedHypList.size();
824   _mainEdge.Nullify();
825   if (nbHyp == 0)
826   {
827     // Check, if propagated from some other edge
828     if (aShape.ShapeType() == TopAbs_EDGE &&
829         aMesh.IsPropagatedHypothesis(aShape, _mainEdge))
830     {
831       // Propagation of 1D hypothesis from <aMainEdge> on this edge
832       //_usedHypList = GetAppliedHypothesis(aMesh, _mainEdge);  // copy
833       // use a general method in order not to nullify _mainEdge
834       _usedHypList = SMESH_Algo::GetUsedHypothesis(aMesh, _mainEdge);   // copy
835       nbHyp = _usedHypList.size();
836     }
837   }
838   if (nbHyp == 0)
839   {
840     TopTools_ListIteratorOfListOfShape ancIt( aMesh.GetAncestors( aShape ));
841     for (; ancIt.More(); ancIt.Next())
842     {
843       const TopoDS_Shape& ancestor = ancIt.Value();
844       _usedHypList = GetAppliedHypothesis(aMesh, ancestor);     // copy
845       nbHyp = _usedHypList.size();
846       if (nbHyp == 1)
847         break;
848     }
849   }
850   if (nbHyp > 1)
851     _usedHypList.clear();       //only one compatible hypothesis allowed
852   return _usedHypList;
853 }
854
855 //=============================================================================
856 /*!
857  *  
858  */
859 //=============================================================================
860
861 ostream & StdMeshers_Regular_1D::SaveTo(ostream & save)
862 {
863   return save;
864 }
865
866 //=============================================================================
867 /*!
868  *  
869  */
870 //=============================================================================
871
872 istream & StdMeshers_Regular_1D::LoadFrom(istream & load)
873 {
874   return load;
875 }
876
877 //=============================================================================
878 /*!
879  *  
880  */
881 //=============================================================================
882
883 ostream & operator <<(ostream & save, StdMeshers_Regular_1D & hyp)
884 {
885   return hyp.SaveTo( save );
886 }
887
888 //=============================================================================
889 /*!
890  *  
891  */
892 //=============================================================================
893
894 istream & operator >>(istream & load, StdMeshers_Regular_1D & hyp)
895 {
896   return hyp.LoadFrom( load );
897 }