Salome HOME
#18963 Minimize compiler warnings
[modules/smesh.git] / src / StdMeshers / StdMeshers_NumberOfSegments.cxx
1 // Copyright (C) 2007-2020  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 //  SMESH SMESH : implementation of SMESH idl descriptions
24 //  File   : StdMeshers_NumberOfSegments.cxx
25 //           Moved here from SMESH_NumberOfSegments.cxx
26 //  Author : Paul RASCLE, EDF
27 //  Module : SMESH
28 //
29 #include "StdMeshers_NumberOfSegments.hxx"
30
31 #include "SMESHDS_Mesh.hxx"
32 #include "SMESHDS_SubMesh.hxx"
33 #include "SMESH_Comment.hxx"
34 #include "SMESH_Mesh.hxx"
35 #include "StdMeshers_Distribution.hxx"
36
37 #include <ExprIntrp_GenExp.hxx>
38 #include <Expr_Array1OfNamedUnknown.hxx>
39 #include <Expr_NamedUnknown.hxx>
40 #include <TColStd_Array1OfReal.hxx>
41 #include <TCollection_AsciiString.hxx>
42 #include <TopExp.hxx>
43 #include <TopTools_IndexedMapOfShape.hxx>
44
45 #include <Standard_Failure.hxx>
46 #include <Standard_ErrorHandler.hxx>
47
48 #include <Basics_Utils.hxx>
49
50 using namespace StdMeshers;
51 using namespace std;
52
53 const double PRECISION = 1e-7;
54
55 //=============================================================================
56 /*!
57  *  
58  */
59 //=============================================================================
60
61 StdMeshers_NumberOfSegments::StdMeshers_NumberOfSegments(int         hypId,
62                                                          SMESH_Gen * gen)
63   : StdMeshers_Reversible1D(hypId, gen),
64     _numberOfSegments(15),//issue 19923
65     _distrType(DT_Regular),
66     _scaleFactor(1.),
67     _convMode(1)  //cut negative by default
68 {
69   _name = "NumberOfSegments";
70   _param_algo_dim = 1;
71 }
72
73 //=============================================================================
74 /*!
75  *  
76  */
77 //=============================================================================
78
79 StdMeshers_NumberOfSegments::~StdMeshers_NumberOfSegments()
80 {
81 }
82
83 //=============================================================================
84 /*!
85  *  
86  */
87 //=============================================================================
88 const vector<double>&
89 StdMeshers_NumberOfSegments::BuildDistributionExpr( const char* expr,int nbSeg,int conv )
90 {
91   if( !buildDistribution( TCollection_AsciiString( ( Standard_CString )expr ), conv, 0.0, 1.0, nbSeg, _distr, 1E-4 ) )
92     _distr.resize( 0 );
93   return _distr;
94 }
95
96 const vector<double>&
97 StdMeshers_NumberOfSegments::BuildDistributionTab( const vector<double>& tab,
98                                                    int nbSeg,
99                                                    int conv )
100 {
101   if( !buildDistribution( tab, conv, 0.0, 1.0, nbSeg, _distr, 1E-4 ) )
102     _distr.resize( 0 );
103   return _distr;
104 }
105
106 //=============================================================================
107 /*!
108  *  
109  */
110 //=============================================================================
111
112 void StdMeshers_NumberOfSegments::SetNumberOfSegments(int segmentsNumber)
113 {
114   int oldNumberOfSegments = _numberOfSegments;
115   if (segmentsNumber <= 0)
116     throw SALOME_Exception(LOCALIZED("number of segments must be positive"));
117   _numberOfSegments = segmentsNumber;
118
119   if (oldNumberOfSegments != _numberOfSegments)
120     NotifySubMeshesHypothesisModification();
121 }
122
123 //=============================================================================
124 /*!
125  *  
126  */
127 //=============================================================================
128
129 int StdMeshers_NumberOfSegments::GetNumberOfSegments() const
130 {
131   return _numberOfSegments;
132 }
133
134 //================================================================================
135 /*!
136  * 
137  */
138 //================================================================================
139
140 void StdMeshers_NumberOfSegments::SetDistrType(DistrType typ)
141 {
142   if (typ < DT_Regular || typ > DT_ExprFunc)
143     throw SALOME_Exception(LOCALIZED("distribution type is out of range"));
144
145   if (typ != _distrType)
146   {
147     _distrType = typ;
148     NotifySubMeshesHypothesisModification();
149   }
150 }
151
152 //================================================================================
153 /*!
154  * 
155  */
156 //================================================================================
157
158 StdMeshers_NumberOfSegments::DistrType StdMeshers_NumberOfSegments::GetDistrType() const
159 {
160   return _distrType;
161 }
162
163 //================================================================================
164 /*!
165  * 
166  */
167 //================================================================================
168
169 void StdMeshers_NumberOfSegments::SetScaleFactor(double scaleFactor)
170 {
171   if (scaleFactor < PRECISION)
172     throw SALOME_Exception(LOCALIZED("scale factor must be positive"));
173
174   if (_distrType != DT_Scale)
175     _distrType = DT_Scale;
176
177 //  commented by mpa for IPAL 52986
178 //  if ( fabs(scaleFactor - 1.0) < PRECISION )
179 //    _distrType = DT_Regular;
180
181   if ( fabs(_scaleFactor - scaleFactor) > PRECISION )
182   {
183     _scaleFactor = scaleFactor;
184     NotifySubMeshesHypothesisModification();
185   }
186 }
187
188 //================================================================================
189 /*!
190  *
191  */
192 //================================================================================
193
194 double StdMeshers_NumberOfSegments::GetScaleFactor() const
195 {
196   if (_distrType != DT_Scale)
197     throw SALOME_Exception(LOCALIZED("not a scale distribution"));
198   return _scaleFactor;
199 }
200
201 //================================================================================
202 /*!
203  *
204  */
205 //================================================================================
206
207 void StdMeshers_NumberOfSegments::SetTableFunction(const vector<double>& table)
208 {
209   if (_distrType != DT_TabFunc)
210     _distrType = DT_TabFunc;
211   //throw SALOME_Exception(LOCALIZED("not a table function distribution"));
212   if ( (table.size() % 2) != 0 )
213     throw SALOME_Exception(LOCALIZED("odd size of vector of table function"));
214
215   double prev = -PRECISION;
216   bool isSame = table.size() == _table.size();
217
218   bool pos = false;
219   for ( size_t i = 0; i < table.size() / 2; i++ )
220   {
221     double par = table[i*2];
222     double val = table[i*2+1];
223     if( _convMode==0 )
224     {
225       try {
226         OCC_CATCH_SIGNALS;
227         val = pow( 10.0, val );
228       }
229       catch(Standard_Failure&) {
230         throw SALOME_Exception( LOCALIZED( "invalid value"));
231         return;
232       }
233     }
234     else if( _convMode==1 && val<0.0 )
235       val = 0.0;
236
237     if ( par < 0 || par > 1)
238       throw SALOME_Exception(LOCALIZED("parameter of table function is out of range [0,1]"));
239     if ( fabs(par-prev) < PRECISION )
240       throw SALOME_Exception(LOCALIZED("two parameters are the same"));
241     if ( val < 0 )
242       throw SALOME_Exception(LOCALIZED("value of table function is not positive"));
243     if( val > PRECISION )
244       pos = true;
245     if (isSame)
246     {
247       double oldpar = _table[i*2];
248       double oldval = _table[i*2+1];
249       if ( fabs(par - oldpar) > PRECISION || fabs(val - oldval) > PRECISION )
250         isSame = false;
251     }
252     prev = par;
253   }
254
255   if( !pos )
256     throw SALOME_Exception(LOCALIZED("value of table function is not positive"));
257
258   if ( pos && !isSame )
259   {
260     _table = table;
261     NotifySubMeshesHypothesisModification();
262   }
263 }
264
265 //================================================================================
266 /*!
267  *
268  */
269 //================================================================================
270
271 const vector<double>& StdMeshers_NumberOfSegments::GetTableFunction() const
272 {
273   if (_distrType != DT_TabFunc)
274     throw SALOME_Exception(LOCALIZED("not a table function distribution"));
275   return _table;
276 }
277
278 //================================================================================
279 /*! check if only 't' is unknown variable in expression
280  */
281 //================================================================================
282 bool isCorrectArg( const Handle( Expr_GeneralExpression )& expr )
283 {
284   Handle( Expr_NamedUnknown ) sub = Handle( Expr_NamedUnknown )::DownCast( expr );
285   if( !sub.IsNull() )
286     return sub->GetName()=="t";
287
288   bool res = true;
289   for( int i=1, n=expr->NbSubExpressions(); i<=n && res; i++ )
290   {
291     Handle( Expr_GeneralExpression ) sub = expr->SubExpression( i );
292     Handle( Expr_NamedUnknown ) name = Handle( Expr_NamedUnknown )::DownCast( sub );
293     if( !name.IsNull() )
294     {
295       if( name->GetName()!="t" )
296         res = false;
297     }
298     else
299       res = isCorrectArg( sub );
300   }
301   return res;
302 }
303
304 //================================================================================
305 /*! this function parses the expression 'str' in order to check if syntax is correct
306  *  ( result in 'syntax' ) and if only 't' is unknown variable in expression ( result in 'args' )
307  */
308 //================================================================================
309 bool process( const TCollection_AsciiString& str, int convMode,
310               bool& syntax, bool& args,
311               bool& non_neg, bool& non_zero,
312               bool& singulars, double& sing_point )
313 {
314   Kernel_Utils::Localizer loc;
315
316   bool parsed_ok = true;
317   Handle( ExprIntrp_GenExp ) myExpr;
318   try {
319     OCC_CATCH_SIGNALS;
320     myExpr = ExprIntrp_GenExp::Create();
321     myExpr->Process( str.ToCString() );
322   } catch(Standard_Failure&) {
323     parsed_ok = false;
324   }
325
326   syntax = false;
327   args = false;
328   if( parsed_ok && myExpr->IsDone() )
329   {
330     syntax = true;
331     args = isCorrectArg( myExpr->Expression() );
332   }
333
334   bool res = parsed_ok && syntax && args;
335   if( !res )
336     myExpr.Nullify();
337
338   non_neg = true;
339   singulars = false;
340   non_zero = false;
341
342   if( res )
343   {
344     FunctionExpr f( str.ToCString(), convMode );
345     const int max = 500;
346     for( int i=0; i<=max; i++ )
347     {
348       double t = double(i)/double(max), val;
349       if( !f.value( t, val ) )
350       {
351         sing_point = t;
352         singulars = true;
353         break;
354       }
355       if( val<0 )
356       {
357         non_neg = false;
358         break;
359       }
360       if( val>PRECISION )
361         non_zero = true;
362     }
363   }
364
365   return res && non_neg && non_zero && ( !singulars );
366 }
367
368 //================================================================================
369 /*!
370  * 
371  */
372 //================================================================================
373
374 void StdMeshers_NumberOfSegments::SetExpressionFunction(const char* expr)
375 {
376   if (_distrType != DT_ExprFunc)
377     _distrType = DT_ExprFunc;
378
379   string func = CheckExpressionFunction( expr, _convMode );
380   if( _func != func )
381   {
382     _func = func;
383     NotifySubMeshesHypothesisModification();
384   }
385 }
386
387 //=======================================================================
388 //function : CheckExpressionFunction
389 //purpose  : Checks validity of  the expression of the function f(t), e.g. "sin(t)".
390 //           In case of validity returns a cleaned expression
391 //=======================================================================
392
393 std::string
394 StdMeshers_NumberOfSegments::CheckExpressionFunction( const std::string& expr,
395                                                       const int          convMode)
396 {
397   // remove white spaces
398   TCollection_AsciiString str((Standard_CString)expr.c_str());
399   str.RemoveAll(' ');
400   str.RemoveAll('\t');
401   str.RemoveAll('\r');
402   str.RemoveAll('\n');
403
404   bool syntax, args, non_neg, singulars, non_zero;
405   double sing_point;
406   bool res = process( str, convMode, syntax, args, non_neg, non_zero, singulars, sing_point );
407   if( !res )
408   {
409     if( !syntax )
410       throw SALOME_Exception(SMESH_Comment("invalid expression syntax: ") << str );
411     if( !args )
412       throw SALOME_Exception(LOCALIZED("only 't' may be used as function argument"));
413     if( !non_neg )
414       throw SALOME_Exception(LOCALIZED("only non-negative function can be used"));
415     if( singulars )
416     {
417       char buf[1024];
418       sprintf( buf, "Function has singular point in %.3f", sing_point );
419       throw SALOME_Exception( buf );
420     }
421     if( !non_zero )
422       throw SALOME_Exception(LOCALIZED("f(t)=0 cannot be used"));
423   }
424  
425   return str.ToCString();
426 }
427
428 //================================================================================
429 /*!
430  * 
431  */
432 //================================================================================
433
434 const char* StdMeshers_NumberOfSegments::GetExpressionFunction() const
435 {
436   if (_distrType != DT_ExprFunc)
437     throw SALOME_Exception(LOCALIZED("not an expression function distribution"));
438   return _func.c_str();
439 }
440
441 //================================================================================
442 /*!
443  * 
444  */
445 //================================================================================
446
447 void StdMeshers_NumberOfSegments::SetConversionMode( int conv )
448 {
449 //   if (_distrType != DT_TabFunc && _distrType != DT_ExprFunc)
450 //     throw SALOME_Exception(LOCALIZED("not a functional distribution"));
451
452   if( conv != _convMode )
453   {
454     _convMode = conv;
455     NotifySubMeshesHypothesisModification();
456   }
457 }
458
459 //================================================================================
460 /*!
461  * 
462  */
463 //================================================================================
464
465 int StdMeshers_NumberOfSegments::ConversionMode() const
466 {
467 //   if (_distrType != DT_TabFunc && _distrType != DT_ExprFunc)
468 //     throw SALOME_Exception(LOCALIZED("not a functional distribution"));
469   return _convMode;
470 }
471
472 //=============================================================================
473 /*!
474  *  
475  */
476 //=============================================================================
477
478 ostream & StdMeshers_NumberOfSegments::SaveTo(ostream & save)
479 {
480   int listSize = _edgeIDs.size();
481   save << _numberOfSegments << " " << (int)_distrType;
482   switch (_distrType)
483   {
484   case DT_Scale:
485     save << " " << _scaleFactor;
486     break;
487   case DT_TabFunc:
488     save << " " << _table.size();
489     for ( size_t i = 0; i < _table.size(); i++ )
490       save << " " << _table[i];
491     break;
492   case DT_ExprFunc:
493     save << " " << _func;
494     break;
495   case DT_Regular:
496   default:
497     break;
498   }
499
500   if (_distrType == DT_TabFunc || _distrType == DT_ExprFunc)
501     save << " " << _convMode;
502
503   if ( _distrType != DT_Regular && listSize > 0 ) {
504     save << " " << listSize;
505     for ( int i = 0; i < listSize; i++ )
506       save << " " << _edgeIDs[i];
507     save << " " << _objEntry;
508   }
509   
510   return save;
511 }
512
513 //=============================================================================
514 /*!
515  *  
516  */
517 //=============================================================================
518
519 istream & StdMeshers_NumberOfSegments::LoadFrom(istream & load)
520 {
521   bool isOK = true;
522   int a;
523
524   // read number of segments
525   isOK = static_cast<bool>(load >> a);
526   if (isOK)
527     _numberOfSegments = a;
528   else
529     load.clear(ios::badbit | load.rdstate());
530
531   // read second stored value. It can be two variants here:
532   // 1. If the hypothesis is stored in old format (nb.segments and scale factor),
533   //    we wait here the scale factor, which is double.
534   // 2. If the hypothesis is stored in new format
535   //    (nb.segments, distr.type, some other params.),
536   //    we wait here the distribution type, which is integer
537   double scale_factor;
538   isOK = static_cast<bool>(load >> scale_factor);
539   a = (int)scale_factor;
540
541   // try to interpret distribution type,
542   // supposing that this hypothesis was written in the new format
543   if (isOK)
544   {
545     if (a < DT_Regular || a > DT_ExprFunc)
546       _distrType = DT_Regular;
547     else
548       _distrType = (DistrType) a;
549   }
550   else
551     load.clear(ios::badbit | load.rdstate());
552
553   // parameters of distribution
554   double b;
555   switch (_distrType)
556   {
557   case DT_Scale:
558     {
559       isOK = static_cast<bool>(load >> b);
560       if (isOK)
561         _scaleFactor = b;
562       else
563       {
564         load.clear(ios::badbit | load.rdstate());
565         // this can mean, that the hypothesis is stored in old format
566         _distrType = DT_Regular;
567         _scaleFactor = scale_factor;
568       }
569     }
570     break;
571   case DT_TabFunc:
572     {
573       isOK = static_cast<bool>(load >> a);
574       if (isOK)
575       {
576         _table.resize(a, 0.);
577         for ( size_t i=0; i < _table.size(); i++ )
578         {
579           isOK = static_cast<bool>(load >> b);
580           if (isOK)
581             _table[i] = b;
582           else
583             load.clear(ios::badbit | load.rdstate());
584         }
585       }
586       else
587       {
588         load.clear(ios::badbit | load.rdstate());
589         // this can mean, that the hypothesis is stored in old format
590         _distrType = DT_Regular;
591         _scaleFactor = scale_factor;
592       }
593     }
594     break;
595   case DT_ExprFunc:
596     {
597       string str;
598       isOK = static_cast<bool>(load >> str);
599       if (isOK)
600         _func = str;
601       else
602       {
603         load.clear(ios::badbit | load.rdstate());
604         // this can mean, that the hypothesis is stored in old format
605         _distrType = DT_Regular;
606         _scaleFactor = scale_factor;
607       }
608     }
609     break;
610   case DT_Regular:
611   default:
612     break;
613   }
614
615   if (_distrType == DT_TabFunc || _distrType == DT_ExprFunc)
616   {
617     isOK = static_cast<bool>(load >> a);
618     if (isOK)
619       _convMode = a;
620     else
621       load.clear(ios::badbit | load.rdstate());
622   }
623
624   // load reversed edges IDs
625   int intVal;
626   isOK = static_cast<bool>(load >> intVal);
627   if ( isOK && _distrType != DT_Regular && intVal > 0 ) {
628     _edgeIDs.reserve( intVal );
629     for ( size_t i = 0; i < _edgeIDs.capacity() && isOK; i++) {
630       isOK = static_cast<bool>(load >> intVal);
631       if ( isOK ) _edgeIDs.push_back( intVal );
632     }
633     isOK = static_cast<bool>(load >> _objEntry);
634   }
635
636   return load;
637 }
638
639 //=============================================================================
640 /*!
641  *
642  */
643 //=============================================================================
644
645 ostream & operator <<(ostream & save, StdMeshers_NumberOfSegments & hyp)
646 {
647   return hyp.SaveTo( save );
648 }
649
650 //=============================================================================
651 /*!
652  *  
653  */
654 //=============================================================================
655
656 istream & operator >>(istream & load, StdMeshers_NumberOfSegments & hyp)
657 {
658   return hyp.LoadFrom( load );
659 }
660
661 //================================================================================
662 /*!
663  * \brief Initialize number of segments by the mesh built on the geometry
664  * \param theMesh - the built mesh
665  * \param theShape - the geometry of interest
666  * \retval bool - true if parameter values have been successfully defined
667  */
668 //================================================================================
669
670 bool StdMeshers_NumberOfSegments::SetParametersByMesh(const SMESH_Mesh*   theMesh,
671                                                       const TopoDS_Shape& theShape)
672 {
673   if ( !theMesh || theShape.IsNull() )
674     return false;
675
676   _numberOfSegments = 0;
677   _distrType = DT_Regular;
678
679   int nbEdges = 0;
680   TopTools_IndexedMapOfShape edgeMap;
681   TopExp::MapShapes( theShape, TopAbs_EDGE, edgeMap );
682   SMESHDS_Mesh* aMeshDS = const_cast< SMESH_Mesh* >( theMesh )->GetMeshDS();
683   for ( int i = 1; i <= edgeMap.Extent(); ++i )
684   {
685     // get current segment length
686     SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( edgeMap( i ));
687     if ( eSubMesh && eSubMesh->NbElements())
688       _numberOfSegments += eSubMesh->NbElements();
689
690     ++nbEdges;
691   }
692   if ( nbEdges )
693     _numberOfSegments /= nbEdges;
694
695   if (_numberOfSegments == 0) _numberOfSegments = 1;
696
697   return nbEdges;
698 }
699 //================================================================================
700 /*!
701  * \brief Initialize my parameter values by default parameters.
702  *  \retval bool - true if parameter values have been successfully defined
703  */
704 //================================================================================
705
706 bool StdMeshers_NumberOfSegments::SetParametersByDefaults(const TDefaults&  dflts,
707                                                           const SMESH_Mesh* /*theMesh*/)
708 {
709   return (_numberOfSegments = dflts._nbSegments );
710 }