Salome HOME
Join modifications from BR_Dev_For_4_0 tag V4_1_1.
[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 #include "StdMeshers_Propagation.hxx"
41
42 #include "SMESH_Gen.hxx"
43 #include "SMESH_Mesh.hxx"
44 #include "SMESH_HypoFilter.hxx"
45 #include "SMESH_subMesh.hxx"
46 #include "SMESH_subMeshEventListener.hxx"
47 #include "SMESH_Comment.hxx"
48
49 #include "SMDS_MeshElement.hxx"
50 #include "SMDS_MeshNode.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
66 #include <string>
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         _compatibleHypothesis.push_back("Propagation"); // auxiliary !!!
92 }
93
94 //=============================================================================
95 /*!
96  *  
97  */
98 //=============================================================================
99
100 StdMeshers_Regular_1D::~StdMeshers_Regular_1D()
101 {
102 }
103
104 //=============================================================================
105 /*!
106  *  
107  */
108 //=============================================================================
109
110 bool StdMeshers_Regular_1D::CheckHypothesis
111                          (SMESH_Mesh&                          aMesh,
112                           const TopoDS_Shape&                  aShape,
113                           SMESH_Hypothesis::Hypothesis_Status& aStatus)
114 {
115   _hypType = NONE;
116   _quadraticMesh = false;
117
118   const bool ignoreAuxiliaryHyps = false;
119   const list <const SMESHDS_Hypothesis * > & hyps =
120     GetUsedHypothesis(aMesh, aShape, ignoreAuxiliaryHyps);
121
122   // find non-auxiliary hypothesis
123   const SMESHDS_Hypothesis *theHyp = 0;
124   list <const SMESHDS_Hypothesis * >::const_iterator h = hyps.begin();
125   for ( ; h != hyps.end(); ++h ) {
126     if ( static_cast<const SMESH_Hypothesis*>(*h)->IsAuxiliary() ) {
127       if ( strcmp( "QuadraticMesh", (*h)->GetName() ) == 0 )
128         _quadraticMesh = true;
129     }
130     else {
131       if ( !theHyp )
132         theHyp = *h; // use only the first non-auxiliary hypothesis
133     }
134   }
135
136   if ( !theHyp )
137   {
138     aStatus = SMESH_Hypothesis::HYP_MISSING;
139     return false;  // can't work without a hypothesis
140   }
141
142   string hypName = theHyp->GetName();
143
144   if (hypName == "LocalLength")
145   {
146     const StdMeshers_LocalLength * hyp =
147       dynamic_cast <const StdMeshers_LocalLength * >(theHyp);
148     ASSERT(hyp);
149     //_value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength();
150     _value[ BEG_LENGTH_IND ] = hyp->GetLength();
151     _value[ END_LENGTH_IND ] = hyp->GetPrecision();
152     ASSERT( _value[ BEG_LENGTH_IND ] > 0 );
153     _hypType = LOCAL_LENGTH;
154     aStatus = SMESH_Hypothesis::HYP_OK;
155   }
156
157   else if (hypName == "NumberOfSegments")
158   {
159     const StdMeshers_NumberOfSegments * hyp =
160       dynamic_cast <const StdMeshers_NumberOfSegments * >(theHyp);
161     ASSERT(hyp);
162     _ivalue[ NB_SEGMENTS_IND  ] = hyp->GetNumberOfSegments();
163     ASSERT( _ivalue[ NB_SEGMENTS_IND ] > 0 );
164     _ivalue[ DISTR_TYPE_IND ] = (int) hyp->GetDistrType();
165     switch (_ivalue[ DISTR_TYPE_IND ])
166     {
167     case StdMeshers_NumberOfSegments::DT_Scale:
168       _value[ SCALE_FACTOR_IND ] = hyp->GetScaleFactor();
169       break;
170     case StdMeshers_NumberOfSegments::DT_TabFunc:
171       _vvalue[ TAB_FUNC_IND ] = hyp->GetTableFunction();
172       break;
173     case StdMeshers_NumberOfSegments::DT_ExprFunc:
174       _svalue[ EXPR_FUNC_IND ] = hyp->GetExpressionFunction();
175       break;
176     case StdMeshers_NumberOfSegments::DT_Regular:
177       break;
178     default:
179       ASSERT(0);
180       break;
181     }
182     if (_ivalue[ DISTR_TYPE_IND ] == StdMeshers_NumberOfSegments::DT_TabFunc ||
183         _ivalue[ DISTR_TYPE_IND ] == StdMeshers_NumberOfSegments::DT_ExprFunc)
184         _ivalue[ CONV_MODE_IND ] = hyp->ConversionMode();
185     _hypType = NB_SEGMENTS;
186     aStatus = SMESH_Hypothesis::HYP_OK;
187   }
188
189   else if (hypName == "Arithmetic1D")
190   {
191     const StdMeshers_Arithmetic1D * hyp =
192       dynamic_cast <const StdMeshers_Arithmetic1D * >(theHyp);
193     ASSERT(hyp);
194     _value[ BEG_LENGTH_IND ] = hyp->GetLength( true );
195     _value[ END_LENGTH_IND ] = hyp->GetLength( false );
196     ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 );
197     _hypType = ARITHMETIC_1D;
198     aStatus = SMESH_Hypothesis::HYP_OK;
199   }
200
201   else if (hypName == "StartEndLength")
202   {
203     const StdMeshers_StartEndLength * hyp =
204       dynamic_cast <const StdMeshers_StartEndLength * >(theHyp);
205     ASSERT(hyp);
206     _value[ BEG_LENGTH_IND ] = hyp->GetLength( true );
207     _value[ END_LENGTH_IND ] = hyp->GetLength( false );
208     ASSERT( _value[ BEG_LENGTH_IND ] > 0 && _value[ END_LENGTH_IND ] > 0 );
209     _hypType = BEG_END_LENGTH;
210     aStatus = SMESH_Hypothesis::HYP_OK;
211   }
212
213   else if (hypName == "Deflection1D")
214   {
215     const StdMeshers_Deflection1D * hyp =
216       dynamic_cast <const StdMeshers_Deflection1D * >(theHyp);
217     ASSERT(hyp);
218     _value[ DEFLECTION_IND ] = hyp->GetDeflection();
219     ASSERT( _value[ DEFLECTION_IND ] > 0 );
220     _hypType = DEFLECTION;
221     aStatus = SMESH_Hypothesis::HYP_OK;
222   }
223
224   else if (hypName == "AutomaticLength")
225   {
226     StdMeshers_AutomaticLength * hyp = const_cast<StdMeshers_AutomaticLength *>
227       (dynamic_cast <const StdMeshers_AutomaticLength * >(theHyp));
228     ASSERT(hyp);
229     //_value[ BEG_LENGTH_IND ] = _value[ END_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape );
230     _value[ BEG_LENGTH_IND ] = hyp->GetLength( &aMesh, aShape );
231     _value[ END_LENGTH_IND ] = Precision::Confusion(); // ?? or set to zero?
232     ASSERT( _value[ BEG_LENGTH_IND ] > 0 );
233     _hypType = LOCAL_LENGTH;
234     aStatus = SMESH_Hypothesis::HYP_OK;
235   }
236   else
237     aStatus = SMESH_Hypothesis::HYP_INCOMPATIBLE;
238
239   return ( _hypType != NONE );
240 }
241
242 static bool computeParamByFunc(Adaptor3d_Curve& C3d, double first, double last,
243                                double length, bool theReverse,
244                                int nbSeg, Function& func,
245                                list<double>& theParams)
246 {
247   // never do this way
248   //OSD::SetSignal( true );
249
250   if (nbSeg <= 0)
251     return false;
252
253   MESSAGE( "computeParamByFunc" );
254
255   int nbPnt = 1 + nbSeg;
256   vector<double> x(nbPnt, 0.);
257
258   if (!buildDistribution(func, 0.0, 1.0, nbSeg, x, 1E-4))
259      return false;
260
261   MESSAGE( "Points:\n" );
262   char buf[1024];
263   for ( int i=0; i<=nbSeg; i++ )
264   {
265     sprintf(  buf, "%f\n", float(x[i] ) );
266     MESSAGE( buf );
267   }
268
269
270
271   // apply parameters in range [0,1] to the space of the curve
272   double prevU = first;
273   double sign = 1.;
274   if (theReverse)
275   {
276     prevU = last;
277     sign = -1.;
278   }
279   for( int i = 1; i < nbSeg; i++ )
280   {
281     double curvLength = length * (x[i] - x[i-1]) * sign;
282     GCPnts_AbscissaPoint Discret( C3d, curvLength, prevU );
283     if ( !Discret.IsDone() )
284       return false;
285     double U = Discret.Parameter();
286     if ( U > first && U < last )
287       theParams.push_back( U );
288     else
289       return false;
290     prevU = U;
291   }
292   return true;
293 }
294
295
296 //================================================================================
297 /*!
298  * \brief adjust internal node parameters so that the last segment length == an
299   * \param a1 - the first segment length
300   * \param an - the last segment length
301   * \param U1 - the first edge parameter
302   * \param Un - the last edge parameter
303   * \param length - the edge length
304   * \param C3d - the edge curve
305   * \param theParams - internal node parameters to adjust
306   * \param adjustNeighbors2an - to adjust length of segments next to the last one
307   *  and not to remove parameters
308  */
309 //================================================================================
310
311 static void compensateError(double a1, double an,
312                             double U1, double Un,
313                             double            length,
314                             Adaptor3d_Curve&  C3d,
315                             list<double> &    theParams,
316                             bool              adjustNeighbors2an = false)
317 {
318   int i, nPar = theParams.size();
319   if ( a1 + an < length && nPar > 1 )
320   {
321     bool reverse = ( U1 > Un );
322     GCPnts_AbscissaPoint Discret(C3d, reverse ? an : -an, Un);
323     if ( !Discret.IsDone() )
324       return;
325     double Utgt = Discret.Parameter(); // target value of the last parameter
326     list<double>::reverse_iterator itU = theParams.rbegin();
327     double Ul = *itU++; // real value of the last parameter
328     double dUn = Utgt - Ul; // parametric error of <an>
329     if ( Abs(dUn) <= Precision::Confusion() )
330       return;
331     double dU = Abs( Ul - *itU ); // parametric length of the last but one segment
332     if ( adjustNeighbors2an || Abs(dUn) < 0.5 * dU ) { // last segment is a bit shorter than it should
333       // move the last parameter to the edge beginning
334     }
335     else {  // last segment is much shorter than it should -> remove the last param and
336       theParams.pop_back(); nPar--; // move the rest points toward the edge end
337       dUn = Utgt - theParams.back();
338     }
339
340     double q  = dUn / ( nPar - 1 );
341     if ( !adjustNeighbors2an ) {
342       for ( itU = theParams.rbegin(), i = 1; i < nPar; itU++, i++ ) {
343         (*itU) += dUn;
344         dUn -= q;
345       }
346     }
347     else {
348       theParams.back() += dUn;
349       double sign = reverse ? -1 : 1;
350       double prevU = theParams.back();
351       itU = theParams.rbegin();
352       for ( ++itU, i = 2; i < nPar; ++itU, i++ ) {
353         double newU = *itU + dUn;
354         if ( newU*sign < prevU*sign ) {
355           prevU = *itU = newU;
356           dUn -= q;
357         }
358         else { // set U between prevU and next valid param
359           list<double>::reverse_iterator itU2 = itU;
360           ++itU2;
361           int nb = 2;
362           while ( (*itU2)*sign > prevU*sign ) {
363             ++itU2; ++nb;
364           }
365           dU = ( *itU2 - prevU ) / nb;
366           while ( itU != itU2 ) {
367             *itU += dU; ++itU;
368           }
369           break;
370         }
371       }
372     }
373   }
374 }
375
376 //================================================================================
377 /*!
378  * \brief Class used to clean mesh on edges when 0D hyp modified.
379  * Common approach doesn't work when 0D algo is missing because the 0D hyp is
380  * considered as not participating in computation whereas it is used by 1D algo.
381  */
382 //================================================================================
383
384 // struct VertexEventListener : public SMESH_subMeshEventListener
385 // {
386 //   VertexEventListener():SMESH_subMeshEventListener(0) // won't be deleted by submesh
387 //   {}
388 //   /*!
389 //    * \brief Clean mesh on edges
390 //    * \param event - algo_event or compute_event itself (of SMESH_subMesh)
391 //    * \param eventType - ALGO_EVENT or COMPUTE_EVENT (of SMESH_subMesh)
392 //    * \param subMesh - the submesh where the event occures
393 //    */
394 //   void ProcessEvent(const int event, const int eventType, SMESH_subMesh* subMesh,
395 //                     EventListenerData*, const SMESH_Hypothesis*)
396 //   {
397 //     if ( eventType == SMESH_subMesh::ALGO_EVENT) // all algo events
398 //     {
399 //       subMesh->ComputeStateEngine( SMESH_subMesh::MODIF_ALGO_STATE );
400 //     }
401 //   }
402 // }; // struct VertexEventListener
403
404 //=============================================================================
405 /*!
406  * \brief Sets event listener to vertex submeshes
407  * \param subMesh - submesh where algo is set
408  *
409  * This method is called when a submesh gets HYP_OK algo_state.
410  * After being set, event listener is notified on each event of a submesh.
411  */
412 //=============================================================================
413
414 void StdMeshers_Regular_1D::SetEventListener(SMESH_subMesh* subMesh)
415 {
416 //   static VertexEventListener listener;
417 //   SMESH_subMeshIteratorPtr smIt = subMesh->getDependsOnIterator(false,false);
418 //   while (smIt->more()) {
419 //     subMesh->SetEventListener( &listener, 0, smIt->next() );
420 //   }
421   StdMeshers_Propagation::SetPropagationMgr( subMesh );
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("SegmentAroundVertex_0D"));
448   if ( const SMESH_Hypothesis * h = theMesh.GetHypothesis( theV, filter, true ))
449   {
450     SMESH_Algo* algo = const_cast< SMESH_Algo* >( static_cast< const SMESH_Algo* > ( h ));
451     const list <const SMESHDS_Hypothesis *> & hypList = algo->GetUsedHypothesis( theMesh, theV, 0 );
452     if ( !hypList.empty() && string("SegmentLengthAroundVertex") == hypList.front()->GetName() )
453       return static_cast<const StdMeshers_SegmentLengthAroundVertex*>( hypList.front() );
454   }
455   return 0;
456 }
457
458 //================================================================================
459 /*!
460  * \brief Tune parameters to fit "SegmentLengthAroundVertex" hypothesis
461   * \param theC3d - wire curve
462   * \param theLength - curve length
463   * \param theParameters - internal nodes parameters to modify
464   * \param theVf - 1st vertex
465   * \param theVl - 2nd vertex
466  */
467 //================================================================================
468
469 void StdMeshers_Regular_1D::redistributeNearVertices (SMESH_Mesh &          theMesh,
470                                                       Adaptor3d_Curve &     theC3d,
471                                                       double                theLength,
472                                                       std::list< double > & theParameters,
473                                                       const TopoDS_Vertex & theVf,
474                                                       const TopoDS_Vertex & theVl)
475 {
476   double f = theC3d.FirstParameter(), l = theC3d.LastParameter();
477   int nPar = theParameters.size();
478   for ( int isEnd1 = 0; isEnd1 < 2; ++isEnd1 )
479   {
480     const TopoDS_Vertex & V = isEnd1 ? theVf : theVl;
481     const StdMeshers_SegmentLengthAroundVertex* hyp = getVertexHyp (theMesh, V );
482     if ( hyp ) {
483       double vertexLength = hyp->GetLength();
484       if ( vertexLength > theLength / 2.0 )
485         continue;
486       if ( isEnd1 ) { // to have a segment of interest at end of theParameters
487         theParameters.reverse();
488         std::swap( f, l );
489       }
490       if ( _hypType == NB_SEGMENTS )
491       {
492         compensateError(0, vertexLength, f, l, theLength, theC3d, theParameters, true );
493       }
494       else if ( nPar <= 3 )
495       {
496         if ( !isEnd1 )
497           vertexLength = -vertexLength;
498         GCPnts_AbscissaPoint Discret(theC3d, vertexLength, l);
499         if ( Discret.IsDone() ) {
500           if ( nPar == 0 )
501             theParameters.push_back( Discret.Parameter());
502           else {
503             double L = GCPnts_AbscissaPoint::Length( theC3d, theParameters.back(), l);
504             if ( vertexLength < L / 2.0 )
505               theParameters.push_back( Discret.Parameter());
506             else
507               compensateError(0, vertexLength, f, l, theLength, theC3d, theParameters, true );
508           }
509         }
510       }
511       else
512       {
513         // recompute params between the last segment and a middle one.
514         // find size of a middle segment
515         int nHalf = ( nPar-1 ) / 2;
516         list< double >::reverse_iterator itU = theParameters.rbegin();
517         std::advance( itU, nHalf );
518         double Um = *itU++;
519         double Lm = GCPnts_AbscissaPoint::Length( theC3d, Um, *itU);
520         double L = GCPnts_AbscissaPoint::Length( theC3d, *itU, l);
521         StdMeshers_Regular_1D algo( *this );
522         algo._hypType = BEG_END_LENGTH;
523         algo._value[ BEG_LENGTH_IND ] = Lm;
524         algo._value[ END_LENGTH_IND ] = vertexLength;
525         double from = *itU, to = l;
526         if ( isEnd1 ) {
527           std::swap( from, to );
528           std::swap( algo._value[ BEG_LENGTH_IND ], algo._value[ END_LENGTH_IND ]);
529         }
530         list<double> params;
531         if ( algo.computeInternalParameters( theMesh, theC3d, L, from, to, params, false ))
532         {
533           if ( isEnd1 ) params.reverse();
534           while ( 1 + nHalf-- )
535             theParameters.pop_back();
536           theParameters.splice( theParameters.end(), params );
537         }
538         else
539         {
540           compensateError(0, vertexLength, f, l, theLength, theC3d, theParameters, true );
541         }
542       }
543       if ( isEnd1 )
544         theParameters.reverse();
545     }
546   }
547 }
548
549 //=============================================================================
550 /*!
551  *  
552  */
553 //=============================================================================
554 bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh &     theMesh,
555                                                       Adaptor3d_Curve& theC3d,
556                                                       double           theLength,
557                                                       double           theFirstU,
558                                                       double           theLastU,
559                                                       list<double> &   theParams,
560                                                       const bool       theReverse,
561                                                       bool             theConsiderPropagation)
562 {
563   theParams.clear();
564
565   double f = theFirstU, l = theLastU;
566
567   switch( _hypType )
568   {
569   case LOCAL_LENGTH:
570   case NB_SEGMENTS: {
571
572     double eltSize = 1;
573     if ( _hypType == LOCAL_LENGTH )
574     {
575       // Local Length hypothesis
576       double nbseg = ceil(theLength / _value[ BEG_LENGTH_IND ]); // integer sup
577
578       // NPAL17873:
579       bool isFound = false;
580       if (theConsiderPropagation && !_mainEdge.IsNull()) // propagated from some other edge
581       {
582         // Advanced processing to assure equal number of segments in case of Propagation
583         SMESH_subMesh* sm = theMesh.GetSubMeshContaining(_mainEdge);
584         if (sm) {
585           bool computed = sm->IsMeshComputed();
586           if (!computed) {
587             if (sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE) {
588               sm->ComputeStateEngine(SMESH_subMesh::COMPUTE);
589               computed = sm->IsMeshComputed();
590             }
591           }
592           if (computed) {
593             SMESHDS_SubMesh* smds = sm->GetSubMeshDS();
594             int nb_segments = smds->NbElements();
595             if (nbseg - 1 <= nb_segments && nb_segments <= nbseg + 1) {
596               isFound = true;
597               nbseg = nb_segments;
598             }
599           }
600         }
601       }
602       if (!isFound) // not found by meshed edge in the propagation chain, use precision
603       {
604         double aPrecision = _value[ END_LENGTH_IND ];
605         double nbseg_prec = ceil((theLength / _value[ BEG_LENGTH_IND ]) - aPrecision);
606         if (nbseg_prec == (nbseg - 1)) nbseg--;
607       }
608
609       if (nbseg <= 0)
610         nbseg = 1;                        // degenerated edge
611       eltSize = theLength / nbseg;
612     }
613     else
614     {
615       // Number Of Segments hypothesis
616       int NbSegm = _ivalue[ NB_SEGMENTS_IND ];
617       if ( NbSegm < 1 )  return false;
618       if ( NbSegm == 1 ) return true;
619
620       switch (_ivalue[ DISTR_TYPE_IND ])
621       {
622       case StdMeshers_NumberOfSegments::DT_Scale:
623         {
624           double scale = _value[ SCALE_FACTOR_IND ];
625
626           if (fabs(scale - 1.0) < Precision::Confusion()) {
627             // special case to avoid division on zero
628             for (int i = 1; i < NbSegm; i++) {
629               double param = f + (l - f) * i / NbSegm;
630               theParams.push_back( param );
631             }
632           } else {
633             // general case of scale distribution
634             if ( theReverse )
635               scale = 1.0 / scale;
636
637             double alpha = pow(scale, 1.0 / (NbSegm - 1));
638             double factor = (l - f) / (1.0 - pow(alpha, NbSegm));
639
640             for (int i = 1; i < NbSegm; i++) {
641               double param = f + factor * (1.0 - pow(alpha, i));
642               theParams.push_back( param );
643             }
644           }
645           return true;
646         }
647         break;
648       case StdMeshers_NumberOfSegments::DT_TabFunc:
649         {
650           FunctionTable func(_vvalue[ TAB_FUNC_IND ], _ivalue[ CONV_MODE_IND ]);
651           return computeParamByFunc(theC3d, f, l, theLength, theReverse,
652                                     _ivalue[ NB_SEGMENTS_IND ], func,
653                                     theParams);
654         }
655         break;
656       case StdMeshers_NumberOfSegments::DT_ExprFunc:
657         {
658           FunctionExpr func(_svalue[ EXPR_FUNC_IND ].c_str(), _ivalue[ CONV_MODE_IND ]);
659           return computeParamByFunc(theC3d, f, l, theLength, theReverse,
660                                     _ivalue[ NB_SEGMENTS_IND ], func,
661                                     theParams);
662         }
663         break;
664       case StdMeshers_NumberOfSegments::DT_Regular:
665         eltSize = theLength / _ivalue[ NB_SEGMENTS_IND ];
666         break;
667       default:
668         return false;
669       }
670     }
671     GCPnts_UniformAbscissa Discret(theC3d, eltSize, f, l);
672     if ( !Discret.IsDone() )
673       return error( "GCPnts_UniformAbscissa failed");
674
675     int NbPoints = Discret.NbPoints();
676     for ( int i = 2; i < NbPoints; i++ )
677     {
678       double param = Discret.Parameter(i);
679       theParams.push_back( param );
680     }
681     compensateError( eltSize, eltSize, f, l, theLength, theC3d, theParams ); // for PAL9899
682     return true;
683   }
684
685   case BEG_END_LENGTH: {
686
687     // geometric progression: SUM(n) = ( a1 - an * q ) / ( 1 - q ) = theLength
688
689     double a1 = _value[ BEG_LENGTH_IND ];
690     double an = _value[ END_LENGTH_IND ];
691     double q  = ( theLength - a1 ) / ( theLength - an );
692
693     double U1 = theReverse ? l : f;
694     double Un = theReverse ? f : l;
695     double param = U1;
696     double eltSize = theReverse ? -a1 : a1;
697     while ( 1 ) {
698       // computes a point on a curve <theC3d> at the distance <eltSize>
699       // from the point of parameter <param>.
700       GCPnts_AbscissaPoint Discret( theC3d, eltSize, param );
701       if ( !Discret.IsDone() ) break;
702       param = Discret.Parameter();
703       if ( f < param && param < l )
704         theParams.push_back( param );
705       else
706         break;
707       eltSize *= q;
708     }
709     compensateError( a1, an, U1, Un, theLength, theC3d, theParams );
710     if (theReverse) theParams.reverse(); // NPAL18025
711     return true;
712   }
713
714   case ARITHMETIC_1D: {
715
716     // arithmetic progression: SUM(n) = ( an - a1 + q ) * ( a1 + an ) / ( 2 * q ) = theLength
717
718     double a1 = _value[ BEG_LENGTH_IND ];
719     double an = _value[ END_LENGTH_IND ];
720
721     double  q = ( an - a1 ) / ( 2 *theLength/( a1 + an ) - 1 );
722     int     n = int( 1 + ( an - a1 ) / q );
723
724     double U1 = theReverse ? l : f;
725     double Un = theReverse ? f : l;
726     double param = U1;
727     double eltSize = a1;
728     if ( theReverse ) {
729       eltSize = -eltSize;
730       q = -q;
731     }
732     while ( n-- > 0 && eltSize * ( Un - U1 ) > 0 ) {
733       // computes a point on a curve <theC3d> at the distance <eltSize>
734       // from the point of parameter <param>.
735       GCPnts_AbscissaPoint Discret( theC3d, eltSize, param );
736       if ( !Discret.IsDone() ) break;
737       param = Discret.Parameter();
738       if ( param > f && param < l )
739         theParams.push_back( param );
740       else
741         break;
742       eltSize += q;
743     }
744     compensateError( a1, an, U1, Un, theLength, theC3d, theParams );
745     if (theReverse) theParams.reverse(); // NPAL18025
746
747     return true;
748   }
749
750   case DEFLECTION: {
751
752     GCPnts_UniformDeflection Discret(theC3d, _value[ DEFLECTION_IND ], f, l, true);
753     if ( !Discret.IsDone() )
754       return false;
755
756     int NbPoints = Discret.NbPoints();
757     for ( int i = 2; i < NbPoints; i++ )
758     {
759       double param = Discret.Parameter(i);
760       theParams.push_back( param );
761     }
762     return true;
763   }
764
765   default:;
766   }
767
768   return false;
769 }
770
771 //=============================================================================
772 /*!
773  *  
774  */
775 //=============================================================================
776
777 bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & theShape)
778 {
779   if ( _hypType == NONE )
780     return false;
781
782   SMESHDS_Mesh * meshDS = theMesh.GetMeshDS();
783
784   const TopoDS_Edge & EE = TopoDS::Edge(theShape);
785   TopoDS_Edge E = TopoDS::Edge(EE.Oriented(TopAbs_FORWARD));
786   int shapeID = meshDS->ShapeToIndex( E );
787
788   double f, l;
789   Handle(Geom_Curve) Curve = BRep_Tool::Curve(E, f, l);
790
791   TopoDS_Vertex VFirst, VLast;
792   TopExp::Vertices(E, VFirst, VLast);   // Vfirst corresponds to f and Vlast to l
793
794   ASSERT(!VFirst.IsNull());
795   ASSERT(!VLast.IsNull());
796   const SMDS_MeshNode * idFirst = SMESH_Algo::VertexNode( VFirst, meshDS );
797   const SMDS_MeshNode * idLast = SMESH_Algo::VertexNode( VLast, meshDS );
798   if (!idFirst || !idLast)
799     return error( COMPERR_BAD_INPUT_MESH, "No node on vertex");
800
801   if (!Curve.IsNull())
802   {
803     list< double > params;
804     bool reversed = false;
805     if ( !_mainEdge.IsNull() )
806       reversed = ( _mainEdge.Orientation() == TopAbs_REVERSED );
807
808     BRepAdaptor_Curve C3d( E );
809     double length = EdgeLength( E );
810     if ( ! computeInternalParameters( theMesh, C3d, length, f, l, params, reversed, true )) {
811       return false;
812     }
813     redistributeNearVertices( theMesh, C3d, length, params, VFirst, VLast );
814
815     // edge extrema (indexes : 1 & NbPoints) already in SMDS (TopoDS_Vertex)
816     // only internal nodes receive an edge position with param on curve
817
818     const SMDS_MeshNode * idPrev = idFirst;
819     double parPrev = f;
820     double parLast = l;
821
822     /* NPAL18025
823     if (reversed) {
824       idPrev = idLast;
825       idLast = idFirst;
826       idFirst = idPrev;
827       parPrev = l;
828       parLast = f;
829     }
830     */
831
832     for (list<double>::iterator itU = params.begin(); itU != params.end(); itU++) {
833       double param = *itU;
834       gp_Pnt P = Curve->Value(param);
835
836       //Add the Node in the DataStructure
837       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
838       meshDS->SetNodeOnEdge(node, shapeID, param);
839
840       if(_quadraticMesh) {
841         // create medium node
842         double prm = ( parPrev + param )/2;
843         gp_Pnt PM = Curve->Value(prm);
844         SMDS_MeshNode * NM = meshDS->AddNode(PM.X(), PM.Y(), PM.Z());
845         meshDS->SetNodeOnEdge(NM, shapeID, prm);
846         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node, NM);
847         meshDS->SetMeshElementOnShape(edge, shapeID);
848       }
849       else {
850         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
851         meshDS->SetMeshElementOnShape(edge, shapeID);
852       }
853
854       idPrev = node;
855       parPrev = param;
856     }
857     if(_quadraticMesh) {
858       double prm = ( parPrev + parLast )/2;
859       gp_Pnt PM = Curve->Value(prm);
860       SMDS_MeshNode * NM = meshDS->AddNode(PM.X(), PM.Y(), PM.Z());
861       meshDS->SetNodeOnEdge(NM, shapeID, prm);
862       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast, NM);
863       meshDS->SetMeshElementOnShape(edge, shapeID);
864     }
865     else {
866       SMDS_MeshEdge* edge = meshDS->AddEdge(idPrev, idLast);
867       meshDS->SetMeshElementOnShape(edge, shapeID);
868     }
869   }
870   else
871   {
872     //MESSAGE("************* Degenerated edge! *****************");
873
874     // Edge is a degenerated Edge : We put n = 5 points on the edge.
875     const int NbPoints = 5;
876     BRep_Tool::Range( E, f, l ); // PAL15185
877     double du = (l - f) / (NbPoints - 1);
878
879     gp_Pnt P = BRep_Tool::Pnt(VFirst);
880
881     const SMDS_MeshNode * idPrev = idFirst;
882     for (int i = 2; i < NbPoints; i++) {
883       double param = f + (i - 1) * du;
884       SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z());
885       if(_quadraticMesh) {
886         // create medium node
887         double prm = param - du/2.;
888         SMDS_MeshNode * NM = meshDS->AddNode(P.X(), P.Y(), P.Z());
889         meshDS->SetNodeOnEdge(NM, shapeID, prm);
890         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node, NM);
891         meshDS->SetMeshElementOnShape(edge, shapeID);
892       }
893       else {
894         SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, node);
895         meshDS->SetMeshElementOnShape(edge, shapeID);
896       }
897       meshDS->SetNodeOnEdge(node, shapeID, param);
898       idPrev = node;
899     }
900     if(_quadraticMesh) {
901       // create medium node
902       double prm = l - du/2.;
903       SMDS_MeshNode * NM = meshDS->AddNode(P.X(), P.Y(), P.Z());
904       meshDS->SetNodeOnEdge(NM, shapeID, prm);
905       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast, NM);
906       meshDS->SetMeshElementOnShape(edge, shapeID);
907     }
908     else {
909       SMDS_MeshEdge * edge = meshDS->AddEdge(idPrev, idLast);
910       meshDS->SetMeshElementOnShape(edge, shapeID);
911     }
912   }
913   return true;
914 }
915
916 //=============================================================================
917 /*!
918  *  See comments in SMESH_Algo.cxx
919  */
920 //=============================================================================
921
922 const list <const SMESHDS_Hypothesis *> &
923 StdMeshers_Regular_1D::GetUsedHypothesis(SMESH_Mesh &         aMesh,
924                                          const TopoDS_Shape & aShape,
925                                          const bool           ignoreAuxiliary)
926 {
927   _usedHypList.clear();
928   _mainEdge.Nullify();
929
930   SMESH_HypoFilter auxiliaryFilter, compatibleFilter;
931   auxiliaryFilter.Init( SMESH_HypoFilter::IsAuxiliary() );
932   const bool ignoreAux = true;
933   InitCompatibleHypoFilter( compatibleFilter, ignoreAux );
934
935   // get non-auxiliary assigned to aShape
936   int nbHyp = aMesh.GetHypotheses( aShape, compatibleFilter, _usedHypList, false );
937
938   if (nbHyp == 0 && aShape.ShapeType() == TopAbs_EDGE)
939   {
940     // Check, if propagated from some other edge
941     _mainEdge = StdMeshers_Propagation::GetPropagationSource( aMesh, aShape );
942     if ( !_mainEdge.IsNull() )
943     {
944       // Propagation of 1D hypothesis from <aMainEdge> on this edge;
945       // get non-auxiliary assigned to _mainEdge
946       nbHyp = aMesh.GetHypotheses( _mainEdge, compatibleFilter, _usedHypList, true );
947     }
948   }
949
950   if (nbHyp == 0) // nothing propagated nor assigned to aShape
951   {
952     SMESH_Algo::GetUsedHypothesis( aMesh, aShape, ignoreAuxiliary );
953     nbHyp = _usedHypList.size();
954   }
955   else
956   {
957     // get auxiliary hyps from aShape
958     aMesh.GetHypotheses( aShape, auxiliaryFilter, _usedHypList, true );
959   }
960   if ( nbHyp > 1 && ignoreAuxiliary )
961     _usedHypList.clear(); //only one compatible non-auxiliary hypothesis allowed
962
963   return _usedHypList;
964 }