Salome HOME
Join modifications from branch BR_For_OCT_611: migration to OCCT6.1.1 with new except...
[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.salome-platform.org/ or email : webmaster.salome@opencascade.com
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 "StdMeshers_Distribution.hxx"
34
35 #include "StdMeshers_LocalLength.hxx"
36 #include "StdMeshers_NumberOfSegments.hxx"
37 #include "StdMeshers_Arithmetic1D.hxx"
38 #include "StdMeshers_StartEndLength.hxx"
39 #include "StdMeshers_Deflection1D.hxx"
40 #include "StdMeshers_AutomaticLength.hxx"
41
42 #include "SMESH_Gen.hxx"
43 #include "SMESH_Mesh.hxx"
44 #include "SMESH_HypoFilter.hxx"
45 #include "SMESH_subMesh.hxx"
46
47 #include "SMDS_MeshElement.hxx"
48 #include "SMDS_MeshNode.hxx"
49 #include "SMDS_EdgePosition.hxx"
50
51 #include "Utils_SALOME_Exception.hxx"
52 #include "utilities.h"
53
54 #include <BRep_Tool.hxx>
55 #include <TopoDS_Edge.hxx>
56 #include <TopoDS_Shape.hxx>
57 #include <TopTools_ListIteratorOfListOfShape.hxx>
58 #include <GeomAdaptor_Curve.hxx>
59 #include <GCPnts_AbscissaPoint.hxx>
60 #include <GCPnts_UniformAbscissa.hxx>
61 #include <GCPnts_UniformDeflection.hxx>
62 #include <Precision.hxx>
63 #include <Expr_GeneralExpression.hxx>
64 #include <Expr_NamedUnknown.hxx>
65 #include <Expr_Array1OfNamedUnknown.hxx>
66 #include <ExprIntrp_GenExp.hxx>
67 #include <TColStd_Array1OfReal.hxx>
68 #include <OSD.hxx>
69
70 #include <Standard_ErrorHandler.hxx>
71 #include <Standard_Failure.hxx>
72
73 #include <string>
74 #include <math.h>
75
76 using namespace std;
77
78 //=============================================================================
79 /*!
80  *  
81  */
82 //=============================================================================
83
84 StdMeshers_Regular_1D::StdMeshers_Regular_1D(int hypId, int studyId,
85         SMESH_Gen * gen):SMESH_1D_Algo(hypId, studyId, gen)
86 {
87         MESSAGE("StdMeshers_Regular_1D::StdMeshers_Regular_1D");
88         _name = "Regular_1D";
89         _shapeType = (1 << TopAbs_EDGE);
90
91         _compatibleHypothesis.push_back("LocalLength");
92         _compatibleHypothesis.push_back("NumberOfSegments");
93         _compatibleHypothesis.push_back("StartEndLength");
94         _compatibleHypothesis.push_back("Deflection1D");
95         _compatibleHypothesis.push_back("Arithmetic1D");
96         _compatibleHypothesis.push_back("AutomaticLength");
97
98         _compatibleHypothesis.push_back("QuadraticMesh"); // auxiliary !!!
99 }
100
101 //=============================================================================
102 /*!
103  *  
104  */
105 //=============================================================================
106
107 StdMeshers_Regular_1D::~StdMeshers_Regular_1D()
108 {
109 }
110
111 //=============================================================================
112 /*!
113  *  
114  */
115 //=============================================================================
116
117 bool StdMeshers_Regular_1D::CheckHypothesis
118                          (SMESH_Mesh&                          aMesh,
119                           const TopoDS_Shape&                  aShape,
120                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
121 {
122   _hypType = NONE;
123   _quadraticMesh = false;
124
125   const bool ignoreAuxiliaryHyps = false;
126   const list <const SMESHDS_Hypothesis * > & hyps =
127     GetUsedHypothesis(aMesh, aShape, ignoreAuxiliaryHyps);
128
129   // find non-auxiliary hypothesis
130   const SMESHDS_Hypothesis *theHyp = 0;
131   list <const SMESHDS_Hypothesis * >::const_iterator h = hyps.begin();
132   for ( ; h != hyps.end(); ++h ) {
133     if ( static_cast<const SMESH_Hypothesis*>(*h)->IsAuxiliary() ) {
134       if ( strcmp( "QuadraticMesh", (*h)->GetName() ) == 0 )
135         _quadraticMesh = true;
136     }
137     else {
138       if ( !theHyp )
139         theHyp = *h; // use only the first non-auxiliary hypothesis
140     }
141   }
142
143   if ( !theHyp )
144   {
145     aStatus = SMESH_Hypothesis::HYP_MISSING;
146     return false;  // can't work without a hypothesis
147   }
148
149   string hypName = theHyp->GetName();
150
151   if (hypName == "LocalLength")
152   {
153     const StdMeshers_LocalLength * hyp =
154       dynamic_cast <const StdMeshers_LocalLength * >(theHyp);
155     ASSERT(hyp);
156     _value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength();
157     ASSERT( _value[ BEG_LENGTH_IND ] > 0 );
158     _hypType = LOCAL_LENGTH;
159     aStatus = SMESH_Hypothesis::HYP_OK;
160   }
161
162   else if (hypName == "NumberOfSegments")
163   {
164     const StdMeshers_NumberOfSegments * hyp =
165       dynamic_cast <const StdMeshers_NumberOfSegments * >(theHyp);
166     ASSERT(hyp);
167     _ivalue[ NB_SEGMENTS_IND  ] = hyp->GetNumberOfSegments();
168     ASSERT( _ivalue[ NB_SEGMENTS_IND ] > 0 );
169     _ivalue[ DISTR_TYPE_IND ] = (int) hyp->GetDistrType();
170     switch (_ivalue[ DISTR_TYPE_IND ])
171     {
172     case StdMeshers_NumberOfSegments::DT_Scale:
173       _value[ SCALE_FACTOR_IND ] = hyp->GetScaleFactor();
174       break;
175     case StdMeshers_NumberOfSegments::DT_TabFunc:
176       _vvalue[ TAB_FUNC_IND ] = hyp->GetTableFunction();
177       break;
178     case StdMeshers_NumberOfSegments::DT_ExprFunc:
179       _svalue[ EXPR_FUNC_IND ] = hyp->GetExpressionFunction();
180       break;
181     case StdMeshers_NumberOfSegments::DT_Regular:
182       break;
183     default:
184       ASSERT(0);
185       break;
186     }
187     if (_ivalue[ DISTR_TYPE_IND ] == StdMeshers_NumberOfSegments::DT_TabFunc ||
188         _ivalue[ DISTR_TYPE_IND ] == StdMeshers_NumberOfSegments::DT_ExprFunc)
189         _ivalue[ CONV_MODE_IND ] = hyp->ConversionMode();
190     _hypType = NB_SEGMENTS;
191     aStatus = SMESH_Hypothesis::HYP_OK;
192   }
193
194   else if (hypName == "Arithmetic1D")
195   {
196     const StdMeshers_Arithmetic1D * hyp =
197       dynamic_cast <const StdMeshers_Arithmetic1D * >(theHyp);
198     ASSERT(hyp);
199     _value[ BEG_LENGTH_IND ] = hyp->GetLength( true );
200     _value[ END_LENGTH_IND ] = hyp->GetLength( false );
201     ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 );
202     _hypType = ARITHMETIC_1D;
203     aStatus = SMESH_Hypothesis::HYP_OK;
204   }
205
206   else if (hypName == "StartEndLength")
207   {
208     const StdMeshers_StartEndLength * hyp =
209       dynamic_cast <const StdMeshers_StartEndLength * >(theHyp);
210     ASSERT(hyp);
211     _value[ BEG_LENGTH_IND ] = hyp->GetLength( true );
212     _value[ END_LENGTH_IND ] = hyp->GetLength( false );
213     ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 );
214     _hypType = BEG_END_LENGTH;
215     aStatus = SMESH_Hypothesis::HYP_OK;
216   }
217
218   else if (hypName == "Deflection1D")
219   {
220     const StdMeshers_Deflection1D * hyp =
221       dynamic_cast <const StdMeshers_Deflection1D * >(theHyp);
222     ASSERT(hyp);
223     _value[ DEFLECTION_IND ] = hyp->GetDeflection();
224     ASSERT( _value[ DEFLECTION_IND ] > 0 );
225     _hypType = DEFLECTION;
226     aStatus = SMESH_Hypothesis::HYP_OK;
227   }
228
229   else if (hypName == "AutomaticLength")
230   {
231     StdMeshers_AutomaticLength * hyp = const_cast<StdMeshers_AutomaticLength *>
232       (dynamic_cast <const StdMeshers_AutomaticLength * >(theHyp));
233     ASSERT(hyp);
234     _value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape );
235     ASSERT( _value[ BEG_LENGTH_IND ] > 0 );
236     _hypType = LOCAL_LENGTH;
237     aStatus = SMESH_Hypothesis::HYP_OK;
238   }
239   else
240     aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
241
242   return ( _hypType != NONE );
243 }
244
245 //=======================================================================
246 //function : compensateError
247 //purpose  : adjust theParams so that the last segment length == an
248 //=======================================================================
249
250 static void compensateError(double a1, double an,
251                             double U1, double Un,
252                             double             length,
253                             GeomAdaptor_Curve& C3d,
254                             list<double> &     theParams)
255 {
256   int i, nPar = theParams.size();
257   if ( a1 + an < length && nPar > 1 )
258   {
259     list<double>::reverse_iterator itU = theParams.rbegin();
260     double Ul = *itU++;
261     // dist from the last point to the edge end <Un>, it should be equal <an>
262     double Ln = GCPnts_AbscissaPoint::Length( C3d, Ul, Un );
263     double dLn = an - Ln; // error of <an>
264     if ( Abs( dLn ) <= Precision::Confusion() )
265       return;
266     double dU = Abs( Ul - *itU ); // parametric length of the last but one segment
267     double dUn = dLn * Abs( Un - U1 ) / length; // parametric error of <an>
268     if ( dUn < 0.5 * dU ) { // last segment is a bit shorter than it should
269       dUn = -dUn; // move the last parameter to the edge beginning
270     }
271     else {  // last segment is much shorter than it should -> remove the last param and
272       theParams.pop_back(); nPar--; // move the rest points toward the edge end
273       Ln = GCPnts_AbscissaPoint::Length( C3d, theParams.back(), Un );
274       dUn = ( an - Ln ) * Abs( Un - U1 ) / length;
275       if ( dUn < 0.5 * dU )
276         dUn = -dUn;
277     }
278     if ( U1 > Un )
279       dUn = -dUn;
280     double q  = dUn / ( nPar - 1 );
281     for ( itU = theParams.rbegin(), i = 1; i < nPar; itU++, i++ ) {
282       (*itU) += dUn;
283       dUn -= q;
284     }
285   }
286 }
287
288 static bool computeParamByFunc(Adaptor3d_Curve& C3d, double first, double last,
289                                double length, bool theReverse, 
290                                int nbSeg, Function& func,
291                                list<double>& theParams)
292 {
293   // never do this way
294   //OSD::SetSignal( true );
295
296   if( nbSeg<=0 )
297     return false;
298
299   MESSAGE( "computeParamByFunc" );
300
301   int nbPnt = 1 + nbSeg;
302   vector<double> x(nbPnt, 0.);
303
304   if( !buildDistribution( func, 0.0, 1.0, nbSeg, x, 1E-4 ) )
305      return false;
306
307   MESSAGE( "Points:\n" );
308   char buf[1024];
309   for( int i=0; i<=nbSeg; i++ )
310   {
311     sprintf(  buf, "%f\n", float(x[i] ) );
312     MESSAGE( buf );
313   }
314     
315
316
317   // apply parameters in range [0,1] to the space of the curve
318   double prevU = first;
319   double sign = 1.;
320   if (theReverse)
321   {
322     prevU = last;
323     sign = -1.;
324   }
325   for( int i = 1; i < nbSeg; i++ )
326   {
327     double curvLength = length * (x[i] - x[i-1]) * sign;
328     GCPnts_AbscissaPoint Discret( C3d, curvLength, prevU );
329     if ( !Discret.IsDone() )
330       return false;
331     double U = Discret.Parameter();
332     if ( U > first && U < last )
333       theParams.push_back( U );
334     else
335       return false;
336     prevU = U;
337   }
338   return true;
339 }
340
341 //=============================================================================
342 /*!
343  *  
344  */
345 //=============================================================================
346 bool StdMeshers_Regular_1D::computeInternalParameters(const TopoDS_Edge& theEdge,
347                                                       list<double> &     theParams,
348                                                       const bool         theReverse) const
349 {
350   theParams.clear();
351
352   double f, l;
353   Handle(Geom_Curve) Curve = BRep_Tool::Curve(theEdge, f, l);
354   GeomAdaptor_Curve C3d (Curve, f, l);
355
356   double length = EdgeLength(theEdge);
357
358   switch( _hypType )
359   {
360   case LOCAL_LENGTH:
361   case NB_SEGMENTS: {
362
363     double eltSize = 1;
364     if ( _hypType == LOCAL_LENGTH )
365     {
366       // Local Length hypothesis
367       double nbseg = ceil(length / _value[ BEG_LENGTH_IND ]); // integer sup
368       if (nbseg <= 0)
369         nbseg = 1;                        // degenerated edge
370       eltSize = length / nbseg;
371     }
372     else
373     {
374       // Number Of Segments hypothesis
375       int NbSegm = _ivalue[ NB_SEGMENTS_IND ];
376       if ( NbSegm < 1 )  return false;
377       if ( NbSegm == 1 ) return true;
378
379       switch (_ivalue[ DISTR_TYPE_IND ])
380       {
381       case StdMeshers_NumberOfSegments::DT_Scale:
382         {
383           double scale = _value[ SCALE_FACTOR_IND ];
384
385           if (fabs(scale - 1.0) < Precision::Confusion()) {
386             // special case to avoid division on zero
387             for (int i = 1; i < NbSegm; i++) {
388               double param = f + (l - f) * i / NbSegm;
389               theParams.push_back( param );
390             }
391           } else {
392             // general case of scale distribution
393             if ( theReverse )
394               scale = 1.0 / scale;
395
396             double alpha = pow(scale, 1.0 / (NbSegm - 1));
397             double factor = (l - f) / (1.0 - pow(alpha, NbSegm));
398
399             for (int i = 1; i < NbSegm; i++) {
400               double param = f + factor * (1.0 - pow(alpha, i));
401               theParams.push_back( param );
402             }
403           }
404           return true;
405         }
406         break;
407       case StdMeshers_NumberOfSegments::DT_TabFunc:
408         {
409           FunctionTable func(_vvalue[ TAB_FUNC_IND ], _ivalue[ CONV_MODE_IND ]);
410           return computeParamByFunc(C3d, f, l, length, theReverse,
411                                     _ivalue[ NB_SEGMENTS_IND ], func,
412                                     theParams);
413         }
414         break;
415       case StdMeshers_NumberOfSegments::DT_ExprFunc:
416         {
417           FunctionExpr func(_svalue[ EXPR_FUNC_IND ].c_str(), _ivalue[ CONV_MODE_IND ]);
418           return computeParamByFunc(C3d, f, l, length, theReverse,
419                                     _ivalue[ NB_SEGMENTS_IND ], func,
420                                     theParams);
421         }
422         break;
423       case StdMeshers_NumberOfSegments::DT_Regular:
424         eltSize = length / _ivalue[ NB_SEGMENTS_IND ];
425         break;
426       default:
427         return false;
428       }
429     }
430     GCPnts_UniformAbscissa Discret(C3d, eltSize, f, l);
431     if ( !Discret.IsDone() )
432       return false;
433
434     int NbPoints = Discret.NbPoints();
435     for ( int i = 2; i < NbPoints; i++ )
436     {
437       double param = Discret.Parameter(i);
438       theParams.push_back( param );
439     }
440     compensateError( eltSize, eltSize, f, l, length, C3d, theParams ); // for PAL9899
441     return true;
442   }
443
444   case BEG_END_LENGTH: {
445
446     // geometric progression: SUM(n) = ( a1 - an * q ) / ( 1 - q ) = length
447
448     double a1 = _value[ BEG_LENGTH_IND ];
449     double an = _value[ END_LENGTH_IND ];
450     double q  = ( length - a1 ) / ( length - an );
451
452     double U1 = theReverse ? l : f;
453     double Un = theReverse ? f : l;
454     double param = U1;
455     double eltSize = theReverse ? -a1 : a1;
456     while ( 1 ) {
457       // computes a point on a curve <C3d> at the distance <eltSize>
458       // from the point of parameter <param>.
459       GCPnts_AbscissaPoint Discret( C3d, eltSize, param );
460       if ( !Discret.IsDone() ) break;
461       param = Discret.Parameter();
462       if ( param > f && param < l )
463         theParams.push_back( param );
464       else
465         break;
466       eltSize *= q;
467     }
468     compensateError( a1, an, U1, Un, length, C3d, theParams );
469     return true;
470   }
471
472   case ARITHMETIC_1D: {
473
474     // arithmetic progression: SUM(n) = ( an - a1 + q ) * ( a1 + an ) / ( 2 * q ) = length
475
476     double a1 = _value[ BEG_LENGTH_IND ];
477     double an = _value[ END_LENGTH_IND ];
478
479     double  q = ( an - a1 ) / ( 2 *length/( a1 + an ) - 1 );
480     int     n = int( 1 + ( an - a1 ) / q );
481
482     double U1 = theReverse ? l : f;
483     double Un = theReverse ? f : l;
484     double param = U1;
485     double eltSize = a1;
486     if ( theReverse ) {
487       eltSize = -eltSize;
488       q = -q;
489     }
490     while ( n-- > 0 && eltSize * ( Un - U1 ) > 0 ) {
491       // computes a point on a curve <C3d> at the distance <eltSize>
492       // from the point of parameter <param>.
493       GCPnts_AbscissaPoint Discret( C3d, eltSize, param );
494       if ( !Discret.IsDone() ) break;
495       param = Discret.Parameter();
496       if ( param > f && param < l )
497         theParams.push_back( param );
498       else
499         break;
500       eltSize += q;
501     }
502     compensateError( a1, an, U1, Un, length, C3d, theParams );
503
504     return true;
505   }
506
507   case DEFLECTION: {
508
509     GCPnts_UniformDeflection Discret(C3d, _value[ DEFLECTION_IND ], f, l, true);
510     if ( !Discret.IsDone() )
511       return false;
512
513     int NbPoints = Discret.NbPoints();
514     for ( int i = 2; i < NbPoints; i++ )
515     {
516       double param = Discret.Parameter(i);
517       theParams.push_back( param );
518     }
519     return true;
520     
521   }
522
523   default:;
524   }
525
526   return false;
527 }
528
529 //=============================================================================
530 /*!
531  *  
532  */
533 //=============================================================================
534
535 bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape)
536 {
537   MESSAGE("StdMeshers_Regular_1D::Compute");
538
539   if ( _hypType == NONE )
540     return false;
541
542   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
543   aMesh.GetSubMesh(aShape);
544
545   const TopoDS_Edge & EE = TopoDS::Edge(aShape);
546   TopoDS_Edge E = TopoDS::Edge(EE.Oriented(TopAbs_FORWARD));
547   int shapeID = meshDS->ShapeToIndex( E );
548
549   double f, l;
550   Handle(Geom_Curve) Curve = BRep_Tool::Curve(E, f, l);
551
552   TopoDS_Vertex VFirst, VLast;
553   TopExp::Vertices(E, VFirst, VLast);   // Vfirst corresponds to f and Vlast to l
554
555   ASSERT(!VFirst.IsNull());
556   SMDS_NodeIteratorPtr lid= aMesh.GetSubMesh(VFirst)->GetSubMeshDS()->GetNodes();
557   if (!lid->more())
558   {
559     MESSAGE (" NO NODE BUILT ON VERTEX ");
560     return false;
561   }
562   const SMDS_MeshNode * idFirst = lid->next();
563
564   ASSERT(!VLast.IsNull());
565   lid=aMesh.GetSubMesh(VLast)->GetSubMeshDS()->GetNodes();
566   if (!lid->more()) {
567     MESSAGE (" NO NODE BUILT ON VERTEX ");
568     return false;
569   }
570   const SMDS_MeshNode * idLast = lid->next();
571
572   if (!Curve.IsNull()) {
573     list< double > params;
574     bool reversed = false;
575     if ( !_mainEdge.IsNull() )
576       reversed = aMesh.IsReversedInChain( EE, _mainEdge );
577     try {
578 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
579       OCC_CATCH_SIGNALS;
580 #endif
581       if ( ! computeInternalParameters( E, params, reversed )) {
582         //cout << "computeInternalParameters() failed" <<endl;
583         return false;
584       }
585     }
586     catch ( Standard_Failure ) {
587       //cout << "computeInternalParameters() failed, Standard_Failure" <<endl;
588       return false;
589     }
590
591     // edge extrema (indexes : 1 & NbPoints) already in SMDS (TopoDS_Vertex)
592     // only internal nodes receive an edge position with param on curve
593
594     const SMDS_MeshNode * idPrev = idFirst;
595     double parPrev = f;
596     double parLast = l;
597 //     if(reversed) {
598 //       parPrev = l;
599 //       parLast = f;
600 //     }
601     
602     for (list<double>::iterator itU = params.begin(); itU != params.end(); itU++) {
603       double param = *itU;
604       gp_Pnt P = Curve->Value(param);
605
606       //Add the Node in the DataStructure
607       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
608       meshDS->SetNodeOnEdge(node, shapeID, param);
609
610       if(_quadraticMesh) {
611         // create medium node
612         double prm = ( parPrev + param )/2;
613         gp_Pnt PM = Curve->Value(prm);
614         SMDS_MeshNode * NM = meshDS->AddNode(PM.X(), PM.Y(), PM.Z());
615         meshDS->SetNodeOnEdge(NM, shapeID, prm);
616         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node, NM);
617         meshDS->SetMeshElementOnShape(edge, shapeID);
618       }
619       else {
620         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
621         meshDS->SetMeshElementOnShape(edge, shapeID);
622       }
623
624       idPrev = node;
625       parPrev = param;
626     }
627     if(_quadraticMesh) {
628       double prm = ( parPrev + parLast )/2;
629       gp_Pnt PM = Curve->Value(prm);
630       SMDS_MeshNode * NM = meshDS->AddNode(PM.X(), PM.Y(), PM.Z());
631       meshDS->SetNodeOnEdge(NM, shapeID, prm);
632       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast, NM);
633       meshDS->SetMeshElementOnShape(edge, shapeID);
634     }
635     else {
636       SMDS_MeshEdge* edge = meshDS->AddEdge(idPrev, idLast);
637       meshDS->SetMeshElementOnShape(edge, shapeID);
638     }
639   }
640   else {
641     // Edge is a degenerated Edge : We put n = 5 points on the edge.
642     const int NbPoints = 5;
643     BRep_Tool::Range(E, f, l);
644     double du = (l - f) / (NbPoints - 1);
645     //MESSAGE("************* Degenerated edge! *****************");
646
647     TopoDS_Vertex V1, V2;
648     TopExp::Vertices(E, V1, V2);
649     gp_Pnt P = BRep_Tool::Pnt(V1);
650
651     const SMDS_MeshNode * idPrev = idFirst;
652     for (int i = 2; i < NbPoints; i++) {
653       double param = f + (i - 1) * du;
654       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
655       if(_quadraticMesh) {
656         // create medium node
657         double prm = param - du/2.;
658         SMDS_MeshNode * NM = meshDS->AddNode(P.X(), P.Y(), P.Z());
659         meshDS->SetNodeOnEdge(NM, shapeID, prm);
660         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node, NM);
661         meshDS->SetMeshElementOnShape(edge, shapeID);
662       }
663       else {
664         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
665         meshDS->SetMeshElementOnShape(edge, shapeID);
666       }
667       meshDS->SetNodeOnEdge(node, shapeID, param);
668       idPrev = node;
669     }
670     if(_quadraticMesh) {
671       // create medium node
672       double prm = l - du/2.;
673       SMDS_MeshNode * NM = meshDS->AddNode(P.X(), P.Y(), P.Z());
674       meshDS->SetNodeOnEdge(NM, shapeID, prm);
675       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast, NM);
676       meshDS->SetMeshElementOnShape(edge, shapeID);
677     }
678     else {
679       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast);
680       meshDS->SetMeshElementOnShape(edge, shapeID);
681     }
682   }
683   return true;
684 }
685
686 //=============================================================================
687 /*!
688  *  See comments in SMESH_Algo.cxx
689  */
690 //=============================================================================
691
692 const list <const SMESHDS_Hypothesis *> &
693 StdMeshers_Regular_1D::GetUsedHypothesis(SMESH_Mesh &         aMesh,
694                                          const TopoDS_Shape & aShape,
695                                          const bool           ignoreAuxiliary)
696 {
697   _usedHypList.clear();
698   _mainEdge.Nullify();
699
700   SMESH_HypoFilter auxiliaryFilter, compatibleFilter;
701   auxiliaryFilter.Init( SMESH_HypoFilter::IsAuxiliary() );
702   const bool ignoreAux = true;
703   InitCompatibleHypoFilter( compatibleFilter, ignoreAux );
704
705   // get non-auxiliary assigned to aShape
706   int nbHyp = aMesh.GetHypotheses( aShape, compatibleFilter, _usedHypList, false );
707
708   if (nbHyp == 0)
709   {
710     // Check, if propagated from some other edge
711     if (aShape.ShapeType() == TopAbs_EDGE &&
712         aMesh.IsPropagatedHypothesis(aShape, _mainEdge))
713     {
714       // Propagation of 1D hypothesis from <aMainEdge> on this edge;
715       // get non-auxiliary assigned to _mainEdge
716       nbHyp = aMesh.GetHypotheses( _mainEdge, compatibleFilter, _usedHypList, true );
717     }
718   }
719
720   if (nbHyp == 0) // nothing propagated nor assigned to aShape
721   {
722     SMESH_Algo::GetUsedHypothesis( aMesh, aShape, ignoreAuxiliary );
723     nbHyp = _usedHypList.size();
724   }
725   else
726   {
727     // get auxiliary hyps from aShape
728     aMesh.GetHypotheses( aShape, auxiliaryFilter, _usedHypList, true );
729   }
730   if ( nbHyp > 1 && ignoreAuxiliary )
731     _usedHypList.clear(); //only one compatible non-auxiliary hypothesis allowed
732
733   return _usedHypList;
734 }
735
736 //=============================================================================
737 /*!
738  *  
739  */
740 //=============================================================================
741
742 ostream & StdMeshers_Regular_1D::SaveTo(ostream & save)
743 {
744   return save;
745 }
746
747 //=============================================================================
748 /*!
749  *  
750  */
751 //=============================================================================
752
753 istream & StdMeshers_Regular_1D::LoadFrom(istream & load)
754 {
755   return load;
756 }
757
758 //=============================================================================
759 /*!
760  *  
761  */
762 //=============================================================================
763
764 ostream & operator <<(ostream & save, StdMeshers_Regular_1D & hyp)
765 {
766   return hyp.SaveTo( save );
767 }
768
769 //=============================================================================
770 /*!
771  *  
772  */
773 //=============================================================================
774
775 istream & operator >>(istream & load, StdMeshers_Regular_1D & hyp)
776 {
777   return hyp.LoadFrom( load );
778 }