Salome HOME
7118e0a2160c9973c10c5ab2f747810daa275ada
[modules/smesh.git] / src / StdMeshers / StdMeshers_Regular_1D.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
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 //  File   : StdMeshers_Regular_1D.cxx
24 //           Moved here from SMESH_Regular_1D.cxx
25 //  Author : Paul RASCLE, EDF
26 //  Module : SMESH
27 //
28 #include "StdMeshers_Regular_1D.hxx"
29
30 #include "SMDS_MeshElement.hxx"
31 #include "SMDS_MeshNode.hxx"
32 #include "SMESH_Comment.hxx"
33 #include "SMESH_Gen.hxx"
34 #include "SMESH_HypoFilter.hxx"
35 #include "SMESH_Mesh.hxx"
36 #include "SMESH_subMesh.hxx"
37 #include "SMESH_subMeshEventListener.hxx"
38 #include "StdMeshers_Adaptive1D.hxx"
39 #include "StdMeshers_Arithmetic1D.hxx"
40 #include "StdMeshers_Geometric1D.hxx"
41 #include "StdMeshers_AutomaticLength.hxx"
42 #include "StdMeshers_Deflection1D.hxx"
43 #include "StdMeshers_Distribution.hxx"
44 #include "StdMeshers_FixedPoints1D.hxx"
45 #include "StdMeshers_LocalLength.hxx"
46 #include "StdMeshers_MaxLength.hxx"
47 #include "StdMeshers_NumberOfSegments.hxx"
48 #include "StdMeshers_Propagation.hxx"
49 #include "StdMeshers_SegmentLengthAroundVertex.hxx"
50 #include "StdMeshers_StartEndLength.hxx"
51
52 #include "Utils_SALOME_Exception.hxx"
53 #include "utilities.h"
54
55 #include <BRepAdaptor_Curve.hxx>
56 #include <BRep_Tool.hxx>
57 #include <GCPnts_AbscissaPoint.hxx>
58 #include <GCPnts_UniformAbscissa.hxx>
59 #include <GCPnts_UniformDeflection.hxx>
60 #include <Precision.hxx>
61 #include <TopExp.hxx>
62 #include <TopExp_Explorer.hxx>
63 #include <TopoDS.hxx>
64 #include <TopoDS_Edge.hxx>
65 #include <TopoDS_Vertex.hxx>
66
67 #include <string>
68 #include <limits>
69
70 using namespace std;
71 using namespace StdMeshers;
72
73 //=============================================================================
74 /*!
75  *
76  */
77 //=============================================================================
78
79 StdMeshers_Regular_1D::StdMeshers_Regular_1D(int         hypId,
80                                              int         studyId,
81                                              SMESH_Gen * gen)
82   :SMESH_1D_Algo( hypId, studyId, gen )
83 {
84   _name = "Regular_1D";
85   _shapeType = (1 << TopAbs_EDGE);
86   _fpHyp = 0;
87
88   _compatibleHypothesis.push_back("LocalLength");
89   _compatibleHypothesis.push_back("MaxLength");
90   _compatibleHypothesis.push_back("NumberOfSegments");
91   _compatibleHypothesis.push_back("StartEndLength");
92   _compatibleHypothesis.push_back("Deflection1D");
93   _compatibleHypothesis.push_back("Arithmetic1D");
94   _compatibleHypothesis.push_back("GeometricProgression");
95   _compatibleHypothesis.push_back("FixedPoints1D");
96   _compatibleHypothesis.push_back("AutomaticLength");
97   _compatibleHypothesis.push_back("Adaptive1D");
98   // auxiliary:
99   _compatibleHypothesis.push_back("QuadraticMesh");
100   _compatibleHypothesis.push_back("Propagation");
101   _compatibleHypothesis.push_back("PropagOfDistribution");
102 }
103
104 //=============================================================================
105 /*!
106  *
107  */
108 //=============================================================================
109
110 StdMeshers_Regular_1D::~StdMeshers_Regular_1D()
111 {
112 }
113
114 //=============================================================================
115 /*!
116  *
117  */
118 //=============================================================================
119
120 bool StdMeshers_Regular_1D::CheckHypothesis( SMESH_Mesh&         aMesh,
121                                              const TopoDS_Shape& aShape,
122                                              Hypothesis_Status&  aStatus )
123 {
124   _hypType = NONE;
125   _quadraticMesh = false;
126   _onlyUnaryInput = true;
127
128   const list <const SMESHDS_Hypothesis * > & hyps =
129     GetUsedHypothesis(aMesh, aShape, /*ignoreAuxiliaryHyps=*/false);
130
131   const SMESH_HypoFilter & propagFilter = StdMeshers_Propagation::GetFilter();
132
133   // find non-auxiliary hypothesis
134   const SMESHDS_Hypothesis *theHyp = 0;
135   set< string > propagTypes;
136   list <const SMESHDS_Hypothesis * >::const_iterator h = hyps.begin();
137   for ( ; h != hyps.end(); ++h ) {
138     if ( static_cast<const SMESH_Hypothesis*>(*h)->IsAuxiliary() ) {
139       if ( strcmp( "QuadraticMesh", (*h)->GetName() ) == 0 )
140         _quadraticMesh = true;
141       if ( propagFilter.IsOk( static_cast< const SMESH_Hypothesis*>( *h ), aShape ))
142         propagTypes.insert( (*h)->GetName() );
143     }
144     else {
145       if ( !theHyp )
146         theHyp = *h; // use only the first non-auxiliary hypothesis
147     }
148   }
149
150   if ( !theHyp )
151   {
152     aStatus = SMESH_Hypothesis::HYP_MISSING;
153     return false;  // can't work without a hypothesis
154   }
155
156   string hypName = theHyp->GetName();
157
158   if ( hypName == "LocalLength" )
159   {
160     const StdMeshers_LocalLength * hyp =
161       dynamic_cast <const StdMeshers_LocalLength * >(theHyp);
162     ASSERT(hyp);
163     _value[ BEG_LENGTH_IND ] = hyp->GetLength();
164     _value[ PRECISION_IND ] = hyp->GetPrecision();
165     ASSERT( _value[ BEG_LENGTH_IND ] > 0 );
166     _hypType = LOCAL_LENGTH;
167     aStatus = SMESH_Hypothesis::HYP_OK;
168   }
169
170   else if ( hypName == "MaxLength" )
171   {
172     const StdMeshers_MaxLength * hyp =
173       dynamic_cast <const StdMeshers_MaxLength * >(theHyp);
174     ASSERT(hyp);
175     _value[ BEG_LENGTH_IND ] = hyp->GetLength();
176     if ( hyp->GetUsePreestimatedLength() ) {
177       if ( int nbSeg = aMesh.GetGen()->GetBoundaryBoxSegmentation() )
178         _value[ BEG_LENGTH_IND ] = aMesh.GetShapeDiagonalSize() / nbSeg;
179     }
180     ASSERT( _value[ BEG_LENGTH_IND ] > 0 );
181     _hypType = MAX_LENGTH;
182     aStatus = SMESH_Hypothesis::HYP_OK;
183   }
184
185   else if ( hypName == "NumberOfSegments" )
186   {
187     const StdMeshers_NumberOfSegments * hyp =
188       dynamic_cast <const StdMeshers_NumberOfSegments * >(theHyp);
189     ASSERT(hyp);
190     _ivalue[ NB_SEGMENTS_IND  ] = hyp->GetNumberOfSegments();
191     ASSERT( _ivalue[ NB_SEGMENTS_IND ] > 0 );
192     _ivalue[ DISTR_TYPE_IND ] = (int) hyp->GetDistrType();
193     switch (_ivalue[ DISTR_TYPE_IND ])
194     {
195     case StdMeshers_NumberOfSegments::DT_Scale:
196       _value[ SCALE_FACTOR_IND ] = hyp->GetScaleFactor();
197       _revEdgesIDs = hyp->GetReversedEdges();
198       break;
199     case StdMeshers_NumberOfSegments::DT_TabFunc:
200       _vvalue[ TAB_FUNC_IND ] = hyp->GetTableFunction();
201       _revEdgesIDs = hyp->GetReversedEdges();
202       break;
203     case StdMeshers_NumberOfSegments::DT_ExprFunc:
204       _svalue[ EXPR_FUNC_IND ] = hyp->GetExpressionFunction();
205       _revEdgesIDs = hyp->GetReversedEdges();
206       break;
207     case StdMeshers_NumberOfSegments::DT_Regular:
208       break;
209     default:
210       ASSERT(0);
211       break;
212     }
213     if (_ivalue[ DISTR_TYPE_IND ] == StdMeshers_NumberOfSegments::DT_TabFunc ||
214         _ivalue[ DISTR_TYPE_IND ] == StdMeshers_NumberOfSegments::DT_ExprFunc)
215         _ivalue[ CONV_MODE_IND ] = hyp->ConversionMode();
216     _hypType = NB_SEGMENTS;
217     aStatus = SMESH_Hypothesis::HYP_OK;
218   }
219
220   else if ( hypName == "Arithmetic1D" )
221   {
222     const StdMeshers_Arithmetic1D * hyp =
223       dynamic_cast <const StdMeshers_Arithmetic1D * >(theHyp);
224     ASSERT(hyp);
225     _value[ BEG_LENGTH_IND ] = hyp->GetLength( true );
226     _value[ END_LENGTH_IND ] = hyp->GetLength( false );
227     ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 );
228     _hypType = ARITHMETIC_1D;
229
230     _revEdgesIDs = hyp->GetReversedEdges();
231
232     aStatus = SMESH_Hypothesis::HYP_OK;
233   }
234
235   else if ( hypName == "GeometricProgression" )
236   {
237     const StdMeshers_Geometric1D * hyp =
238       dynamic_cast <const StdMeshers_Geometric1D * >(theHyp);
239     ASSERT(hyp);
240     _value[ BEG_LENGTH_IND ] = hyp->GetStartLength();
241     _value[ END_LENGTH_IND ] = hyp->GetCommonRatio();
242     ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 );
243     _hypType = GEOMETRIC_1D;
244
245     _revEdgesIDs = hyp->GetReversedEdges();
246
247     aStatus = SMESH_Hypothesis::HYP_OK;
248   }
249
250   else if ( hypName == "FixedPoints1D" ) {
251     _fpHyp = dynamic_cast <const StdMeshers_FixedPoints1D*>(theHyp);
252     ASSERT(_fpHyp);
253     _hypType = FIXED_POINTS_1D;
254
255     _revEdgesIDs = _fpHyp->GetReversedEdges();
256
257     aStatus = SMESH_Hypothesis::HYP_OK;
258   }
259
260   else if ( hypName == "StartEndLength" )
261   {
262     const StdMeshers_StartEndLength * hyp =
263       dynamic_cast <const StdMeshers_StartEndLength * >(theHyp);
264     ASSERT(hyp);
265     _value[ BEG_LENGTH_IND ] = hyp->GetLength( true );
266     _value[ END_LENGTH_IND ] = hyp->GetLength( false );
267     ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 );
268     _hypType = BEG_END_LENGTH;
269
270     _revEdgesIDs = hyp->GetReversedEdges();
271
272     aStatus = SMESH_Hypothesis::HYP_OK;
273   }
274
275   else if ( hypName == "Deflection1D" )
276   {
277     const StdMeshers_Deflection1D * hyp =
278       dynamic_cast <const StdMeshers_Deflection1D * >(theHyp);
279     ASSERT(hyp);
280     _value[ DEFLECTION_IND ] = hyp->GetDeflection();
281     ASSERT( _value[ DEFLECTION_IND ] > 0 );
282     _hypType = DEFLECTION;
283     aStatus = SMESH_Hypothesis::HYP_OK;
284   }
285
286   else if ( hypName == "AutomaticLength" )
287   {
288     StdMeshers_AutomaticLength * hyp = const_cast<StdMeshers_AutomaticLength *>
289       (dynamic_cast <const StdMeshers_AutomaticLength * >(theHyp));
290     ASSERT(hyp);
291     _value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape );
292     ASSERT( _value[ BEG_LENGTH_IND ] > 0 );
293     _hypType = MAX_LENGTH;
294     aStatus = SMESH_Hypothesis::HYP_OK;
295   }
296   else if ( hypName == "Adaptive1D" )
297   {
298     _adaptiveHyp = dynamic_cast < const StdMeshers_Adaptive1D* >(theHyp);
299     ASSERT(_adaptiveHyp);
300     _hypType = ADAPTIVE;
301     _onlyUnaryInput = false;
302     aStatus = SMESH_Hypothesis::HYP_OK;
303   }
304   else
305   {
306     aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
307   }
308
309   if ( propagTypes.size() > 1 && aStatus == HYP_OK )
310   {
311     // detect concurrent Propagation hyps
312     _usedHypList.clear();
313     list< TopoDS_Shape > assignedTo;
314     if ( aMesh.GetHypotheses( aShape, propagFilter, _usedHypList, true, &assignedTo ) > 1 )
315     {
316       // find most simple shape and a hyp on it
317       int simpleShape = TopAbs_COMPOUND;
318       const SMESHDS_Hypothesis* localHyp = 0;
319       list< TopoDS_Shape >::iterator            shape = assignedTo.begin();
320       list< const SMESHDS_Hypothesis *>::iterator hyp = _usedHypList.begin();
321       for ( ; shape != assignedTo.end(); ++shape )
322         if ( shape->ShapeType() > simpleShape )
323         {
324           simpleShape = shape->ShapeType();
325           localHyp = (*hyp);
326         }
327       // check if there a different hyp on simpleShape
328       shape = assignedTo.begin();
329       hyp = _usedHypList.begin();
330       for ( ; hyp != _usedHypList.end(); ++hyp, ++shape )
331         if ( shape->ShapeType() == simpleShape &&
332              !localHyp->IsSameName( **hyp ))
333         {
334           aStatus = HYP_INCOMPAT_HYPS;
335           return error( SMESH_Comment("Hypotheses of both \"")
336                         << StdMeshers_Propagation::GetName() << "\" and \""
337                         << StdMeshers_PropagOfDistribution::GetName()
338                         << "\" types can't be applied to the same edge");
339         }
340     }
341   }
342
343   return ( aStatus == SMESH_Hypothesis::HYP_OK );
344 }
345
346 static bool computeParamByFunc(Adaptor3d_Curve& C3d,
347                                double first, double last, double length,
348                                bool theReverse, int nbSeg, Function& func,
349                                list<double>& theParams)
350 {
351   // never do this way
352   //OSD::SetSignal( true );
353
354   if ( nbSeg <= 0 )
355     return false;
356
357   int nbPnt = 1 + nbSeg;
358   vector<double> x( nbPnt, 0. );
359
360   if ( !buildDistribution( func, 0.0, 1.0, nbSeg, x, 1E-4 ))
361      return false;
362
363   // apply parameters in range [0,1] to the space of the curve
364   double prevU = first;
365   double  sign = 1.;
366   if ( theReverse )
367   {
368     prevU = last;
369     sign  = -1.;
370   }
371
372   for ( int i = 1; i < nbSeg; i++ )
373   {
374     double curvLength = length * (x[i] - x[i-1]) * sign;
375     double tol        = Min( Precision::Confusion(), curvLength / 100. );
376     GCPnts_AbscissaPoint Discret( tol, C3d, curvLength, prevU );
377     if ( !Discret.IsDone() )
378       return false;
379     double U = Discret.Parameter();
380     if ( U > first && U < last )
381       theParams.push_back( U );
382     else
383       return false;
384     prevU = U;
385   }
386   if ( theReverse )
387     theParams.reverse();
388   return true;
389 }
390
391
392 //================================================================================
393 /*!
394  * \brief adjust internal node parameters so that the last segment length == an
395   * \param a1 - the first segment length
396   * \param an - the last segment length
397   * \param U1 - the first edge parameter
398   * \param Un - the last edge parameter
399   * \param length - the edge length
400   * \param C3d - the edge curve
401   * \param theParams - internal node parameters to adjust
402   * \param adjustNeighbors2an - to adjust length of segments next to the last one
403   *  and not to remove parameters
404  */
405 //================================================================================
406
407 static void compensateError(double a1, double an,
408                             double U1, double Un,
409                             double            length,
410                             Adaptor3d_Curve&  C3d,
411                             list<double> &    theParams,
412                             bool              adjustNeighbors2an = false)
413 {
414   int i, nPar = theParams.size();
415   if ( a1 + an <= length && nPar > 1 )
416   {
417     bool reverse = ( U1 > Un );
418     GCPnts_AbscissaPoint Discret(C3d, reverse ? an : -an, Un);
419     if ( !Discret.IsDone() )
420       return;
421     double Utgt = Discret.Parameter(); // target value of the last parameter
422     list<double>::reverse_iterator itU = theParams.rbegin();
423     double Ul = *itU++; // real value of the last parameter
424     double dUn = Utgt - Ul; // parametric error of <an>
425     if ( Abs(dUn) <= Precision::Confusion() )
426       return;
427     double dU = Abs( Ul - *itU ); // parametric length of the last but one segment
428     if ( adjustNeighbors2an || Abs(dUn) < 0.5 * dU ) { // last segment is a bit shorter than it should
429       // move the last parameter to the edge beginning
430     }
431     else {  // last segment is much shorter than it should -> remove the last param and
432       theParams.pop_back(); nPar--; // move the rest points toward the edge end
433       dUn = Utgt - theParams.back();
434     }
435
436     if ( !adjustNeighbors2an )
437     {
438       double q = dUn / ( Utgt - Un ); // (signed) factor of segment length change
439       for ( itU = theParams.rbegin(), i = 1; i < nPar; i++ ) {
440         double prevU = *itU;
441         (*itU) += dUn;
442         ++itU;
443         dUn = q * (*itU - prevU) * (prevU-U1)/(Un-U1);
444       }
445     }
446     else if ( nPar == 1 )
447     {
448       theParams.back() += dUn;
449     }
450     else
451     {
452       double q  = dUn / ( nPar - 1 );
453       theParams.back() += dUn;
454       double sign = reverse ? -1 : 1;
455       double prevU = theParams.back();
456       itU = theParams.rbegin();
457       for ( ++itU, i = 2; i < nPar; ++itU, i++ ) {
458         double newU = *itU + dUn;
459         if ( newU*sign < prevU*sign ) {
460           prevU = *itU = newU;
461           dUn -= q;
462         }
463         else { // set U between prevU and next valid param
464           list<double>::reverse_iterator itU2 = itU;
465           ++itU2;
466           int nb = 2;
467           while ( (*itU2)*sign > prevU*sign ) {
468             ++itU2; ++nb;
469           }
470           dU = ( *itU2 - prevU ) / nb;
471           while ( itU != itU2 ) {
472             *itU += dU; ++itU;
473           }
474           break;
475         }
476       }
477     }
478   }
479 }
480
481 //================================================================================
482 /*!
483  * \brief Class used to clean mesh on edges when 0D hyp modified.
484  * Common approach doesn't work when 0D algo is missing because the 0D hyp is
485  * considered as not participating in computation whereas it is used by 1D algo.
486  */
487 //================================================================================
488
489 // struct VertexEventListener : public SMESH_subMeshEventListener
490 // {
491 //   VertexEventListener():SMESH_subMeshEventListener(0) // won't be deleted by submesh
492 //   {}
493 //   /*!
494 //    * \brief Clean mesh on edges
495 //    * \param event - algo_event or compute_event itself (of SMESH_subMesh)
496 //    * \param eventType - ALGO_EVENT or COMPUTE_EVENT (of SMESH_subMesh)
497 //    * \param subMesh - the submesh where the event occures
498 //    */
499 //   void ProcessEvent(const int event, const int eventType, SMESH_subMesh* subMesh,
500 //                     EventListenerData*, const SMESH_Hypothesis*)
501 //   {
502 //     if ( eventType == SMESH_subMesh::ALGO_EVENT) // all algo events
503 //     {
504 //       subMesh->ComputeStateEngine( SMESH_subMesh::MODIF_ALGO_STATE );
505 //     }
506 //   }
507 // }; // struct VertexEventListener
508
509 //=============================================================================
510 /*!
511  * \brief Sets event listener to vertex submeshes
512  * \param subMesh - submesh where algo is set
513  *
514  * This method is called when a submesh gets HYP_OK algo_state.
515  * After being set, event listener is notified on each event of a submesh.
516  */
517 //=============================================================================
518
519 void StdMeshers_Regular_1D::SetEventListener(SMESH_subMesh* subMesh)
520 {
521   StdMeshers_Propagation::SetPropagationMgr( subMesh );
522 }
523
524 //=============================================================================
525 /*!
526  * \brief Do nothing
527  * \param subMesh - restored submesh
528  *
529  * This method is called only if a submesh has HYP_OK algo_state.
530  */
531 //=============================================================================
532
533 void StdMeshers_Regular_1D::SubmeshRestored(SMESH_subMesh* subMesh)
534 {
535 }
536
537 //=============================================================================
538 /*!
539  * \brief Return StdMeshers_SegmentLengthAroundVertex assigned to vertex
540  */
541 //=============================================================================
542
543 const StdMeshers_SegmentLengthAroundVertex*
544 StdMeshers_Regular_1D::getVertexHyp(SMESH_Mesh &          theMesh,
545                                     const TopoDS_Vertex & theV)
546 {
547   static SMESH_HypoFilter filter( SMESH_HypoFilter::HasName("SegmentAroundVertex_0D"));
548   if ( const SMESH_Hypothesis * h = theMesh.GetHypothesis( theV, filter, true ))
549   {
550     SMESH_Algo* algo = const_cast< SMESH_Algo* >( static_cast< const SMESH_Algo* > ( h ));
551     const list <const SMESHDS_Hypothesis *> & hypList = algo->GetUsedHypothesis( theMesh, theV, 0 );
552     if ( !hypList.empty() && string("SegmentLengthAroundVertex") == hypList.front()->GetName() )
553       return static_cast<const StdMeshers_SegmentLengthAroundVertex*>( hypList.front() );
554   }
555   return 0;
556 }
557
558 //================================================================================
559 /*!
560  * \brief Tune parameters to fit "SegmentLengthAroundVertex" hypothesis
561   * \param theC3d - wire curve
562   * \param theLength - curve length
563   * \param theParameters - internal nodes parameters to modify
564   * \param theVf - 1st vertex
565   * \param theVl - 2nd vertex
566  */
567 //================================================================================
568
569 void StdMeshers_Regular_1D::redistributeNearVertices (SMESH_Mesh &          theMesh,
570                                                       Adaptor3d_Curve &     theC3d,
571                                                       double                theLength,
572                                                       std::list< double > & theParameters,
573                                                       const TopoDS_Vertex & theVf,
574                                                       const TopoDS_Vertex & theVl)
575 {
576   double f = theC3d.FirstParameter(), l = theC3d.LastParameter();
577   int nPar = theParameters.size();
578   for ( int isEnd1 = 0; isEnd1 < 2; ++isEnd1 )
579   {
580     const TopoDS_Vertex & V = isEnd1 ? theVf : theVl;
581     const StdMeshers_SegmentLengthAroundVertex* hyp = getVertexHyp (theMesh, V );
582     if ( hyp ) {
583       double vertexLength = hyp->GetLength();
584       if ( vertexLength > theLength / 2.0 )
585         continue;
586       if ( isEnd1 ) { // to have a segment of interest at end of theParameters
587         theParameters.reverse();
588         std::swap( f, l );
589       }
590       if ( _hypType == NB_SEGMENTS )
591       {
592         compensateError(0, vertexLength, f, l, theLength, theC3d, theParameters, true );
593       }
594       else if ( nPar <= 3 )
595       {
596         if ( !isEnd1 )
597           vertexLength = -vertexLength;
598         GCPnts_AbscissaPoint Discret(theC3d, vertexLength, l);
599         if ( Discret.IsDone() ) {
600           if ( nPar == 0 )
601             theParameters.push_back( Discret.Parameter());
602           else {
603             double L = GCPnts_AbscissaPoint::Length( theC3d, theParameters.back(), l);
604             if ( vertexLength < L / 2.0 )
605               theParameters.push_back( Discret.Parameter());
606             else
607               compensateError(0, vertexLength, f, l, theLength, theC3d, theParameters, true );
608           }
609         }
610       }
611       else
612       {
613         // recompute params between the last segment and a middle one.
614         // find size of a middle segment
615         int nHalf = ( nPar-1 ) / 2;
616         list< double >::reverse_iterator itU = theParameters.rbegin();
617         std::advance( itU, nHalf );
618         double Um = *itU++;
619         double Lm = GCPnts_AbscissaPoint::Length( theC3d, Um, *itU);
620         double L = GCPnts_AbscissaPoint::Length( theC3d, *itU, l);
621         static StdMeshers_Regular_1D* auxAlgo = 0;
622         if ( !auxAlgo ) {
623           auxAlgo = new StdMeshers_Regular_1D( _gen->GetANewId(), _studyId, _gen );
624           auxAlgo->_hypType = BEG_END_LENGTH;
625         }
626         auxAlgo->_value[ BEG_LENGTH_IND ] = Lm;
627         auxAlgo->_value[ END_LENGTH_IND ] = vertexLength;
628         double from = *itU, to = l;
629         if ( isEnd1 ) {
630           std::swap( from, to );
631           std::swap( auxAlgo->_value[ BEG_LENGTH_IND ], auxAlgo->_value[ END_LENGTH_IND ]);
632         }
633         list<double> params;
634         if ( auxAlgo->computeInternalParameters( theMesh, theC3d, L, from, to, params, false ))
635         {
636           if ( isEnd1 ) params.reverse();
637           while ( 1 + nHalf-- )
638             theParameters.pop_back();
639           theParameters.splice( theParameters.end(), params );
640         }
641         else
642         {
643           compensateError(0, vertexLength, f, l, theLength, theC3d, theParameters, true );
644         }
645       }
646       if ( isEnd1 )
647         theParameters.reverse();
648     }
649   }
650 }
651
652 //=============================================================================
653 /*!
654  *  
655  */
656 //=============================================================================
657 bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh &     theMesh,
658                                                       Adaptor3d_Curve& theC3d,
659                                                       double           theLength,
660                                                       double           theFirstU,
661                                                       double           theLastU,
662                                                       list<double> &   theParams,
663                                                       const bool       theReverse,
664                                                       bool             theConsiderPropagation)
665 {
666   theParams.clear();
667
668   double f = theFirstU, l = theLastU;
669
670   // Propagation Of Distribution
671   //
672   if ( !_mainEdge.IsNull() && _isPropagOfDistribution )
673   {
674     TopoDS_Edge mainEdge = TopoDS::Edge( _mainEdge ); // should not be a reference!
675     _gen->Compute( theMesh, mainEdge, /*aShapeOnly=*/true, /*anUpward=*/true);
676
677     SMESHDS_SubMesh* smDS = theMesh.GetMeshDS()->MeshElements( mainEdge );
678     if ( !smDS )
679       return error("No mesh on the source edge of Propagation Of Distribution");
680     if ( smDS->NbNodes() < 1 )
681       return true; // 1 segment
682
683     map< double, const SMDS_MeshNode* > mainEdgeParamsOfNodes;
684     if ( ! SMESH_Algo::GetSortedNodesOnEdge( theMesh.GetMeshDS(), mainEdge, _quadraticMesh,
685                                              mainEdgeParamsOfNodes, SMDSAbs_Edge ))
686       return error("Bad node parameters on the source edge of Propagation Of Distribution");
687     vector< double > segLen( mainEdgeParamsOfNodes.size() - 1 );
688     double totalLen = 0;
689     BRepAdaptor_Curve mainEdgeCurve( mainEdge );
690     map< double, const SMDS_MeshNode* >::iterator
691       u_n2 = mainEdgeParamsOfNodes.begin(), u_n1 = u_n2++;
692     for ( size_t i = 1; i < mainEdgeParamsOfNodes.size(); ++i, ++u_n1, ++u_n2 )
693     {
694       segLen[ i-1 ] = GCPnts_AbscissaPoint::Length( mainEdgeCurve,
695                                                     u_n1->first,
696                                                     u_n2->first);
697       totalLen += segLen[ i-1 ];
698     }
699     for ( size_t i = 0; i < segLen.size(); ++i )
700       segLen[ i ] *= theLength / totalLen;
701
702     size_t  iSeg = theReverse ? segLen.size()-1 : 0;
703     size_t  dSeg = theReverse ? -1 : +1;
704     double param = theFirstU;
705     size_t nbParams = 0;
706     for ( int i = 0, nb = segLen.size()-1; i < nb; ++i, iSeg += dSeg )
707     {
708       GCPnts_AbscissaPoint Discret( theC3d, segLen[ iSeg ], param );
709       if ( !Discret.IsDone() ) break;
710       param = Discret.Parameter();
711       theParams.push_back( param );
712       ++nbParams;
713     }
714     if ( nbParams != segLen.size()-1 )
715       return error( SMESH_Comment("Can't divide into ") << segLen.size() << " segments");
716
717     compensateError( segLen[ theReverse ? segLen.size()-1 : 0 ],
718                      segLen[ theReverse ? 0 : segLen.size()-1 ],
719                      f, l, theLength, theC3d, theParams, true );
720     return true;
721   }
722
723
724   switch( _hypType )
725   {
726   case LOCAL_LENGTH:
727   case MAX_LENGTH:
728   case NB_SEGMENTS:
729   {
730     double eltSize = 1;
731     int nbSegments;
732     if ( _hypType == MAX_LENGTH )
733     {
734       double nbseg = ceil(theLength / _value[ BEG_LENGTH_IND ]); // integer sup
735       if (nbseg <= 0)
736         nbseg = 1;                        // degenerated edge
737       eltSize = theLength / nbseg;
738       nbSegments = (int) nbseg;
739     }
740     else if ( _hypType == LOCAL_LENGTH )
741     {
742       // Local Length hypothesis
743       double nbseg = ceil(theLength / _value[ BEG_LENGTH_IND ]); // integer sup
744
745       // NPAL17873:
746       bool isFound = false;
747       if (theConsiderPropagation && !_mainEdge.IsNull()) // propagated from some other edge
748       {
749         // Advanced processing to assure equal number of segments in case of Propagation
750         SMESH_subMesh* sm = theMesh.GetSubMeshContaining(_mainEdge);
751         if (sm) {
752           bool computed = sm->IsMeshComputed();
753           if (!computed) {
754             if (sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE) {
755               _gen->Compute( theMesh, _mainEdge, /*anUpward=*/true);
756               computed = sm->IsMeshComputed();
757             }
758           }
759           if (computed) {
760             SMESHDS_SubMesh* smds = sm->GetSubMeshDS();
761             int       nb_segments = smds->NbElements();
762             if (nbseg - 1 <= nb_segments && nb_segments <= nbseg + 1) {
763               isFound = true;
764               nbseg = nb_segments;
765             }
766           }
767         }
768       }
769       if (!isFound) // not found by meshed edge in the propagation chain, use precision
770       {
771         double aPrecision = _value[ PRECISION_IND ];
772         double nbseg_prec = ceil((theLength / _value[ BEG_LENGTH_IND ]) - aPrecision);
773         if (nbseg_prec == (nbseg - 1)) nbseg--;
774       }
775
776       if (nbseg <= 0)
777         nbseg = 1;                        // degenerated edge
778       eltSize = theLength / nbseg;
779       nbSegments = (int) nbseg;
780     }
781     else
782     {
783       // Number Of Segments hypothesis
784       nbSegments = _ivalue[ NB_SEGMENTS_IND ];
785       if ( nbSegments < 1 )  return false;
786       if ( nbSegments == 1 ) return true;
787
788       switch (_ivalue[ DISTR_TYPE_IND ])
789       {
790       case StdMeshers_NumberOfSegments::DT_Scale:
791         {
792           double scale = _value[ SCALE_FACTOR_IND ];
793
794           if (fabs(scale - 1.0) < Precision::Confusion()) {
795             // special case to avoid division by zero
796             for (int i = 1; i < nbSegments; i++) {
797               double param = f + (l - f) * i / nbSegments;
798               theParams.push_back( param );
799             }
800           } else {
801             // general case of scale distribution
802             if ( theReverse )
803               scale = 1.0 / scale;
804
805             double alpha = pow(scale, 1.0 / (nbSegments - 1));
806             double factor = (l - f) / (1.0 - pow(alpha, nbSegments));
807
808             for (int i = 1; i < nbSegments; i++) {
809               double param = f + factor * (1.0 - pow(alpha, i));
810               theParams.push_back( param );
811             }
812           }
813           const double lenFactor = theLength/(l-f);
814           list<double>::iterator u = theParams.begin(), uEnd = theParams.end();
815           for ( ; u != uEnd; ++u )
816           {
817             GCPnts_AbscissaPoint Discret( theC3d, ((*u)-f) * lenFactor, f );
818             if ( Discret.IsDone() )
819               *u = Discret.Parameter();
820           }
821           return true;
822         }
823         break;
824       case StdMeshers_NumberOfSegments::DT_TabFunc:
825         {
826           FunctionTable func(_vvalue[ TAB_FUNC_IND ], _ivalue[ CONV_MODE_IND ]);
827           return computeParamByFunc(theC3d, f, l, theLength, theReverse,
828                                     _ivalue[ NB_SEGMENTS_IND ], func,
829                                     theParams);
830         }
831         break;
832       case StdMeshers_NumberOfSegments::DT_ExprFunc:
833         {
834           FunctionExpr func(_svalue[ EXPR_FUNC_IND ].c_str(), _ivalue[ CONV_MODE_IND ]);
835           return computeParamByFunc(theC3d, f, l, theLength, theReverse,
836                                     _ivalue[ NB_SEGMENTS_IND ], func,
837                                     theParams);
838         }
839         break;
840       case StdMeshers_NumberOfSegments::DT_Regular:
841         eltSize = theLength / nbSegments;
842         break;
843       default:
844         return false;
845       }
846     }
847     GCPnts_UniformAbscissa Discret(theC3d, eltSize, f, l);
848     if ( !Discret.IsDone() )
849       return error( "GCPnts_UniformAbscissa failed");
850
851     int NbPoints = Min( Discret.NbPoints(), nbSegments + 1 );
852     for ( int i = 2; i < NbPoints; i++ ) // skip 1st and last points
853     {
854       double param = Discret.Parameter(i);
855       theParams.push_back( param );
856     }
857     compensateError( eltSize, eltSize, f, l, theLength, theC3d, theParams, true ); // for PAL9899
858     return true;
859   }
860
861   case BEG_END_LENGTH: {
862
863     // geometric progression: SUM(n) = ( a1 - an * q ) / ( 1 - q ) = theLength
864
865     double a1 = _value[ BEG_LENGTH_IND ];
866     double an = _value[ END_LENGTH_IND ];
867     double q  = ( theLength - a1 ) / ( theLength - an );
868     if ( q < theLength/1e6 || 1.01*theLength < a1 + an)
869       return error ( SMESH_Comment("Invalid segment lengths (")<<a1<<" and "<<an<<") "<<
870                      "for an edge of length "<<theLength);
871
872     double U1 = theReverse ? l : f;
873     double Un = theReverse ? f : l;
874     double param = U1;
875     double eltSize = theReverse ? -a1 : a1;
876     while ( 1 ) {
877       // computes a point on a curve <theC3d> at the distance <eltSize>
878       // from the point of parameter <param>.
879       GCPnts_AbscissaPoint Discret( theC3d, eltSize, param );
880       if ( !Discret.IsDone() ) break;
881       param = Discret.Parameter();
882       if ( f < param && param < l )
883         theParams.push_back( param );
884       else
885         break;
886       eltSize *= q;
887     }
888     compensateError( a1, an, U1, Un, theLength, theC3d, theParams );
889     if (theReverse) theParams.reverse(); // NPAL18025
890     return true;
891   }
892
893   case ARITHMETIC_1D:
894   {
895     // arithmetic progression: SUM(n) = ( an - a1 + q ) * ( a1 + an ) / ( 2 * q ) = theLength
896
897     double a1 = _value[ BEG_LENGTH_IND ];
898     double an = _value[ END_LENGTH_IND ];
899     if ( 1.01*theLength < a1 + an )
900       return error ( SMESH_Comment("Invalid segment lengths (")<<a1<<" and "<<an<<") "<<
901                      "for an edge of length "<<theLength);
902
903     double q = ( an - a1 ) / ( 2 *theLength/( a1 + an ) - 1 );
904     int    n = int(fabs(q) > numeric_limits<double>::min() ? ( 1+( an-a1 )/q ) : ( 1+theLength/a1 ));
905
906     double U1 = theReverse ? l : f;
907     double Un = theReverse ? f : l;
908     double param = U1;
909     double eltSize = a1;
910     if ( theReverse ) {
911       eltSize = -eltSize;
912       q = -q;
913     }
914     while ( n-- > 0 && eltSize * ( Un - U1 ) > 0 ) {
915       // computes a point on a curve <theC3d> at the distance <eltSize>
916       // from the point of parameter <param>.
917       GCPnts_AbscissaPoint Discret( theC3d, eltSize, param );
918       if ( !Discret.IsDone() ) break;
919       param = Discret.Parameter();
920       if ( param > f && param < l )
921         theParams.push_back( param );
922       else
923         break;
924       eltSize += q;
925     }
926     compensateError( a1, an, U1, Un, theLength, theC3d, theParams );
927     if ( theReverse ) theParams.reverse(); // NPAL18025
928
929     return true;
930   }
931
932   case GEOMETRIC_1D:
933   {
934     double a1 = _value[ BEG_LENGTH_IND ], an;
935     double q  = _value[ END_LENGTH_IND ];
936
937     double U1 = theReverse ? l : f;
938     double Un = theReverse ? f : l;
939     double param = U1;
940     double eltSize = a1;
941     if ( theReverse )
942       eltSize = -eltSize;
943
944     int nbParams = 0;
945     while ( true ) {
946       // computes a point on a curve <theC3d> at the distance <eltSize>
947       // from the point of parameter <param>.
948       GCPnts_AbscissaPoint Discret( theC3d, eltSize, param );
949       if ( !Discret.IsDone() ) break;
950       param = Discret.Parameter();
951       if ( f < param && param < l )
952         theParams.push_back( param );
953       else
954         break;
955       an = eltSize;
956       eltSize *= q;
957       ++nbParams;
958     }
959     if ( nbParams > 1 )
960     {
961       if ( Abs( param - Un ) < 0.2 * Abs( param - theParams.back() ))
962       {
963         compensateError( a1, Abs(eltSize), U1, Un, theLength, theC3d, theParams );
964       }
965       else if ( Abs( Un - theParams.back() ) <
966                 0.2 * Abs( theParams.back() - *(++theParams.rbegin())))
967       {
968         theParams.pop_back();
969         compensateError( a1, Abs(an), U1, Un, theLength, theC3d, theParams );
970       }
971     }
972     if (theReverse) theParams.reverse(); // NPAL18025
973
974     return true;
975   }
976
977   case FIXED_POINTS_1D:
978   {
979     const std::vector<double>& aPnts = _fpHyp->GetPoints();
980     const std::vector<int>&   nbsegs = _fpHyp->GetNbSegments();
981     TColStd_SequenceOfReal Params;
982     for ( size_t i = 0; i < aPnts.size(); i++ )
983     {
984       if( aPnts[i]<0.0001 || aPnts[i]>0.9999 ) continue;
985       int j=1;
986       bool IsExist = false;
987       for ( ; j <= Params.Length(); j++ ) {
988         if ( Abs( aPnts[i] - Params.Value(j) ) < 1e-4 ) {
989           IsExist = true;
990           break;
991         }
992         if ( aPnts[i]<Params.Value(j) ) break;
993       }
994       if ( !IsExist ) Params.InsertBefore( j, aPnts[i] );
995     }
996     double par2, par1, lp;
997     par1 = f;
998     lp   = l;
999     double sign = 1.0;
1000     if ( theReverse ) {
1001       par1 = l;
1002       lp   = f;
1003       sign = -1.0;
1004     }
1005     double eltSize, segmentSize = 0.;
1006     double currAbscissa = 0;
1007     for ( int i = 0; i < Params.Length(); i++ )
1008     {
1009       int nbseg = ( i > (int)nbsegs.size()-1 ) ? nbsegs[0] : nbsegs[i];
1010       segmentSize = Params.Value( i+1 ) * theLength - currAbscissa;
1011       currAbscissa += segmentSize;
1012       GCPnts_AbscissaPoint APnt( theC3d, sign*segmentSize, par1 );
1013       if ( !APnt.IsDone() )
1014         return error( "GCPnts_AbscissaPoint failed");
1015       par2    = APnt.Parameter();
1016       eltSize = segmentSize/nbseg;
1017       GCPnts_UniformAbscissa Discret( theC3d, eltSize, par1, par2 );
1018       if ( theReverse )
1019         Discret.Initialize( theC3d, eltSize, par2, par1 );
1020       else
1021         Discret.Initialize( theC3d, eltSize, par1, par2 );
1022       if ( !Discret.IsDone() )
1023         return error( "GCPnts_UniformAbscissa failed");
1024       int NbPoints = Discret.NbPoints();
1025       list<double> tmpParams;
1026       for ( int i = 2; i < NbPoints; i++ ) {
1027         double param = Discret.Parameter(i);
1028         tmpParams.push_back( param );
1029       }
1030       if ( theReverse ) {
1031         compensateError( eltSize, eltSize, par2, par1, segmentSize, theC3d, tmpParams );
1032         tmpParams.reverse();
1033       }
1034       else {
1035         compensateError( eltSize, eltSize, par1, par2, segmentSize, theC3d, tmpParams );
1036       }
1037       theParams.splice( theParams.end(), tmpParams );
1038       theParams.push_back( par2 );
1039
1040       par1 = par2;
1041     }
1042     // add for last
1043     int nbseg = ( (int)nbsegs.size() > Params.Length() ) ? nbsegs[Params.Length()] : nbsegs[0];
1044     segmentSize = theLength - currAbscissa;
1045     eltSize = segmentSize/nbseg;
1046     GCPnts_UniformAbscissa Discret;
1047     if ( theReverse )
1048       Discret.Initialize( theC3d, eltSize, par1, lp );
1049     else
1050       Discret.Initialize( theC3d, eltSize, lp, par1 );
1051     if ( !Discret.IsDone() )
1052       return error( "GCPnts_UniformAbscissa failed");
1053     int NbPoints = Discret.NbPoints();
1054     list<double> tmpParams;
1055     for ( int i = 2; i < NbPoints; i++ ) {
1056       double param = Discret.Parameter(i);
1057       tmpParams.push_back( param );
1058     }
1059     if ( theReverse ) {
1060       compensateError( eltSize, eltSize, lp, par1, segmentSize, theC3d, tmpParams );
1061       tmpParams.reverse();
1062     }
1063     else {
1064       compensateError( eltSize, eltSize, par1, lp, segmentSize, theC3d, tmpParams );
1065     }
1066     theParams.splice( theParams.end(), tmpParams );
1067
1068     if ( theReverse )
1069       theParams.reverse(); // NPAL18025
1070
1071     return true;
1072   }
1073
1074   case DEFLECTION:
1075   {
1076     GCPnts_UniformDeflection Discret( theC3d, _value[ DEFLECTION_IND ], f, l, true );
1077     if ( !Discret.IsDone() )
1078       return false;
1079
1080     int NbPoints = Discret.NbPoints();
1081     for ( int i = 2; i < NbPoints; i++ )
1082     {
1083       double param = Discret.Parameter(i);
1084       theParams.push_back( param );
1085     }
1086     return true;
1087   }
1088
1089   default:;
1090   }
1091
1092   return false;
1093 }
1094
1095 //=============================================================================
1096 /*!
1097  *  
1098  */
1099 //=============================================================================
1100
1101 bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & theShape)
1102 {
1103   if ( _hypType == NONE )
1104     return false;
1105
1106   if ( _hypType == ADAPTIVE )
1107   {
1108     _adaptiveHyp->GetAlgo()->InitComputeError();
1109     _adaptiveHyp->GetAlgo()->Compute( theMesh, theShape );
1110     return error( _adaptiveHyp->GetAlgo()->GetComputeError() );
1111   }
1112
1113   SMESHDS_Mesh * meshDS = theMesh.GetMeshDS();
1114
1115   const TopoDS_Edge & EE = TopoDS::Edge(theShape);
1116   TopoDS_Edge E = TopoDS::Edge(EE.Oriented(TopAbs_FORWARD));
1117   int shapeID = meshDS->ShapeToIndex( E );
1118
1119   double f, l;
1120   Handle(Geom_Curve) Curve = BRep_Tool::Curve(E, f, l);
1121
1122   TopoDS_Vertex VFirst, VLast;
1123   TopExp::Vertices(E, VFirst, VLast);   // Vfirst corresponds to f and Vlast to l
1124
1125   ASSERT(!VFirst.IsNull());
1126   ASSERT(!VLast.IsNull());
1127   const SMDS_MeshNode * idFirst = SMESH_Algo::VertexNode( VFirst, meshDS );
1128   const SMDS_MeshNode * idLast = SMESH_Algo::VertexNode( VLast, meshDS );
1129   if (!idFirst || !idLast)
1130     return error( COMPERR_BAD_INPUT_MESH, "No node on vertex");
1131
1132   // remove elements created by e.g. patern mapping (PAL21999)
1133   // CLEAN event is incorrectly ptopagated seemingly due to Propagation hyp
1134   // so TEMPORARY solution is to clean the submesh manually
1135   //theMesh.GetSubMesh(theShape)->ComputeStateEngine( SMESH_subMesh::CLEAN );
1136   if (SMESHDS_SubMesh * subMeshDS = meshDS->MeshElements(theShape))
1137   {
1138     SMDS_ElemIteratorPtr ite = subMeshDS->GetElements();
1139     while (ite->more())
1140       meshDS->RemoveFreeElement(ite->next(), subMeshDS);
1141     SMDS_NodeIteratorPtr itn = subMeshDS->GetNodes();
1142     while (itn->more()) {
1143       const SMDS_MeshNode * node = itn->next();
1144       if ( node->NbInverseElements() == 0 )
1145         meshDS->RemoveFreeNode(node, subMeshDS);
1146       else
1147         meshDS->RemoveNode(node);
1148     }
1149   }
1150
1151   if (!Curve.IsNull())
1152   {
1153     list< double > params;
1154     bool reversed = false;
1155     if ( theMesh.GetShapeToMesh().ShapeType() >= TopAbs_WIRE ) {
1156       // if the shape to mesh is WIRE or EDGE
1157       reversed = ( EE.Orientation() == TopAbs_REVERSED );
1158     }
1159     if ( !_mainEdge.IsNull() ) {
1160       // take into account reversing the edge the hypothesis is propagated from
1161       // (_mainEdge.Orientation() marks mutual orientation of EDGEs in propagation chain)
1162       reversed = ( _mainEdge.Orientation() == TopAbs_REVERSED );
1163       if ( !_isPropagOfDistribution ) {
1164         int mainID = meshDS->ShapeToIndex(_mainEdge);
1165         if ( std::find( _revEdgesIDs.begin(), _revEdgesIDs.end(), mainID) != _revEdgesIDs.end())
1166           reversed = !reversed;
1167       }
1168     }
1169     // take into account this edge reversing
1170     if ( std::find( _revEdgesIDs.begin(), _revEdgesIDs.end(), shapeID) != _revEdgesIDs.end())
1171       reversed = !reversed;
1172
1173     BRepAdaptor_Curve C3d( E );
1174     double length = EdgeLength( E );
1175     if ( ! computeInternalParameters( theMesh, C3d, length, f, l, params, reversed, true )) {
1176       return false;
1177     }
1178     redistributeNearVertices( theMesh, C3d, length, params, VFirst, VLast );
1179
1180     // edge extrema (indexes : 1 & NbPoints) already in SMDS (TopoDS_Vertex)
1181     // only internal nodes receive an edge position with param on curve
1182
1183     const SMDS_MeshNode * idPrev = idFirst;
1184     double parPrev = f;
1185     double parLast = l;
1186
1187     /* NPAL18025
1188     if (reversed) {
1189       idPrev = idLast;
1190       idLast = idFirst;
1191       idFirst = idPrev;
1192       parPrev = l;
1193       parLast = f;
1194     }
1195     */
1196     for (list<double>::iterator itU = params.begin(); itU != params.end(); itU++) {
1197       double param = *itU;
1198       gp_Pnt P = Curve->Value(param);
1199
1200       //Add the Node in the DataStructure
1201       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
1202       meshDS->SetNodeOnEdge(node, shapeID, param);
1203
1204       if(_quadraticMesh) {
1205         // create medium node
1206         double prm = ( parPrev + param )/2;
1207         gp_Pnt PM = Curve->Value(prm);
1208         SMDS_MeshNode * NM = meshDS->AddNode(PM.X(), PM.Y(), PM.Z());
1209         meshDS->SetNodeOnEdge(NM, shapeID, prm);
1210         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node, NM);
1211         meshDS->SetMeshElementOnShape(edge, shapeID);
1212       }
1213       else {
1214         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
1215         meshDS->SetMeshElementOnShape(edge, shapeID);
1216       }
1217
1218       idPrev = node;
1219       parPrev = param;
1220     }
1221     if(_quadraticMesh) {
1222       double prm = ( parPrev + parLast )/2;
1223       gp_Pnt PM = Curve->Value(prm);
1224       SMDS_MeshNode * NM = meshDS->AddNode(PM.X(), PM.Y(), PM.Z());
1225       meshDS->SetNodeOnEdge(NM, shapeID, prm);
1226       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast, NM);
1227       meshDS->SetMeshElementOnShape(edge, shapeID);
1228     }
1229     else {
1230       SMDS_MeshEdge* edge = meshDS->AddEdge(idPrev, idLast);
1231       meshDS->SetMeshElementOnShape(edge, shapeID);
1232     }
1233   }
1234   else
1235   {
1236     // Edge is a degenerated Edge : We put n = 5 points on the edge.
1237     const int NbPoints = 5;
1238     BRep_Tool::Range( E, f, l ); // PAL15185
1239     double du = (l - f) / (NbPoints - 1);
1240
1241     gp_Pnt P = BRep_Tool::Pnt(VFirst);
1242
1243     const SMDS_MeshNode * idPrev = idFirst;
1244     for (int i = 2; i < NbPoints; i++) {
1245       double param = f + (i - 1) * du;
1246       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
1247       if(_quadraticMesh) {
1248         // create medium node
1249         double prm = param - du/2.;
1250         SMDS_MeshNode * NM = meshDS->AddNode(P.X(), P.Y(), P.Z());
1251         meshDS->SetNodeOnEdge(NM, shapeID, prm);
1252         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node, NM);
1253         meshDS->SetMeshElementOnShape(edge, shapeID);
1254       }
1255       else {
1256         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
1257         meshDS->SetMeshElementOnShape(edge, shapeID);
1258       }
1259       meshDS->SetNodeOnEdge(node, shapeID, param);
1260       idPrev = node;
1261     }
1262     if(_quadraticMesh) {
1263       // create medium node
1264       double prm = l - du/2.;
1265       SMDS_MeshNode * NM = meshDS->AddNode(P.X(), P.Y(), P.Z());
1266       meshDS->SetNodeOnEdge(NM, shapeID, prm);
1267       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast, NM);
1268       meshDS->SetMeshElementOnShape(edge, shapeID);
1269     }
1270     else {
1271       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast);
1272       meshDS->SetMeshElementOnShape(edge, shapeID);
1273     }
1274   }
1275   return true;
1276 }
1277
1278
1279 //=============================================================================
1280 /*!
1281  *  
1282  */
1283 //=============================================================================
1284
1285 bool StdMeshers_Regular_1D::Evaluate(SMESH_Mesh & theMesh,
1286                                      const TopoDS_Shape & theShape,
1287                                      MapShapeNbElems& aResMap)
1288 {
1289   if ( _hypType == NONE )
1290     return false;
1291
1292   if ( _hypType == ADAPTIVE )
1293   {
1294     _adaptiveHyp->GetAlgo()->InitComputeError();
1295     _adaptiveHyp->GetAlgo()->Evaluate( theMesh, theShape, aResMap );
1296     return error( _adaptiveHyp->GetAlgo()->GetComputeError() );
1297   }
1298
1299   const TopoDS_Edge & EE = TopoDS::Edge(theShape);
1300   TopoDS_Edge E = TopoDS::Edge(EE.Oriented(TopAbs_FORWARD));
1301
1302   double f, l;
1303   Handle(Geom_Curve) Curve = BRep_Tool::Curve(E, f, l);
1304
1305   TopoDS_Vertex VFirst, VLast;
1306   TopExp::Vertices(E, VFirst, VLast);   // Vfirst corresponds to f and Vlast to l
1307
1308   ASSERT(!VFirst.IsNull());
1309   ASSERT(!VLast.IsNull());
1310
1311   std::vector<int> aVec(SMDSEntity_Last,0);
1312
1313   if (!Curve.IsNull()) {
1314     list< double > params;
1315
1316     BRepAdaptor_Curve C3d( E );
1317     double length = EdgeLength( E );
1318     if ( ! computeInternalParameters( theMesh, C3d, length, f, l, params, false, true )) {
1319       SMESH_subMesh * sm = theMesh.GetSubMesh(theShape);
1320       aResMap.insert(std::make_pair(sm,aVec));
1321       SMESH_ComputeErrorPtr& smError = sm->GetComputeError();
1322       smError.reset( new SMESH_ComputeError(COMPERR_ALGO_FAILED,"Submesh can not be evaluated",this));
1323       return false;
1324     }
1325     redistributeNearVertices( theMesh, C3d, length, params, VFirst, VLast );
1326
1327     if(_quadraticMesh) {
1328       aVec[SMDSEntity_Node] = 2*params.size() + 1;
1329       aVec[SMDSEntity_Quad_Edge] = params.size() + 1;
1330     }
1331     else {
1332       aVec[SMDSEntity_Node] = params.size();
1333       aVec[SMDSEntity_Edge] = params.size() + 1;
1334     }
1335     
1336   }
1337   else {
1338     // Edge is a degenerated Edge : We put n = 5 points on the edge.
1339     if ( _quadraticMesh ) {
1340       aVec[SMDSEntity_Node] = 11;
1341       aVec[SMDSEntity_Quad_Edge] = 6;
1342     }
1343     else {
1344       aVec[SMDSEntity_Node] = 5;
1345       aVec[SMDSEntity_Edge] = 6;
1346     }
1347   }
1348
1349   SMESH_subMesh * sm = theMesh.GetSubMesh(theShape);
1350   aResMap.insert(std::make_pair(sm,aVec));
1351
1352   return true;
1353 }
1354
1355
1356 //=============================================================================
1357 /*!
1358  *  See comments in SMESH_Algo.cxx
1359  */
1360 //=============================================================================
1361
1362 const list <const SMESHDS_Hypothesis *> &
1363 StdMeshers_Regular_1D::GetUsedHypothesis(SMESH_Mesh &         aMesh,
1364                                          const TopoDS_Shape & aShape,
1365                                          const bool           ignoreAuxiliary)
1366 {
1367   _usedHypList.clear();
1368   _mainEdge.Nullify();
1369
1370   SMESH_HypoFilter auxiliaryFilter( SMESH_HypoFilter::IsAuxiliary() );
1371   const SMESH_HypoFilter* compatibleFilter = GetCompatibleHypoFilter(/*ignoreAux=*/true );
1372
1373   // get non-auxiliary assigned directly to aShape
1374   int nbHyp = aMesh.GetHypotheses( aShape, *compatibleFilter, _usedHypList, false );
1375
1376   if (nbHyp == 0 && aShape.ShapeType() == TopAbs_EDGE)
1377   {
1378     // Check, if propagated from some other edge
1379     _mainEdge = StdMeshers_Propagation::GetPropagationSource( aMesh, aShape,
1380                                                               _isPropagOfDistribution );
1381     if ( !_mainEdge.IsNull() )
1382     {
1383       // Propagation of 1D hypothesis from <aMainEdge> on this edge;
1384       // get non-auxiliary assigned to _mainEdge
1385       nbHyp = aMesh.GetHypotheses( _mainEdge, *compatibleFilter, _usedHypList, true );
1386     }
1387   }
1388
1389   if (nbHyp == 0) // nothing propagated nor assigned to aShape
1390   {
1391     SMESH_Algo::GetUsedHypothesis( aMesh, aShape, ignoreAuxiliary );
1392     nbHyp = _usedHypList.size();
1393   }
1394   else
1395   {
1396     // get auxiliary hyps from aShape
1397     aMesh.GetHypotheses( aShape, auxiliaryFilter, _usedHypList, true );
1398   }
1399   if ( nbHyp > 1 && ignoreAuxiliary )
1400     _usedHypList.clear(); //only one compatible non-auxiliary hypothesis allowed
1401
1402   return _usedHypList;
1403 }
1404
1405 //================================================================================
1406 /*!
1407  * \brief Pass CancelCompute() to a child algorithm
1408  */
1409 //================================================================================
1410
1411 void StdMeshers_Regular_1D::CancelCompute()
1412 {
1413   SMESH_Algo::CancelCompute();
1414   if ( _hypType == ADAPTIVE )
1415     _adaptiveHyp->GetAlgo()->CancelCompute();
1416 }