Salome HOME
PAL13639 (EDF PAL 317 : SMESH : Create "0D Hypothesis")
[modules/smesh.git] / src / StdMeshers / StdMeshers_Regular_1D.cxx
1 //  SMESH SMESH : implementaion of SMESH idl descriptions
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
5 // 
6 //  This library is free software; you can redistribute it and/or 
7 //  modify it under the terms of the GNU Lesser General Public 
8 //  License as published by the Free Software Foundation; either 
9 //  version 2.1 of the License. 
10 // 
11 //  This library is distributed in the hope that it will be useful, 
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
14 //  Lesser General Public License for more details. 
15 // 
16 //  You should have received a copy of the GNU Lesser General Public 
17 //  License along with this library; if not, write to the Free Software 
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
19 // 
20 //  See http://www.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 #include "StdMeshers_Regular_1D.hxx"
31 #include "StdMeshers_Distribution.hxx"
32
33 #include "StdMeshers_LocalLength.hxx"
34 #include "StdMeshers_NumberOfSegments.hxx"
35 #include "StdMeshers_Arithmetic1D.hxx"
36 #include "StdMeshers_StartEndLength.hxx"
37 #include "StdMeshers_Deflection1D.hxx"
38 #include "StdMeshers_AutomaticLength.hxx"
39 #include "StdMeshers_SegmentLengthAroundVertex.hxx"
40
41 #include "SMESH_Gen.hxx"
42 #include "SMESH_Mesh.hxx"
43 #include "SMESH_HypoFilter.hxx"
44 #include "SMESH_subMesh.hxx"
45 #include "SMESH_subMeshEventListener.hxx"
46
47 #include "SMDS_MeshElement.hxx"
48 #include "SMDS_MeshNode.hxx"
49
50 #include "Utils_SALOME_Exception.hxx"
51 #include "utilities.h"
52
53 #include <BRepAdaptor_Curve.hxx>
54 #include <BRep_Tool.hxx>
55 #include <TopoDS_Edge.hxx>
56 #include <TopExp_Explorer.hxx>
57 #include <GCPnts_AbscissaPoint.hxx>
58 #include <GCPnts_UniformAbscissa.hxx>
59 #include <GCPnts_UniformDeflection.hxx>
60 #include <Precision.hxx>
61
62 #include <Standard_ErrorHandler.hxx>
63 #include <Standard_Failure.hxx>
64
65 #include <string>
66 //#include <math.h>
67
68 using namespace std;
69
70 //=============================================================================
71 /*!
72  *  
73  */
74 //=============================================================================
75
76 StdMeshers_Regular_1D::StdMeshers_Regular_1D(int hypId, int studyId,
77         SMESH_Gen * gen):SMESH_1D_Algo(hypId, studyId, gen)
78 {
79         MESSAGE("StdMeshers_Regular_1D::StdMeshers_Regular_1D");
80         _name = "Regular_1D";
81         _shapeType = (1 << TopAbs_EDGE);
82
83         _compatibleHypothesis.push_back("LocalLength");
84         _compatibleHypothesis.push_back("NumberOfSegments");
85         _compatibleHypothesis.push_back("StartEndLength");
86         _compatibleHypothesis.push_back("Deflection1D");
87         _compatibleHypothesis.push_back("Arithmetic1D");
88         _compatibleHypothesis.push_back("AutomaticLength");
89
90         _compatibleHypothesis.push_back("QuadraticMesh"); // auxiliary !!!
91 }
92
93 //=============================================================================
94 /*!
95  *  
96  */
97 //=============================================================================
98
99 StdMeshers_Regular_1D::~StdMeshers_Regular_1D()
100 {
101 }
102
103 //=============================================================================
104 /*!
105  *  
106  */
107 //=============================================================================
108
109 bool StdMeshers_Regular_1D::CheckHypothesis
110                          (SMESH_Mesh&                          aMesh,
111                           const TopoDS_Shape&                  aShape,
112                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
113 {
114   _hypType = NONE;
115   _quadraticMesh = false;
116
117   const bool ignoreAuxiliaryHyps = false;
118   const list <const SMESHDS_Hypothesis * > & hyps =
119     GetUsedHypothesis(aMesh, aShape, ignoreAuxiliaryHyps);
120
121   // find non-auxiliary hypothesis
122   const SMESHDS_Hypothesis *theHyp = 0;
123   list <const SMESHDS_Hypothesis * >::const_iterator h = hyps.begin();
124   for ( ; h != hyps.end(); ++h ) {
125     if ( static_cast<const SMESH_Hypothesis*>(*h)->IsAuxiliary() ) {
126       if ( strcmp( "QuadraticMesh", (*h)->GetName() ) == 0 )
127         _quadraticMesh = true;
128     }
129     else {
130       if ( !theHyp )
131         theHyp = *h; // use only the first non-auxiliary hypothesis
132     }
133   }
134
135   if ( !theHyp )
136   {
137     aStatus = SMESH_Hypothesis::HYP_MISSING;
138     return false;  // can't work without a hypothesis
139   }
140
141   string hypName = theHyp->GetName();
142
143   if (hypName == "LocalLength")
144   {
145     const StdMeshers_LocalLength * hyp =
146       dynamic_cast <const StdMeshers_LocalLength * >(theHyp);
147     ASSERT(hyp);
148     _value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength();
149     ASSERT( _value[ BEG_LENGTH_IND ] > 0 );
150     _hypType = LOCAL_LENGTH;
151     aStatus = SMESH_Hypothesis::HYP_OK;
152   }
153
154   else if (hypName == "NumberOfSegments")
155   {
156     const StdMeshers_NumberOfSegments * hyp =
157       dynamic_cast <const StdMeshers_NumberOfSegments * >(theHyp);
158     ASSERT(hyp);
159     _ivalue[ NB_SEGMENTS_IND  ] = hyp->GetNumberOfSegments();
160     ASSERT( _ivalue[ NB_SEGMENTS_IND ] > 0 );
161     _ivalue[ DISTR_TYPE_IND ] = (int) hyp->GetDistrType();
162     switch (_ivalue[ DISTR_TYPE_IND ])
163     {
164     case StdMeshers_NumberOfSegments::DT_Scale:
165       _value[ SCALE_FACTOR_IND ] = hyp->GetScaleFactor();
166       break;
167     case StdMeshers_NumberOfSegments::DT_TabFunc:
168       _vvalue[ TAB_FUNC_IND ] = hyp->GetTableFunction();
169       break;
170     case StdMeshers_NumberOfSegments::DT_ExprFunc:
171       _svalue[ EXPR_FUNC_IND ] = hyp->GetExpressionFunction();
172       break;
173     case StdMeshers_NumberOfSegments::DT_Regular:
174       break;
175     default:
176       ASSERT(0);
177       break;
178     }
179     if (_ivalue[ DISTR_TYPE_IND ] == StdMeshers_NumberOfSegments::DT_TabFunc ||
180         _ivalue[ DISTR_TYPE_IND ] == StdMeshers_NumberOfSegments::DT_ExprFunc)
181         _ivalue[ CONV_MODE_IND ] = hyp->ConversionMode();
182     _hypType = NB_SEGMENTS;
183     aStatus = SMESH_Hypothesis::HYP_OK;
184   }
185
186   else if (hypName == "Arithmetic1D")
187   {
188     const StdMeshers_Arithmetic1D * hyp =
189       dynamic_cast <const StdMeshers_Arithmetic1D * >(theHyp);
190     ASSERT(hyp);
191     _value[ BEG_LENGTH_IND ] = hyp->GetLength( true );
192     _value[ END_LENGTH_IND ] = hyp->GetLength( false );
193     ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 );
194     _hypType = ARITHMETIC_1D;
195     aStatus = SMESH_Hypothesis::HYP_OK;
196   }
197
198   else if (hypName == "StartEndLength")
199   {
200     const StdMeshers_StartEndLength * hyp =
201       dynamic_cast <const StdMeshers_StartEndLength * >(theHyp);
202     ASSERT(hyp);
203     _value[ BEG_LENGTH_IND ] = hyp->GetLength( true );
204     _value[ END_LENGTH_IND ] = hyp->GetLength( false );
205     ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 );
206     _hypType = BEG_END_LENGTH;
207     aStatus = SMESH_Hypothesis::HYP_OK;
208   }
209
210   else if (hypName == "Deflection1D")
211   {
212     const StdMeshers_Deflection1D * hyp =
213       dynamic_cast <const StdMeshers_Deflection1D * >(theHyp);
214     ASSERT(hyp);
215     _value[ DEFLECTION_IND ] = hyp->GetDeflection();
216     ASSERT( _value[ DEFLECTION_IND ] > 0 );
217     _hypType = DEFLECTION;
218     aStatus = SMESH_Hypothesis::HYP_OK;
219   }
220
221   else if (hypName == "AutomaticLength")
222   {
223     StdMeshers_AutomaticLength * hyp = const_cast<StdMeshers_AutomaticLength *>
224       (dynamic_cast <const StdMeshers_AutomaticLength * >(theHyp));
225     ASSERT(hyp);
226     _value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape );
227     ASSERT( _value[ BEG_LENGTH_IND ] > 0 );
228     _hypType = LOCAL_LENGTH;
229     aStatus = SMESH_Hypothesis::HYP_OK;
230   }
231   else
232     aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
233
234   return ( _hypType != NONE );
235 }
236
237 static bool computeParamByFunc(Adaptor3d_Curve& C3d, double first, double last,
238                                double length, bool theReverse, 
239                                int nbSeg, Function& func,
240                                list<double>& theParams)
241 {
242   // never do this way
243   //OSD::SetSignal( true );
244
245   if( nbSeg<=0 )
246     return false;
247
248   MESSAGE( "computeParamByFunc" );
249
250   int nbPnt = 1 + nbSeg;
251   vector<double> x(nbPnt, 0.);
252
253   if( !buildDistribution( func, 0.0, 1.0, nbSeg, x, 1E-4 ) )
254      return false;
255
256   MESSAGE( "Points:\n" );
257   char buf[1024];
258   for( int i=0; i<=nbSeg; i++ )
259   {
260     sprintf(  buf, "%f\n", float(x[i] ) );
261     MESSAGE( buf );
262   }
263     
264
265
266   // apply parameters in range [0,1] to the space of the curve
267   double prevU = first;
268   double sign = 1.;
269   if (theReverse)
270   {
271     prevU = last;
272     sign = -1.;
273   }
274   for( int i = 1; i < nbSeg; i++ )
275   {
276     double curvLength = length * (x[i] - x[i-1]) * sign;
277     GCPnts_AbscissaPoint Discret( C3d, curvLength, prevU );
278     if ( !Discret.IsDone() )
279       return false;
280     double U = Discret.Parameter();
281     if ( U > first && U < last )
282       theParams.push_back( U );
283     else
284       return false;
285     prevU = U;
286   }
287   return true;
288 }
289
290
291 //================================================================================
292 /*!
293  * \brief adjust internal node parameters so that the last segment length == an
294   * \param a1 - the first segment length
295   * \param an - the last segment length
296   * \param U1 - the first edge parameter
297   * \param Un - the last edge parameter
298   * \param length - the edge length
299   * \param C3d - the edge curve
300   * \param theParams - internal node parameters to adjust
301   * \param adjustNeighbors2an - to adjust length of segments next to the last one
302   *  and not to remove parameters
303  */
304 //================================================================================
305
306 static void compensateError(double a1, double an,
307                             double U1, double Un,
308                             double            length,
309                             Adaptor3d_Curve&  C3d,
310                             list<double> &    theParams,
311                             bool              adjustNeighbors2an = false)
312 {
313   int i, nPar = theParams.size();
314   if ( a1 + an < length && nPar > 1 )
315   {
316     list<double>::reverse_iterator itU = theParams.rbegin();
317     double Ul = *itU++;
318     // dist from the last point to the edge end <Un>, it should be equal to <an>
319     double Ln = GCPnts_AbscissaPoint::Length( C3d, Ul, Un );
320     double dLn = an - Ln; // signed error of <an>
321     if ( Abs( dLn ) <= Precision::Confusion() )
322       return;
323     double dU = Abs( Ul - *itU ); // parametric length of the last but one segment
324     double dUn = dLn * Abs( Un - U1 ) / length; // parametric error of <an>
325     if ( adjustNeighbors2an || dUn < 0.5 * dU ) { // last segment is a bit shorter than it should
326       dUn = -dUn; // move the last parameter to the edge beginning
327     }
328     else {  // last segment is much shorter than it should -> remove the last param and
329       theParams.pop_back(); nPar--; // move the rest points toward the edge end
330       Ln = GCPnts_AbscissaPoint::Length( C3d, theParams.back(), Un );
331       dUn = ( an - Ln ) * Abs( Un - U1 ) / length;
332       if ( dUn < 0.5 * dU )
333         dUn = -dUn;
334     }
335     bool reverse = ( U1 > Un );
336     if ( reverse )
337       dUn = -dUn;
338
339     double q  = dUn / ( nPar - 1 );
340     if ( !adjustNeighbors2an ) {
341       for ( itU = theParams.rbegin(), i = 1; i < nPar; itU++, i++ ) {
342         (*itU) += dUn;
343         dUn -= q;
344       }
345     }
346     else {
347       theParams.back() += dUn;
348       double sign = reverse ? -1 : 1;
349       double prevU = theParams.back();
350       itU = theParams.rbegin();
351       for ( ++itU, i = 1; i < nPar; ++itU, i++ ) {
352         double newU = *itU + dUn;
353         if ( newU*sign < prevU*sign ) {
354           prevU = *itU = newU;
355           dUn -= q;
356         }
357         else { // set U between prevU and next valid param
358           list<double>::reverse_iterator itU2 = itU;
359           ++itU2;
360           int nb = 2;
361           while ( (*itU2)*sign > prevU*sign ) {
362             ++itU2; ++nb;
363           }
364           dU = ( *itU2 - prevU ) / nb;
365           while ( itU != itU2 ) {
366             *itU += dU; ++itU;
367           }
368           break;
369         }
370       }
371     }
372   }
373 }
374
375 //================================================================================
376 /*!
377  * \brief Class used to clean mesh on edges when 0D hyp modified.
378  * Common approach doesn't work when 0D algo is missing because the 0D hyp is
379  * considered as not participating in computation whereas it is used by 1D algo.
380  */
381 //================================================================================
382
383 struct VertexEventListener : public SMESH_subMeshEventListener
384 {
385   VertexEventListener():SMESH_subMeshEventListener(0) // won't be deleted by submesh
386   {}
387   /*!
388    * \brief Clean mesh on edges
389    * \param event - algo_event or compute_event itself (of SMESH_subMesh)
390    * \param eventType - ALGO_EVENT or COMPUTE_EVENT (of SMESH_subMesh)
391    * \param subMesh - the submesh where the event occures
392    */
393   void ProcessEvent(const int event, const int eventType, SMESH_subMesh* subMesh,
394                     EventListenerData*, SMESH_Hypothesis*)
395   {
396     if ( eventType == SMESH_subMesh::ALGO_EVENT) // all algo events
397     {
398       subMesh->ComputeStateEngine( SMESH_subMesh::MODIF_ALGO_STATE );
399     }
400   }
401 }; // struct VertexEventListener
402
403 //=============================================================================
404 /*!
405  * \brief Sets event listener to vertex submeshes
406  * \param subMesh - submesh where algo is set
407  *
408  * This method is called when a submesh gets HYP_OK algo_state.
409  * After being set, event listener is notified on each event of a submesh.
410  */
411 //=============================================================================
412
413 void StdMeshers_Regular_1D::SetEventListener(SMESH_subMesh* subMesh)
414 {
415   static VertexEventListener listener;
416   const map < int, SMESH_subMesh * >& vSMs = subMesh->DependsOn();
417   map < int, SMESH_subMesh * >::const_iterator itsub;
418   for (itsub = vSMs.begin(); itsub != vSMs.end(); itsub++)
419   {
420     subMesh->SetEventListener( &listener, 0, itsub->second );
421   }
422 }
423
424 //=============================================================================
425 /*!
426  * \brief Do nothing
427  * \param subMesh - restored submesh
428  *
429  * This method is called only if a submesh has HYP_OK algo_state.
430  */
431 //=============================================================================
432
433 void StdMeshers_Regular_1D::SubmeshRestored(SMESH_subMesh* subMesh)
434 {
435 }
436
437 //=============================================================================
438 /*!
439  * \brief Return StdMeshers_SegmentLengthAroundVertex assigned to vertex
440  */
441 //=============================================================================
442
443 const StdMeshers_SegmentLengthAroundVertex*
444 StdMeshers_Regular_1D::getVertexHyp(SMESH_Mesh &          theMesh,
445                                     const TopoDS_Vertex & theV)
446 {
447   static SMESH_HypoFilter filter( SMESH_HypoFilter::HasName("SegmentLengthAroundVertex"));
448   const SMESH_Hypothesis * hyp = theMesh.GetHypothesis( theV, filter, true );
449   return static_cast<const StdMeshers_SegmentLengthAroundVertex*>( hyp );
450 }
451
452 //================================================================================
453 /*!
454  * \brief Tune parameters to fit "SegmentLengthAroundVertex" hypothesis
455   * \param theC3d - wire curve
456   * \param theLength - curve length
457   * \param theParameters - internal nodes parameters to modify
458   * \param theVf - 1st vertex
459   * \param theVl - 2nd vertex
460  */
461 //================================================================================
462
463 void StdMeshers_Regular_1D::redistributeNearVertices (SMESH_Mesh &          theMesh,
464                                                       Adaptor3d_Curve &     theC3d,
465                                                       double                theLength,
466                                                       std::list< double > & theParameters,
467                                                       const TopoDS_Vertex & theVf,
468                                                       const TopoDS_Vertex & theVl) const
469 {
470   double f = theC3d.FirstParameter(), l = theC3d.LastParameter();
471   int nPar = theParameters.size();
472   for ( int isEnd1 = 0; isEnd1 < 2; ++isEnd1 )
473   {
474     const TopoDS_Vertex & V = isEnd1 ? theVf : theVl;
475     const StdMeshers_SegmentLengthAroundVertex* hyp = getVertexHyp (theMesh, V );
476     if ( hyp ) {
477       double vertexLength = hyp->GetLength();
478       if ( isEnd1 ) {
479         theParameters.reverse();
480         std::swap( f, l );
481       }
482       if ( _hypType == NB_SEGMENTS || nPar < 5 )
483       {
484         compensateError(0, vertexLength, f, l, theLength, theC3d, theParameters, true );
485       }
486       else
487       {
488         // recompute params between the last segment and a middle one.
489         // find size of a middle segment
490         int nHalf = ( nPar-1 ) / 2;
491         list< double >::reverse_iterator itU = theParameters.rbegin();
492         std::advance( itU, nHalf );
493         double Um = *itU++;
494         double Lm = GCPnts_AbscissaPoint::Length( theC3d, Um, *itU);
495         double L = GCPnts_AbscissaPoint::Length( theC3d, *itU, l);
496         StdMeshers_Regular_1D algo( *this );
497         algo._hypType = BEG_END_LENGTH;
498         algo._value[ BEG_LENGTH_IND ] = Lm;
499         algo._value[ END_LENGTH_IND ] = vertexLength;
500         double from = *itU, to = l;
501         if ( isEnd1 ) {
502           std::swap( from, to );
503           std::swap( algo._value[ BEG_LENGTH_IND ], algo._value[ END_LENGTH_IND ]);
504         }
505         list<double> params;
506         if ( algo.computeInternalParameters( theC3d, L, from, to, params, false ))
507         {
508           if ( isEnd1 ) params.reverse();
509           while ( 1 + nHalf-- )
510             theParameters.pop_back();
511           theParameters.splice( theParameters.end(), params );
512         }
513         else
514         {
515           compensateError(0, vertexLength, f, l, theLength, theC3d, theParameters, true );
516         }
517       }
518       if ( isEnd1 )
519         theParameters.reverse();
520     }
521   }
522 }
523
524 //=============================================================================
525 /*!
526  *  
527  */
528 //=============================================================================
529 bool StdMeshers_Regular_1D::computeInternalParameters(Adaptor3d_Curve& theC3d,
530                                                       double           theLength,
531                                                       double           theFirstU,
532                                                       double           theLastU,
533                                                       list<double> &   theParams,
534                                                       const bool       theReverse) const
535 {
536   theParams.clear();
537
538   double f = theFirstU, l = theLastU;
539
540   switch( _hypType )
541   {
542   case LOCAL_LENGTH:
543   case NB_SEGMENTS: {
544
545     double eltSize = 1;
546     if ( _hypType == LOCAL_LENGTH )
547     {
548       // Local Length hypothesis
549       double nbseg = ceil(theLength / _value[ BEG_LENGTH_IND ]); // integer sup
550       if (nbseg <= 0)
551         nbseg = 1;                        // degenerated edge
552       eltSize = theLength / nbseg;
553     }
554     else
555     {
556       // Number Of Segments hypothesis
557       int NbSegm = _ivalue[ NB_SEGMENTS_IND ];
558       if ( NbSegm < 1 )  return false;
559       if ( NbSegm == 1 ) return true;
560
561       switch (_ivalue[ DISTR_TYPE_IND ])
562       {
563       case StdMeshers_NumberOfSegments::DT_Scale:
564         {
565           double scale = _value[ SCALE_FACTOR_IND ];
566
567           if (fabs(scale - 1.0) < Precision::Confusion()) {
568             // special case to avoid division on zero
569             for (int i = 1; i < NbSegm; i++) {
570               double param = f + (l - f) * i / NbSegm;
571               theParams.push_back( param );
572             }
573           } else {
574             // general case of scale distribution
575             if ( theReverse )
576               scale = 1.0 / scale;
577
578             double alpha = pow(scale, 1.0 / (NbSegm - 1));
579             double factor = (l - f) / (1.0 - pow(alpha, NbSegm));
580
581             for (int i = 1; i < NbSegm; i++) {
582               double param = f + factor * (1.0 - pow(alpha, i));
583               theParams.push_back( param );
584             }
585           }
586           return true;
587         }
588         break;
589       case StdMeshers_NumberOfSegments::DT_TabFunc:
590         {
591           FunctionTable func(_vvalue[ TAB_FUNC_IND ], _ivalue[ CONV_MODE_IND ]);
592           return computeParamByFunc(theC3d, f, l, theLength, theReverse,
593                                     _ivalue[ NB_SEGMENTS_IND ], func,
594                                     theParams);
595         }
596         break;
597       case StdMeshers_NumberOfSegments::DT_ExprFunc:
598         {
599           FunctionExpr func(_svalue[ EXPR_FUNC_IND ].c_str(), _ivalue[ CONV_MODE_IND ]);
600           return computeParamByFunc(theC3d, f, l, theLength, theReverse,
601                                     _ivalue[ NB_SEGMENTS_IND ], func,
602                                     theParams);
603         }
604         break;
605       case StdMeshers_NumberOfSegments::DT_Regular:
606         eltSize = theLength / _ivalue[ NB_SEGMENTS_IND ];
607         break;
608       default:
609         return false;
610       }
611     }
612     GCPnts_UniformAbscissa Discret(theC3d, eltSize, f, l);
613     if ( !Discret.IsDone() )
614       return false;
615
616     int NbPoints = Discret.NbPoints();
617     for ( int i = 2; i < NbPoints; i++ )
618     {
619       double param = Discret.Parameter(i);
620       theParams.push_back( param );
621     }
622     compensateError( eltSize, eltSize, f, l, theLength, theC3d, theParams ); // for PAL9899
623     return true;
624   }
625
626   case BEG_END_LENGTH: {
627
628     // geometric progression: SUM(n) = ( a1 - an * q ) / ( 1 - q ) = theLength
629
630     double a1 = _value[ BEG_LENGTH_IND ];
631     double an = _value[ END_LENGTH_IND ];
632     double q  = ( theLength - a1 ) / ( theLength - an );
633
634     double U1 = theReverse ? l : f;
635     double Un = theReverse ? f : l;
636     double param = U1;
637     double eltSize = theReverse ? -a1 : a1;
638     while ( 1 ) {
639       // computes a point on a curve <theC3d> at the distance <eltSize>
640       // from the point of parameter <param>.
641       GCPnts_AbscissaPoint Discret( theC3d, eltSize, param );
642       if ( !Discret.IsDone() ) break;
643       param = Discret.Parameter();
644       if ( param > f && param < l )
645         theParams.push_back( param );
646       else
647         break;
648       eltSize *= q;
649     }
650     compensateError( a1, an, U1, Un, theLength, theC3d, theParams );
651     return true;
652   }
653
654   case ARITHMETIC_1D: {
655
656     // arithmetic progression: SUM(n) = ( an - a1 + q ) * ( a1 + an ) / ( 2 * q ) = theLength
657
658     double a1 = _value[ BEG_LENGTH_IND ];
659     double an = _value[ END_LENGTH_IND ];
660
661     double  q = ( an - a1 ) / ( 2 *theLength/( a1 + an ) - 1 );
662     int     n = int( 1 + ( an - a1 ) / q );
663
664     double U1 = theReverse ? l : f;
665     double Un = theReverse ? f : l;
666     double param = U1;
667     double eltSize = a1;
668     if ( theReverse ) {
669       eltSize = -eltSize;
670       q = -q;
671     }
672     while ( n-- > 0 && eltSize * ( Un - U1 ) > 0 ) {
673       // computes a point on a curve <theC3d> at the distance <eltSize>
674       // from the point of parameter <param>.
675       GCPnts_AbscissaPoint Discret( theC3d, eltSize, param );
676       if ( !Discret.IsDone() ) break;
677       param = Discret.Parameter();
678       if ( param > f && param < l )
679         theParams.push_back( param );
680       else
681         break;
682       eltSize += q;
683     }
684     compensateError( a1, an, U1, Un, theLength, theC3d, theParams );
685
686     return true;
687   }
688
689   case DEFLECTION: {
690
691     GCPnts_UniformDeflection Discret(theC3d, _value[ DEFLECTION_IND ], f, l, true);
692     if ( !Discret.IsDone() )
693       return false;
694
695     int NbPoints = Discret.NbPoints();
696     for ( int i = 2; i < NbPoints; i++ )
697     {
698       double param = Discret.Parameter(i);
699       theParams.push_back( param );
700     }
701     return true;
702     
703   }
704
705   default:;
706   }
707
708   return false;
709 }
710
711 //=============================================================================
712 /*!
713  *  
714  */
715 //=============================================================================
716
717 bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape)
718 {
719   MESSAGE("StdMeshers_Regular_1D::Compute");
720
721   if ( _hypType == NONE )
722     return false;
723
724   SMESHDS_Mesh * meshDS = aMesh.GetMeshDS();
725
726   const TopoDS_Edge & EE = TopoDS::Edge(aShape);
727   TopoDS_Edge E = TopoDS::Edge(EE.Oriented(TopAbs_FORWARD));
728   int shapeID = meshDS->ShapeToIndex( E );
729
730   double f, l;
731   Handle(Geom_Curve) Curve = BRep_Tool::Curve(E, f, l);
732
733   TopoDS_Vertex VFirst, VLast;
734   TopExp::Vertices(E, VFirst, VLast);   // Vfirst corresponds to f and Vlast to l
735
736   ASSERT(!VFirst.IsNull());
737   const SMDS_MeshNode * idFirst = SMESH_Algo::VertexNode( VFirst, meshDS );
738   if (!idFirst) {
739     MESSAGE (" NO NODE BUILT ON VERTEX ");
740     return false;
741   }
742
743   ASSERT(!VLast.IsNull());
744   const SMDS_MeshNode * idLast = SMESH_Algo::VertexNode( VLast, meshDS );
745   if (!idLast) {
746     MESSAGE (" NO NODE BUILT ON VERTEX ");
747     return false;
748   }
749
750   if (!Curve.IsNull()) {
751     list< double > params;
752     bool reversed = false;
753     if ( !_mainEdge.IsNull() )
754       reversed = aMesh.IsReversedInChain( EE, _mainEdge );
755     BRepAdaptor_Curve C3d( E );
756     double length = EdgeLength( E );
757     try {
758 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
759       OCC_CATCH_SIGNALS;
760 #endif
761       if ( ! computeInternalParameters( C3d, length, f, l, params, reversed )) {
762         return false;
763       }
764       redistributeNearVertices( aMesh, C3d, length, params, VFirst, VLast );
765     }
766     catch ( Standard_Failure ) {
767       return false;
768     }
769
770     // edge extrema (indexes : 1 & NbPoints) already in SMDS (TopoDS_Vertex)
771     // only internal nodes receive an edge position with param on curve
772
773     const SMDS_MeshNode * idPrev = idFirst;
774     double parPrev = f;
775     double parLast = l;
776     
777     for (list<double>::iterator itU = params.begin(); itU != params.end(); itU++) {
778       double param = *itU;
779       gp_Pnt P = Curve->Value(param);
780
781       //Add the Node in the DataStructure
782       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
783       meshDS->SetNodeOnEdge(node, shapeID, param);
784
785       if(_quadraticMesh) {
786         // create medium node
787         double prm = ( parPrev + param )/2;
788         gp_Pnt PM = Curve->Value(prm);
789         SMDS_MeshNode * NM = meshDS->AddNode(PM.X(), PM.Y(), PM.Z());
790         meshDS->SetNodeOnEdge(NM, shapeID, prm);
791         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node, NM);
792         meshDS->SetMeshElementOnShape(edge, shapeID);
793       }
794       else {
795         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
796         meshDS->SetMeshElementOnShape(edge, shapeID);
797       }
798
799       idPrev = node;
800       parPrev = param;
801     }
802     if(_quadraticMesh) {
803       double prm = ( parPrev + parLast )/2;
804       gp_Pnt PM = Curve->Value(prm);
805       SMDS_MeshNode * NM = meshDS->AddNode(PM.X(), PM.Y(), PM.Z());
806       meshDS->SetNodeOnEdge(NM, shapeID, prm);
807       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast, NM);
808       meshDS->SetMeshElementOnShape(edge, shapeID);
809     }
810     else {
811       SMDS_MeshEdge* edge = meshDS->AddEdge(idPrev, idLast);
812       meshDS->SetMeshElementOnShape(edge, shapeID);
813     }
814   }
815   else {
816     // Edge is a degenerated Edge : We put n = 5 points on the edge.
817     const int NbPoints = 5;
818     double du = (l - f) / (NbPoints - 1);
819     //MESSAGE("************* Degenerated edge! *****************");
820
821     gp_Pnt P = BRep_Tool::Pnt(VFirst);
822
823     const SMDS_MeshNode * idPrev = idFirst;
824     for (int i = 2; i < NbPoints; i++) {
825       double param = f + (i - 1) * du;
826       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
827       if(_quadraticMesh) {
828         // create medium node
829         double prm = param - du/2.;
830         SMDS_MeshNode * NM = meshDS->AddNode(P.X(), P.Y(), P.Z());
831         meshDS->SetNodeOnEdge(NM, shapeID, prm);
832         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node, NM);
833         meshDS->SetMeshElementOnShape(edge, shapeID);
834       }
835       else {
836         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
837         meshDS->SetMeshElementOnShape(edge, shapeID);
838       }
839       meshDS->SetNodeOnEdge(node, shapeID, param);
840       idPrev = node;
841     }
842     if(_quadraticMesh) {
843       // create medium node
844       double prm = l - du/2.;
845       SMDS_MeshNode * NM = meshDS->AddNode(P.X(), P.Y(), P.Z());
846       meshDS->SetNodeOnEdge(NM, shapeID, prm);
847       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast, NM);
848       meshDS->SetMeshElementOnShape(edge, shapeID);
849     }
850     else {
851       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast);
852       meshDS->SetMeshElementOnShape(edge, shapeID);
853     }
854   }
855   return true;
856 }
857
858 //=============================================================================
859 /*!
860  *  See comments in SMESH_Algo.cxx
861  */
862 //=============================================================================
863
864 const list <const SMESHDS_Hypothesis *> &
865 StdMeshers_Regular_1D::GetUsedHypothesis(SMESH_Mesh &         aMesh,
866                                          const TopoDS_Shape & aShape,
867                                          const bool           ignoreAuxiliary)
868 {
869   _usedHypList.clear();
870   _mainEdge.Nullify();
871
872   SMESH_HypoFilter auxiliaryFilter, compatibleFilter;
873   auxiliaryFilter.Init( SMESH_HypoFilter::IsAuxiliary() );
874   const bool ignoreAux = true;
875   InitCompatibleHypoFilter( compatibleFilter, ignoreAux );
876
877   // get non-auxiliary assigned to aShape
878   int nbHyp = aMesh.GetHypotheses( aShape, compatibleFilter, _usedHypList, false );
879
880   if (nbHyp == 0)
881   {
882     // Check, if propagated from some other edge
883     if (aShape.ShapeType() == TopAbs_EDGE &&
884         aMesh.IsPropagatedHypothesis(aShape, _mainEdge))
885     {
886       // Propagation of 1D hypothesis from <aMainEdge> on this edge;
887       // get non-auxiliary assigned to _mainEdge
888       nbHyp = aMesh.GetHypotheses( _mainEdge, compatibleFilter, _usedHypList, true );
889     }
890   }
891
892   if (nbHyp == 0) // nothing propagated nor assigned to aShape
893   {
894     SMESH_Algo::GetUsedHypothesis( aMesh, aShape, ignoreAuxiliary );
895     nbHyp = _usedHypList.size();
896   }
897   else
898   {
899     // get auxiliary hyps from aShape
900     aMesh.GetHypotheses( aShape, auxiliaryFilter, _usedHypList, true );
901   }
902   if ( nbHyp > 1 && ignoreAuxiliary )
903     _usedHypList.clear(); //only one compatible non-auxiliary hypothesis allowed
904
905   return _usedHypList;
906 }