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