Salome HOME
PAL10237. Add StdMeshers_AutomaticLength 1D hypothesis
[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   vector<double> xxx[2];
430   int nbPnt = 1 + nbSeg;
431   int rev, i;
432   for (rev=0; rev < 2; rev++)
433   {
434     // curv abscisses initialisation
435     vector<double> x(nbPnt, 0.);
436     // the first abscissa is 0.0
437
438     // The aim of the algorithm is to find a second abscisse x[1] such as the last
439     // one x[nbSeg] is very close to 1.0 with the epsilon precision
440
441     double x1_too_small = 0.0;
442     double x1_too_large = RealLast();
443     double x1 = 1.0/nbSeg;
444     while (1)
445     {
446       x[1] = x1;
447
448       // Check if the abscissa of the point 2 to N-1
449       // are in the segment ...
450
451       bool ok = true;
452       for (i=2; i <= nbSeg; i++)
453       {
454         x[i] = nextAbscissa(x[i-2], x[i-1], func, rev);
455         if (x[i] - 1.0 > Precision::Confusion())
456         {
457           x[nbSeg] = x[i];
458           ok = false;
459           break;
460         }
461       }
462       if (!ok)
463       {
464         // The segments are to large
465         // Decrease x1 ...
466         x1_too_large = x1;
467         x1 = (x1_too_small+x1_too_large)/2;
468         continue;
469       }
470
471       // Look at the abscissa of the point N
472       // which is to be close to 1.0
473
474       // break condition --> algo converged !!
475
476       if (1.0 - x[nbSeg] < Precision::Confusion())
477         break;
478
479       // not ok ...
480
481       x1_too_small = x1;
482
483       // Modify x1 value
484
485       if (x1_too_large > 1e100)
486         x1 = 2*x1;
487       else
488         x1 = (x1_too_small+x1_too_large)/2;
489     }
490     xxx[rev] = x;
491   }
492
493   // average
494   vector<double> x(nbPnt, 0.);
495   for (i=0; i < nbPnt; i++)
496     x[i] = (xxx[0][i] + (1.0 - xxx[1][nbPnt-i])) / 2;
497
498   // apply parameters in range [0,1] to the space of the curve
499   double prevU = first;
500   double sign = 1.;
501   if (theReverse)
502   {
503     prevU = last;
504     sign = -1.;
505   }
506   for (i = 1; i < nbSeg; i++)
507   {
508     double curvLength = length * (x[i] - x[i-1]) * sign;
509     GCPnts_AbscissaPoint Discret( C3d, curvLength, prevU );
510     if ( !Discret.IsDone() )
511       return false;
512     double U = Discret.Parameter();
513     if ( U > first && U < last )
514       theParams.push_back( U );
515     else
516       return false;
517     prevU = U;
518   }
519   return false;
520 }
521
522 //=============================================================================
523 /*!
524  *  
525  */
526 //=============================================================================
527 bool StdMeshers_Regular_1D::computeInternalParameters(const TopoDS_Edge& theEdge,
528                                                       list<double> &     theParams,
529                                                       const bool         theReverse) const
530 {
531   theParams.clear();
532
533   double f, l;
534   Handle(Geom_Curve) Curve = BRep_Tool::Curve(theEdge, f, l);
535   GeomAdaptor_Curve C3d(Curve);
536
537   double length = EdgeLength(theEdge);
538
539   switch( _hypType )
540   {
541   case LOCAL_LENGTH:
542   case NB_SEGMENTS: {
543
544     double eltSize = 1;
545     if ( _hypType == LOCAL_LENGTH )
546     {
547       // Local Length hypothesis
548       double nbseg = ceil(length / _value[ BEG_LENGTH_IND ]); // integer sup
549       if (nbseg <= 0)
550         nbseg = 1;                        // degenerated edge
551       eltSize = length / nbseg;
552     }
553     else
554     {
555       // Number Of Segments hypothesis
556       switch (_ivalue[ DISTR_TYPE_IND ])
557       {
558       case StdMeshers_NumberOfSegments::DT_Scale:
559         {
560           double scale = _value[ SCALE_FACTOR_IND ];
561           if ( theReverse )
562             scale = 1. / scale;
563           double alpha = pow( scale , 1.0 / (_ivalue[ NB_SEGMENTS_IND ] - 1));
564           double factor = (l - f) / (1 - pow( alpha,_ivalue[ NB_SEGMENTS_IND ]));
565
566           int i, NbPoints = 1 + _ivalue[ NB_SEGMENTS_IND ];
567           for ( i = 2; i < NbPoints; i++ )
568           {
569             double param = f + factor * (1 - pow(alpha, i - 1));
570             theParams.push_back( param );
571           }
572           return true;
573         }
574         break;
575       case StdMeshers_NumberOfSegments::DT_TabFunc:
576         {
577           TabFunction func(_vvalue[ TAB_FUNC_IND ], (bool)_ivalue[ EXP_MODE_IND ]);
578           return computeParamByFunc(C3d, f, l, length, theReverse,
579                                     _ivalue[ NB_SEGMENTS_IND ], func,
580                                     theParams);
581         }
582         break;
583       case StdMeshers_NumberOfSegments::DT_ExprFunc:
584         {
585           ExprFunction func(_svalue[ EXPR_FUNC_IND ].c_str(), (bool)_ivalue[ EXP_MODE_IND ]);
586           return computeParamByFunc(C3d, f, l, length, theReverse,
587                                     _ivalue[ NB_SEGMENTS_IND ], func,
588                                     theParams);
589         }
590         break;
591       case StdMeshers_NumberOfSegments::DT_Regular:
592         eltSize = length / _ivalue[ NB_SEGMENTS_IND ];
593         break;
594       default:
595         return false;
596       }
597     }
598
599     GCPnts_UniformAbscissa Discret(C3d, eltSize, f, l);
600     if ( !Discret.IsDone() )
601       return false;
602
603     int NbPoints = Discret.NbPoints();
604     for ( int i = 2; i < NbPoints; i++ )
605     {
606       double param = Discret.Parameter(i);
607       theParams.push_back( param );
608     }
609     return true;
610   }
611
612   case BEG_END_LENGTH: {
613
614     // geometric progression: SUM(n) = ( a1 - an * q ) / ( 1 - q ) = length
615
616     double a1 = _value[ BEG_LENGTH_IND ];
617     double an = _value[ END_LENGTH_IND ];
618     double q  = ( length - a1 ) / ( length - an );
619
620     double U1 = theReverse ? l : f;
621     double Un = theReverse ? f : l;
622     double param = U1;
623     double eltSize = theReverse ? -a1 : a1;
624     while ( 1 ) {
625       // computes a point on a curve <C3d> at the distance <eltSize>
626       // from the point of parameter <param>.
627       GCPnts_AbscissaPoint Discret( C3d, eltSize, param );
628       if ( !Discret.IsDone() ) break;
629       param = Discret.Parameter();
630       if ( param > f && param < l )
631         theParams.push_back( param );
632       else
633         break;
634       eltSize *= q;
635     }
636     compensateError( a1, an, U1, Un, length, C3d, theParams );
637     return true;
638   }
639
640   case ARITHMETIC_1D: {
641
642     // arithmetic progression: SUM(n) = ( an - a1 + q ) * ( a1 + an ) / ( 2 * q ) = length
643
644     double a1 = _value[ BEG_LENGTH_IND ];
645     double an = _value[ END_LENGTH_IND ];
646
647     double  q = ( an - a1 ) / ( 2 *length/( a1 + an ) - 1 );
648     int     n = int( 1 + ( an - a1 ) / q );
649
650     double U1 = theReverse ? l : f;
651     double Un = theReverse ? f : l;
652     double param = U1;
653     double eltSize = a1;
654     if ( theReverse ) {
655       eltSize = -eltSize;
656       q = -q;
657     }
658     while ( n-- > 0 && eltSize * ( Un - U1 ) > 0 ) {
659       // computes a point on a curve <C3d> at the distance <eltSize>
660       // from the point of parameter <param>.
661       GCPnts_AbscissaPoint Discret( C3d, eltSize, param );
662       if ( !Discret.IsDone() ) break;
663       param = Discret.Parameter();
664       if ( param > f && param < l )
665         theParams.push_back( param );
666       else
667         break;
668       eltSize += q;
669     }
670     compensateError( a1, an, U1, Un, length, C3d, theParams );
671
672     return true;
673   }
674
675   case DEFLECTION: {
676
677     GCPnts_UniformDeflection Discret(C3d, _value[ DEFLECTION_IND ], true);
678     if ( !Discret.IsDone() )
679       return false;
680
681     int NbPoints = Discret.NbPoints();
682     for ( int i = 2; i < NbPoints; i++ )
683     {
684       double param = Discret.Parameter(i);
685       theParams.push_back( param );
686     }
687     return true;
688     
689   }
690
691   default:;
692   }
693
694   return false;
695 }
696
697 //=============================================================================
698 /*!
699  *  
700  */
701 //=============================================================================
702
703 bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape)
704 {
705   MESSAGE("StdMeshers_Regular_1D::Compute");
706
707   if ( _hypType == NONE )
708     return false;
709
710   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
711   aMesh.GetSubMesh(aShape);
712
713   const TopoDS_Edge & EE = TopoDS::Edge(aShape);
714   TopoDS_Edge E = TopoDS::Edge(EE.Oriented(TopAbs_FORWARD));
715   int shapeID = meshDS->ShapeToIndex( E );
716
717   double f, l;
718   Handle(Geom_Curve) Curve = BRep_Tool::Curve(E, f, l);
719
720   TopoDS_Vertex VFirst, VLast;
721   TopExp::Vertices(E, VFirst, VLast);   // Vfirst corresponds to f and Vlast to l
722
723   ASSERT(!VFirst.IsNull());
724   SMDS_NodeIteratorPtr lid= aMesh.GetSubMesh(VFirst)->GetSubMeshDS()->GetNodes();
725   if (!lid->more())
726   {
727     MESSAGE (" NO NODE BUILT ON VERTEX ");
728     return false;
729   }
730   const SMDS_MeshNode * idFirst = lid->next();
731
732   ASSERT(!VLast.IsNull());
733   lid=aMesh.GetSubMesh(VLast)->GetSubMeshDS()->GetNodes();
734   if (!lid->more())
735   {
736     MESSAGE (" NO NODE BUILT ON VERTEX ");
737     return false;
738   }
739   const SMDS_MeshNode * idLast = lid->next();
740
741   if (!Curve.IsNull())
742   {
743     list< double > params;
744     bool reversed = false;
745     if ( !_mainEdge.IsNull() )
746       reversed = aMesh.IsReversedInChain( EE, _mainEdge );
747     try {
748       if ( ! computeInternalParameters( E, params, reversed ))
749         return false;
750     }
751     catch ( Standard_Failure ) {
752       return false;
753     }
754
755     // edge extrema (indexes : 1 & NbPoints) already in SMDS (TopoDS_Vertex)
756     // only internal nodes receive an edge position with param on curve
757
758     const SMDS_MeshNode * idPrev = idFirst;
759     
760     for (list<double>::iterator itU = params.begin(); itU != params.end(); itU++)
761     {
762       double param = *itU;
763       gp_Pnt P = Curve->Value(param);
764
765       //Add the Node in the DataStructure
766       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
767       meshDS->SetNodeOnEdge(node, shapeID, param);
768
769       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
770       meshDS->SetMeshElementOnShape(edge, shapeID);
771       idPrev = node;
772     }
773     SMDS_MeshEdge* edge = meshDS->AddEdge(idPrev, idLast);
774     meshDS->SetMeshElementOnShape(edge, shapeID);
775   }
776   else
777   {
778     // Edge is a degenerated Edge : We put n = 5 points on the edge.
779     int NbPoints = 5;
780     BRep_Tool::Range(E, f, l);
781     double du = (l - f) / (NbPoints - 1);
782     //MESSAGE("************* Degenerated edge! *****************");
783
784     TopoDS_Vertex V1, V2;
785     TopExp::Vertices(E, V1, V2);
786     gp_Pnt P = BRep_Tool::Pnt(V1);
787
788     const SMDS_MeshNode * idPrev = idFirst;
789     for (int i = 2; i < NbPoints; i++)
790     {
791       double param = f + (i - 1) * du;
792       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
793       meshDS->SetNodeOnEdge(node, shapeID, param);
794
795       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
796       meshDS->SetMeshElementOnShape(edge, shapeID);
797       idPrev = node;
798     }
799     SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast);
800     meshDS->SetMeshElementOnShape(edge, shapeID);
801   }
802   return true;
803 }
804
805 //=============================================================================
806 /*!
807  *  See comments in SMESH_Algo.cxx
808  */
809 //=============================================================================
810
811 const list <const SMESHDS_Hypothesis *> & StdMeshers_Regular_1D::GetUsedHypothesis(
812         SMESH_Mesh & aMesh, const TopoDS_Shape & aShape)
813 {
814   _usedHypList.clear();
815   _usedHypList = GetAppliedHypothesis(aMesh, aShape);   // copy
816   int nbHyp = _usedHypList.size();
817   _mainEdge.Nullify();
818   if (nbHyp == 0)
819   {
820     // Check, if propagated from some other edge
821     if (aShape.ShapeType() == TopAbs_EDGE &&
822         aMesh.IsPropagatedHypothesis(aShape, _mainEdge))
823     {
824       // Propagation of 1D hypothesis from <aMainEdge> on this edge
825       //_usedHypList = GetAppliedHypothesis(aMesh, _mainEdge);  // copy
826       // use a general method in order not to nullify _mainEdge
827       _usedHypList = SMESH_Algo::GetUsedHypothesis(aMesh, _mainEdge);   // copy
828       nbHyp = _usedHypList.size();
829     }
830   }
831   if (nbHyp == 0)
832   {
833     TopTools_ListIteratorOfListOfShape ancIt( aMesh.GetAncestors( aShape ));
834     for (; ancIt.More(); ancIt.Next())
835     {
836       const TopoDS_Shape& ancestor = ancIt.Value();
837       _usedHypList = GetAppliedHypothesis(aMesh, ancestor);     // copy
838       nbHyp = _usedHypList.size();
839       if (nbHyp == 1)
840         break;
841     }
842   }
843   if (nbHyp > 1)
844     _usedHypList.clear();       //only one compatible hypothesis allowed
845   return _usedHypList;
846 }
847
848 //=============================================================================
849 /*!
850  *  
851  */
852 //=============================================================================
853
854 ostream & StdMeshers_Regular_1D::SaveTo(ostream & save)
855 {
856   return save;
857 }
858
859 //=============================================================================
860 /*!
861  *  
862  */
863 //=============================================================================
864
865 istream & StdMeshers_Regular_1D::LoadFrom(istream & load)
866 {
867   return load;
868 }
869
870 //=============================================================================
871 /*!
872  *  
873  */
874 //=============================================================================
875
876 ostream & operator <<(ostream & save, StdMeshers_Regular_1D & hyp)
877 {
878   return hyp.SaveTo( save );
879 }
880
881 //=============================================================================
882 /*!
883  *  
884  */
885 //=============================================================================
886
887 istream & operator >>(istream & load, StdMeshers_Regular_1D & hyp)
888 {
889   return hyp.LoadFrom( load );
890 }