Salome HOME
PAL10953. Add Fineness parameter to Automatic Length hypothesis
[modules/smesh.git] / src / StdMeshers / StdMeshers_NumberOfSegments.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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : StdMeshers_NumberOfSegments.cxx
25 //           Moved here from SMESH_NumberOfSegments.cxx
26 //  Author : Paul RASCLE, EDF
27 //  Module : SMESH
28 //  $Header$
29
30 using namespace std;
31 #include "StdMeshers_NumberOfSegments.hxx"
32 #include <Standard_ErrorHandler.hxx>
33 #include <TCollection_AsciiString.hxx>
34 #include <ExprIntrp_GenExp.hxx>
35 #include <Expr_NamedUnknown.hxx>
36 #include <CASCatch_CatchSignals.hxx>
37 #include <CASCatch_Failure.hxx> 
38 #include <CASCatch_ErrorHandler.hxx>
39 #include <OSD.hxx>
40 #include <Expr_Array1OfNamedUnknown.hxx>
41 #include <TColStd_Array1OfReal.hxx>
42
43
44 const double PRECISION = 1e-7;
45
46 //=============================================================================
47 /*!
48  *  
49  */
50 //=============================================================================
51
52 StdMeshers_NumberOfSegments::StdMeshers_NumberOfSegments(int hypId, int studyId,
53         SMESH_Gen * gen)
54   : SMESH_Hypothesis(hypId, studyId, gen),
55     _numberOfSegments(1),
56     _distrType(DT_Regular),
57     _scaleFactor(1.),
58     _expMode(false)
59 {
60   _name = "NumberOfSegments";
61   _param_algo_dim = 1;
62 }
63
64 //=============================================================================
65 /*!
66  *  
67  */
68 //=============================================================================
69
70 StdMeshers_NumberOfSegments::~StdMeshers_NumberOfSegments()
71 {
72 }
73
74 //=============================================================================
75 /*!
76  *  
77  */
78 //=============================================================================
79
80 void StdMeshers_NumberOfSegments::SetNumberOfSegments(int segmentsNumber)
81 throw(SALOME_Exception)
82 {
83         int oldNumberOfSegments = _numberOfSegments;
84         if (segmentsNumber <= 0)
85                 throw
86                         SALOME_Exception(LOCALIZED("number of segments must be positive"));
87         _numberOfSegments = segmentsNumber;
88
89         if (oldNumberOfSegments != _numberOfSegments)
90                 NotifySubMeshesHypothesisModification();
91 }
92
93 //=============================================================================
94 /*!
95  *  
96  */
97 //=============================================================================
98
99 int StdMeshers_NumberOfSegments::GetNumberOfSegments() const
100 {
101         return _numberOfSegments;
102 }
103
104 //================================================================================
105 /*!
106  * 
107  */
108 //================================================================================
109
110 void StdMeshers_NumberOfSegments::SetDistrType(DistrType typ)
111   throw(SALOME_Exception)
112 {
113   if (typ < DT_Regular || typ > DT_ExprFunc)
114     throw SALOME_Exception(LOCALIZED("distribution type is out of range"));
115
116   if (typ != _distrType)
117   {
118     _distrType = typ;
119     NotifySubMeshesHypothesisModification();
120   }
121 }
122
123 //================================================================================
124 /*!
125  * 
126  */
127 //================================================================================
128
129 StdMeshers_NumberOfSegments::DistrType StdMeshers_NumberOfSegments::GetDistrType() const
130 {
131   return _distrType;
132 }
133
134 //================================================================================
135 /*!
136  * 
137  */
138 //================================================================================
139
140 void StdMeshers_NumberOfSegments::SetScaleFactor(double scaleFactor)
141   throw(SALOME_Exception)
142 {
143   if (_distrType != DT_Scale)
144     throw SALOME_Exception(LOCALIZED("not a scale distribution"));
145   if (scaleFactor < PRECISION)
146     throw SALOME_Exception(LOCALIZED("scale factor must be positive"));
147   if (fabs(scaleFactor - 1.0) < PRECISION)
148     throw SALOME_Exception(LOCALIZED("scale factor must not be equal to 1"));
149
150   if (fabs(_scaleFactor - scaleFactor) > PRECISION)
151   {
152     _scaleFactor = scaleFactor;
153     NotifySubMeshesHypothesisModification();
154   }
155 }
156
157 //================================================================================
158 /*!
159  * 
160  */
161 //================================================================================
162
163 double StdMeshers_NumberOfSegments::GetScaleFactor() const
164   throw(SALOME_Exception)
165 {
166   if (_distrType != DT_Scale)
167     throw SALOME_Exception(LOCALIZED("not a scale distribution"));
168   return _scaleFactor;
169 }
170
171 //================================================================================
172 /*!
173  * 
174  */
175 //================================================================================
176
177 void StdMeshers_NumberOfSegments::SetTableFunction(const std::vector<double>& table)
178   throw(SALOME_Exception)
179 {
180   if (_distrType != DT_TabFunc)
181     throw SALOME_Exception(LOCALIZED("not a table function distribution"));
182   if ( (table.size() % 2) != 0 )
183     throw SALOME_Exception(LOCALIZED("odd size of vector of table function"));
184
185   int i;
186   double prev = -PRECISION;
187   bool isSame = table.size() == _table.size();
188
189   bool pos = false;
190   for (i=0; i < table.size()/2; i++) {
191     double par = table[i*2];
192     double val = table[i*2+1];
193     if ( par<0 || par > 1)
194       throw SALOME_Exception(LOCALIZED("parameter of table function is out of range [0,1]"));
195     if ( fabs(par-prev)<PRECISION )
196       throw SALOME_Exception(LOCALIZED("two parameters are the same"));
197     if ( val < 0 )
198       throw SALOME_Exception(LOCALIZED("value of table function is not positive"));
199     if( val>PRECISION )
200       pos = true;
201     if (isSame)
202     {
203       double oldpar = _table[i*2];
204       double oldval = _table[i*2+1];
205       if (fabs(par - oldpar) > PRECISION || fabs(val - oldval) > PRECISION)
206         isSame = false;
207     }
208     prev = par;
209   }
210
211   if( !pos )
212     throw SALOME_Exception(LOCALIZED("value of table function is not positive"));
213
214   if( pos && !isSame )
215   {
216     _table = table;
217     NotifySubMeshesHypothesisModification();
218   }
219 }
220
221 //================================================================================
222 /*!
223  * 
224  */
225 //================================================================================
226
227 const std::vector<double>& StdMeshers_NumberOfSegments::GetTableFunction() const
228   throw(SALOME_Exception)
229 {
230   if (_distrType != DT_TabFunc)
231     throw SALOME_Exception(LOCALIZED("not a table function distribution"));
232   return _table;
233 }
234
235 //================================================================================
236 /*! check if only 't' is unknown variable in expression
237  */
238 //================================================================================
239 bool isCorrectArg( const Handle( Expr_GeneralExpression )& expr )
240 {
241   Handle( Expr_NamedUnknown ) sub = Handle( Expr_NamedUnknown )::DownCast( expr );
242   if( !sub.IsNull() )
243     return sub->GetName()=="t";
244
245   bool res = true;
246   for( int i=1, n=expr->NbSubExpressions(); i<=n && res; i++ )
247   {
248     Handle( Expr_GeneralExpression ) sub = expr->SubExpression( i );
249     Handle( Expr_NamedUnknown ) name = Handle( Expr_NamedUnknown )::DownCast( sub );
250     if( !name.IsNull() )
251     {
252       if( name->GetName()!="t" )
253         res = false;
254     }
255     else
256       res = isCorrectArg( sub );
257   }
258   return res;
259 }
260
261 //================================================================================
262 /*! this function parses the expression 'str' in order to check if syntax is correct
263  *  ( result in 'syntax' ) and if only 't' is unknown variable in expression ( result in 'args' )
264  */
265 //================================================================================
266 bool process( const TCollection_AsciiString& str,
267               bool& syntax, bool& args,
268               bool& non_neg, bool& non_zero,
269               bool& singulars, double& sing_point )
270 {
271   Handle( ExprIntrp_GenExp ) myExpr = ExprIntrp_GenExp::Create();
272   myExpr->Process( str.ToCString() );
273
274   if( myExpr->IsDone() )
275   {
276     syntax = true;
277     args = isCorrectArg( myExpr->Expression() );
278   }
279
280   bool res = syntax && args;
281   if( !res )
282     myExpr.Nullify();
283
284   non_neg = true;
285   singulars = false;
286   non_zero = false;
287
288   if( res )
289   {
290     OSD::SetSignal( true );
291     CASCatch_CatchSignals aCatchSignals;
292     aCatchSignals.Activate();
293     double res;
294     Expr_Array1OfNamedUnknown myVars( 1, 1 );
295     TColStd_Array1OfReal  myValues( 1, 1 );
296     myVars.ChangeValue( 1 ) = new Expr_NamedUnknown( "t" );
297
298     const int max = 500;
299     for( int i=0; i<=max; i++ )
300     {
301       double t = double(i)/double(max);
302       myValues.ChangeValue( 1 ) = t;
303       CASCatch_TRY
304       {   
305         res = myExpr->Expression()->Evaluate( myVars, myValues );
306       }
307       CASCatch_CATCH(CASCatch_Failure)
308       {
309         aCatchSignals.Deactivate();
310         Handle(CASCatch_Failure) aFail = CASCatch_Failure::Caught();
311         sing_point = t;
312         singulars = true;
313         break;
314       }
315       if( res<0 )
316       {
317         non_neg = false;
318         break;
319       }
320       if( res>PRECISION )
321         non_zero = true;
322     }
323     aCatchSignals.Deactivate();
324   }
325   return res && non_neg && ( !singulars );
326 }
327
328 //================================================================================
329 /*!
330  * 
331  */
332 //================================================================================
333
334 void StdMeshers_NumberOfSegments::SetExpressionFunction(const char* expr)
335   throw(SALOME_Exception)
336 {
337   if (_distrType != DT_ExprFunc)
338     throw SALOME_Exception(LOCALIZED("not an expression function distribution"));
339
340   // remove white spaces
341   TCollection_AsciiString str((Standard_CString)expr);
342   str.RemoveAll(' ');
343   str.RemoveAll('\t');
344   str.RemoveAll('\r');
345   str.RemoveAll('\n');
346
347   bool syntax, args, non_neg, singulars, non_zero;
348   double sing_point;
349   bool res = true;//process( str, syntax, args, non_neg, non_zero, singulars, sing_point );
350   if( !res )
351   {
352     if( !syntax )
353       throw SALOME_Exception(LOCALIZED("invalid expression syntax"));
354     if( !args )
355       throw SALOME_Exception(LOCALIZED("only 't' may be used as function argument"));
356     if( !non_neg )
357       throw SALOME_Exception(LOCALIZED("only non-negative function can be used as density"));
358     if( singulars )
359     {
360       char buf[1024];
361       sprintf( buf, "Function has singular point in %.3f", sing_point );
362       throw SALOME_Exception( buf );
363     }
364     if( !non_zero )
365       throw SALOME_Exception(LOCALIZED("f(t)=0 cannot be used as density"));
366
367     return;
368   }
369   
370   std::string func = expr;
371   if( _func != func )
372   {
373     _func = func;
374     NotifySubMeshesHypothesisModification();
375   }
376 }
377
378 //================================================================================
379 /*!
380  * 
381  */
382 //================================================================================
383
384 const char* StdMeshers_NumberOfSegments::GetExpressionFunction() const
385   throw(SALOME_Exception)
386 {
387   if (_distrType != DT_ExprFunc)
388     throw SALOME_Exception(LOCALIZED("not an expression function distribution"));
389   return _func.c_str();
390 }
391
392 //================================================================================
393 /*!
394  * 
395  */
396 //================================================================================
397
398 void StdMeshers_NumberOfSegments::SetExponentMode(bool isExp)
399   throw(SALOME_Exception)
400 {
401   if (_distrType != DT_TabFunc && _distrType != DT_ExprFunc)
402     throw SALOME_Exception(LOCALIZED("not a functional distribution"));
403
404   if (isExp != _expMode)
405   {
406     _expMode = isExp;
407     NotifySubMeshesHypothesisModification();
408   }
409 }
410
411 //================================================================================
412 /*!
413  * 
414  */
415 //================================================================================
416
417 bool StdMeshers_NumberOfSegments::IsExponentMode() const
418   throw(SALOME_Exception)
419 {
420   if (_distrType != DT_TabFunc && _distrType != DT_ExprFunc)
421     throw SALOME_Exception(LOCALIZED("not a functional distribution"));
422   return _expMode;
423 }
424
425 //=============================================================================
426 /*!
427  *  
428  */
429 //=============================================================================
430
431 ostream & StdMeshers_NumberOfSegments::SaveTo(ostream & save)
432 {
433   save << _numberOfSegments << " " << (int)_distrType;
434   switch (_distrType)
435   {
436   case DT_Scale:
437     save << " " << _scaleFactor;
438     break;
439   case DT_TabFunc:
440     int i;
441     save << " " << _table.size();
442     for (i=0; i < _table.size(); i++)
443       save << " " << _table[i];
444     break;
445   case DT_ExprFunc:
446     save << " " << _func;
447     break;
448   case DT_Regular:
449   default:
450     break;
451   }
452
453   if (_distrType == DT_TabFunc || _distrType == DT_ExprFunc)
454     save << " " << (int)_expMode;
455   
456   return save;
457 }
458
459 //=============================================================================
460 /*!
461  *  
462  */
463 //=============================================================================
464
465 istream & StdMeshers_NumberOfSegments::LoadFrom(istream & load)
466 {
467   bool isOK = true;
468   int a;
469
470   // read number of segments
471   isOK = (load >> a);
472   if (isOK)
473     _numberOfSegments = a;
474   else
475     load.clear(ios::badbit | load.rdstate());
476
477   // read second stored value. It can be two variants here:
478   // 1. If the hypothesis is stored in old format (nb.segments and scale factor),
479   //    we wait here the scale factor, which is double.
480   // 2. If the hypothesis is stored in new format
481   //    (nb.segments, distr.type, some other params.),
482   //    we wait here the ditribution type, which is integer
483   double scale_factor;
484   isOK = (load >> scale_factor);
485   a = (int)scale_factor;
486
487   // try to interprete ditribution type,
488   // supposing that this hypothesis was written in the new format
489   if (isOK)
490   {
491     if (a < DT_Regular || a > DT_ExprFunc)
492       _distrType = DT_Regular;
493     else
494       _distrType = (DistrType) a;
495   }
496   else
497     load.clear(ios::badbit | load.rdstate());
498
499   // parameters of distribution
500   double b;
501   switch (_distrType)
502   {
503   case DT_Scale:
504     {
505       isOK = (load >> b);
506       if (isOK)
507         _scaleFactor = b;
508       else
509       {
510         load.clear(ios::badbit | load.rdstate());
511         // this can mean, that the hypothesis is stored in old format
512         _distrType = DT_Regular;
513         _scaleFactor = scale_factor;
514       }
515     }
516     break;
517   case DT_TabFunc:
518     {
519       isOK = (load >> a);
520       if (isOK)
521       {
522         _table.resize(a, 0.);
523         int i;
524         for (i=0; i < _table.size(); i++)
525         {
526           isOK = (load >> b);
527           if (isOK)
528             _table[i] = b;
529           else
530             load.clear(ios::badbit | load.rdstate());
531         }
532       }
533       else
534       {
535         load.clear(ios::badbit | load.rdstate());
536         // this can mean, that the hypothesis is stored in old format
537         _distrType = DT_Regular;
538         _scaleFactor = scale_factor;
539       }
540     }
541     break;
542   case DT_ExprFunc:
543     {
544       string str;
545       isOK = (load >> str);
546       if (isOK)
547         _func = str;
548       else
549       {
550         load.clear(ios::badbit | load.rdstate());
551         // this can mean, that the hypothesis is stored in old format
552         _distrType = DT_Regular;
553         _scaleFactor = scale_factor;
554       }
555     }
556     break;
557   case DT_Regular:
558   default:
559     break;
560   }
561
562   if (_distrType == DT_TabFunc || _distrType == DT_ExprFunc)
563   {
564     isOK = (load >> a);
565     if (isOK)
566       _expMode = (bool) a;
567     else
568       load.clear(ios::badbit | load.rdstate());
569   }
570
571   return load;
572 }
573
574 //=============================================================================
575 /*!
576  *  
577  */
578 //=============================================================================
579
580 ostream & operator <<(ostream & save, StdMeshers_NumberOfSegments & hyp)
581 {
582   return hyp.SaveTo( save );
583 }
584
585 //=============================================================================
586 /*!
587  *  
588  */
589 //=============================================================================
590
591 istream & operator >>(istream & load, StdMeshers_NumberOfSegments & hyp)
592 {
593   return hyp.LoadFrom( load );
594 }