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