Salome HOME
SMH: Version ported on new OCT6.1.1
[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.salome-platform.org/ or email : webmaster.salome@opencascade.com
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 #include "StdMeshers_NumberOfSegments.hxx"
31
32 #include "StdMeshers_Distribution.hxx"
33 #include "SMESHDS_SubMesh.hxx"
34 #include "SMESH_Mesh.hxx"
35
36 #include <ExprIntrp_GenExp.hxx>
37 #include <Expr_Array1OfNamedUnknown.hxx>
38 #include <Expr_NamedUnknown.hxx>
39 #include <TColStd_Array1OfReal.hxx>
40 #include <TCollection_AsciiString.hxx>
41 #include <TopExp.hxx>
42 #include <TopTools_IndexedMapOfShape.hxx>
43
44 #include <Standard_Failure.hxx>
45 #include <Standard_ErrorHandler.hxx>
46
47 using namespace std;
48
49 const double PRECISION = 1e-7;
50
51 //=============================================================================
52 /*!
53  *  
54  */
55 //=============================================================================
56
57 StdMeshers_NumberOfSegments::StdMeshers_NumberOfSegments(int hypId, int studyId,
58         SMESH_Gen * gen)
59   : SMESH_Hypothesis(hypId, studyId, gen),
60     _numberOfSegments(1),
61     _distrType(DT_Regular),
62     _scaleFactor(1.),
63     _convMode(1)  //cut negative by default
64 {
65   _name = "NumberOfSegments";
66   _param_algo_dim = 1;
67 }
68
69 //=============================================================================
70 /*!
71  *  
72  */
73 //=============================================================================
74
75 StdMeshers_NumberOfSegments::~StdMeshers_NumberOfSegments()
76 {
77 }
78
79 //=============================================================================
80 /*!
81  *  
82  */
83 //=============================================================================
84 const std::vector<double>& StdMeshers_NumberOfSegments::BuildDistributionExpr( const char* expr, int nbSeg, int conv )
85 throw ( SALOME_Exception )
86 {
87   if( !buildDistribution( TCollection_AsciiString( ( Standard_CString )expr ), conv, 0.0, 1.0, nbSeg, _distr, 1E-4 ) )
88     _distr.resize( 0 );
89   return _distr;
90 }
91
92 const std::vector<double>& StdMeshers_NumberOfSegments::BuildDistributionTab( const std::vector<double>& tab,
93                                                                               int nbSeg, int conv )
94 throw ( SALOME_Exception )
95 {
96   if( !buildDistribution( tab, conv, 0.0, 1.0, nbSeg, _distr, 1E-4 ) )
97     _distr.resize( 0 );
98   return _distr;
99 }
100
101 //=============================================================================
102 /*!
103  *  
104  */
105 //=============================================================================
106
107 void StdMeshers_NumberOfSegments::SetNumberOfSegments(int segmentsNumber)
108 throw(SALOME_Exception)
109 {
110         int oldNumberOfSegments = _numberOfSegments;
111         if (segmentsNumber <= 0)
112                 throw
113                         SALOME_Exception(LOCALIZED("number of segments must be positive"));
114         _numberOfSegments = segmentsNumber;
115
116         if (oldNumberOfSegments != _numberOfSegments)
117                 NotifySubMeshesHypothesisModification();
118 }
119
120 //=============================================================================
121 /*!
122  *  
123  */
124 //=============================================================================
125
126 int StdMeshers_NumberOfSegments::GetNumberOfSegments() const
127 {
128         return _numberOfSegments;
129 }
130
131 //================================================================================
132 /*!
133  * 
134  */
135 //================================================================================
136
137 void StdMeshers_NumberOfSegments::SetDistrType(DistrType typ)
138   throw(SALOME_Exception)
139 {
140   if (typ < DT_Regular || typ > DT_ExprFunc)
141     throw SALOME_Exception(LOCALIZED("distribution type is out of range"));
142
143   if (typ != _distrType)
144   {
145     _distrType = typ;
146     NotifySubMeshesHypothesisModification();
147   }
148 }
149
150 //================================================================================
151 /*!
152  * 
153  */
154 //================================================================================
155
156 StdMeshers_NumberOfSegments::DistrType StdMeshers_NumberOfSegments::GetDistrType() const
157 {
158   return _distrType;
159 }
160
161 //================================================================================
162 /*!
163  * 
164  */
165 //================================================================================
166
167 void StdMeshers_NumberOfSegments::SetScaleFactor(double scaleFactor)
168   throw(SALOME_Exception)
169 {
170   if (_distrType != DT_Scale)
171     throw SALOME_Exception(LOCALIZED("not a scale distribution"));
172   if (scaleFactor < PRECISION)
173     throw SALOME_Exception(LOCALIZED("scale factor must be positive"));
174   //if (fabs(scaleFactor - 1.0) < PRECISION)
175   //  throw SALOME_Exception(LOCALIZED("scale factor must not be equal to 1"));
176
177   if (fabs(_scaleFactor - scaleFactor) > PRECISION)
178   {
179     _scaleFactor = scaleFactor;
180     NotifySubMeshesHypothesisModification();
181   }
182 }
183
184 //================================================================================
185 /*!
186  * 
187  */
188 //================================================================================
189
190 double StdMeshers_NumberOfSegments::GetScaleFactor() const
191   throw(SALOME_Exception)
192 {
193   if (_distrType != DT_Scale)
194     throw SALOME_Exception(LOCALIZED("not a scale distribution"));
195   return _scaleFactor;
196 }
197
198 //================================================================================
199 /*!
200  * 
201  */
202 //================================================================================
203
204 void StdMeshers_NumberOfSegments::SetTableFunction(const std::vector<double>& table)
205   throw(SALOME_Exception)
206 {
207   if (_distrType != DT_TabFunc)
208     throw SALOME_Exception(LOCALIZED("not a table function distribution"));
209   if ( (table.size() % 2) != 0 )
210     throw SALOME_Exception(LOCALIZED("odd size of vector of table function"));
211
212   int i;
213   double prev = -PRECISION;
214   bool isSame = table.size() == _table.size();
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       try {
223         OCC_CATCH_SIGNALS;
224         val = pow( 10.0, val );
225       }
226       catch(Standard_Failure)
227       {
228         Handle(Standard_Failure) aFail = Standard_Failure::Caught();
229         throw SALOME_Exception( LOCALIZED( "invalid value"));
230         return;
231       }
232     }
233     else if( _convMode==1 && val<0.0 )
234       val = 0.0;
235
236     if ( par<0 || par > 1)
237       throw SALOME_Exception(LOCALIZED("parameter of table function is out of range [0,1]"));
238     if ( fabs(par-prev)<PRECISION )
239       throw SALOME_Exception(LOCALIZED("two parameters are the same"));
240     if ( val < 0 )
241       throw SALOME_Exception(LOCALIZED("value of table function is not positive"));
242     if( val>PRECISION )
243       pos = true;
244     if (isSame)
245     {
246       double oldpar = _table[i*2];
247       double oldval = _table[i*2+1];
248       if (fabs(par - oldpar) > PRECISION || fabs(val - oldval) > PRECISION)
249         isSame = false;
250     }
251     prev = par;
252   }
253
254   if( !pos )
255     throw SALOME_Exception(LOCALIZED("value of table function is not positive"));
256
257   if( pos && !isSame )
258   {
259     _table = table;
260     NotifySubMeshesHypothesisModification();
261   }
262 }
263
264 //================================================================================
265 /*!
266  * 
267  */
268 //================================================================================
269
270 const std::vector<double>& StdMeshers_NumberOfSegments::GetTableFunction() const
271   throw(SALOME_Exception)
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   bool parsed_ok = true;
315   Handle( ExprIntrp_GenExp ) myExpr;
316   try {
317     OCC_CATCH_SIGNALS;
318     myExpr = ExprIntrp_GenExp::Create();
319     myExpr->Process( str.ToCString() );
320   }
321   catch(Standard_Failure)
322   {
323     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
324     parsed_ok = false;
325   }
326
327   syntax = false;
328   args = false;
329   if( parsed_ok && myExpr->IsDone() )
330   {
331     syntax = true;
332     args = isCorrectArg( myExpr->Expression() );
333   }
334
335   bool res = parsed_ok && syntax && args;
336   if( !res )
337     myExpr.Nullify();
338
339   non_neg = true;
340   singulars = false;
341   non_zero = false;
342
343   if( res )
344   {
345     FunctionExpr f( str.ToCString(), convMode );
346     const int max = 500;
347     for( int i=0; i<=max; i++ )
348     {
349       double t = double(i)/double(max), val;
350       if( !f.value( t, val ) )
351       {
352         sing_point = t;
353         singulars = true;
354         break;
355       }
356       if( val<0 )
357       {
358         non_neg = false;
359         break;
360       }
361       if( val>PRECISION )
362         non_zero = true;
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   throw(SALOME_Exception)
376 {
377   if (_distrType != DT_ExprFunc)
378     throw SALOME_Exception(LOCALIZED("not an expression function distribution"));
379
380   // remove white spaces
381   TCollection_AsciiString str((Standard_CString)expr);
382   str.RemoveAll(' ');
383   str.RemoveAll('\t');
384   str.RemoveAll('\r');
385   str.RemoveAll('\n');
386
387   bool syntax, args, non_neg, singulars, non_zero;
388   double sing_point;
389   bool res = process( str, _convMode, syntax, args, non_neg, non_zero, singulars, sing_point );
390   if( !res )
391   {
392     if( !syntax )
393       throw SALOME_Exception(LOCALIZED("invalid expression syntax"));
394     if( !args )
395       throw SALOME_Exception(LOCALIZED("only 't' may be used as function argument"));
396     if( !non_neg )
397       throw SALOME_Exception(LOCALIZED("only non-negative function can be used as density"));
398     if( singulars )
399     {
400       char buf[1024];
401       sprintf( buf, "Function has singular point in %.3f", sing_point );
402       throw SALOME_Exception( buf );
403     }
404     if( !non_zero )
405       throw SALOME_Exception(LOCALIZED("f(t)=0 cannot be used as density"));
406
407     return;
408   }
409   
410   std::string func = expr;
411   if( _func != func )
412   {
413     _func = func;
414     NotifySubMeshesHypothesisModification();
415   }
416 }
417
418 //================================================================================
419 /*!
420  * 
421  */
422 //================================================================================
423
424 const char* StdMeshers_NumberOfSegments::GetExpressionFunction() const
425   throw(SALOME_Exception)
426 {
427   if (_distrType != DT_ExprFunc)
428     throw SALOME_Exception(LOCALIZED("not an expression function distribution"));
429   return _func.c_str();
430 }
431
432 //================================================================================
433 /*!
434  * 
435  */
436 //================================================================================
437
438 void StdMeshers_NumberOfSegments::SetConversionMode( int conv )
439   throw(SALOME_Exception)
440 {
441   if (_distrType != DT_TabFunc && _distrType != DT_ExprFunc)
442     throw SALOME_Exception(LOCALIZED("not a functional distribution"));
443
444   if( conv != _convMode )
445   {
446     _convMode = conv;
447     NotifySubMeshesHypothesisModification();
448   }
449 }
450
451 //================================================================================
452 /*!
453  * 
454  */
455 //================================================================================
456
457 int StdMeshers_NumberOfSegments::ConversionMode() const
458   throw(SALOME_Exception)
459 {
460   if (_distrType != DT_TabFunc && _distrType != DT_ExprFunc)
461     throw SALOME_Exception(LOCALIZED("not a functional distribution"));
462   return _convMode;
463 }
464
465 //=============================================================================
466 /*!
467  *  
468  */
469 //=============================================================================
470
471 ostream & StdMeshers_NumberOfSegments::SaveTo(ostream & save)
472 {
473   save << _numberOfSegments << " " << (int)_distrType;
474   switch (_distrType)
475   {
476   case DT_Scale:
477     save << " " << _scaleFactor;
478     break;
479   case DT_TabFunc:
480     int i;
481     save << " " << _table.size();
482     for (i=0; i < _table.size(); i++)
483       save << " " << _table[i];
484     break;
485   case DT_ExprFunc:
486     save << " " << _func;
487     break;
488   case DT_Regular:
489   default:
490     break;
491   }
492
493   if (_distrType == DT_TabFunc || _distrType == DT_ExprFunc)
494     save << " " << _convMode;
495   
496   return save;
497 }
498
499 //=============================================================================
500 /*!
501  *  
502  */
503 //=============================================================================
504
505 istream & StdMeshers_NumberOfSegments::LoadFrom(istream & load)
506 {
507   bool isOK = true;
508   int a;
509
510   // read number of segments
511   isOK = (load >> a);
512   if (isOK)
513     _numberOfSegments = a;
514   else
515     load.clear(ios::badbit | load.rdstate());
516
517   // read second stored value. It can be two variants here:
518   // 1. If the hypothesis is stored in old format (nb.segments and scale factor),
519   //    we wait here the scale factor, which is double.
520   // 2. If the hypothesis is stored in new format
521   //    (nb.segments, distr.type, some other params.),
522   //    we wait here the ditribution type, which is integer
523   double scale_factor;
524   isOK = (load >> scale_factor);
525   a = (int)scale_factor;
526
527   // try to interprete ditribution type,
528   // supposing that this hypothesis was written in the new format
529   if (isOK)
530   {
531     if (a < DT_Regular || a > DT_ExprFunc)
532       _distrType = DT_Regular;
533     else
534       _distrType = (DistrType) a;
535   }
536   else
537     load.clear(ios::badbit | load.rdstate());
538
539   // parameters of distribution
540   double b;
541   switch (_distrType)
542   {
543   case DT_Scale:
544     {
545       isOK = (load >> b);
546       if (isOK)
547         _scaleFactor = b;
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_TabFunc:
558     {
559       isOK = (load >> a);
560       if (isOK)
561       {
562         _table.resize(a, 0.);
563         int i;
564         for (i=0; i < _table.size(); i++)
565         {
566           isOK = (load >> b);
567           if (isOK)
568             _table[i] = b;
569           else
570             load.clear(ios::badbit | load.rdstate());
571         }
572       }
573       else
574       {
575         load.clear(ios::badbit | load.rdstate());
576         // this can mean, that the hypothesis is stored in old format
577         _distrType = DT_Regular;
578         _scaleFactor = scale_factor;
579       }
580     }
581     break;
582   case DT_ExprFunc:
583     {
584       string str;
585       isOK = (load >> str);
586       if (isOK)
587         _func = str;
588       else
589       {
590         load.clear(ios::badbit | load.rdstate());
591         // this can mean, that the hypothesis is stored in old format
592         _distrType = DT_Regular;
593         _scaleFactor = scale_factor;
594       }
595     }
596     break;
597   case DT_Regular:
598   default:
599     break;
600   }
601
602   if (_distrType == DT_TabFunc || _distrType == DT_ExprFunc)
603   {
604     isOK = (load >> a);
605     if (isOK)
606       _convMode = a;
607     else
608       load.clear(ios::badbit | load.rdstate());
609   }
610
611   return load;
612 }
613
614 //=============================================================================
615 /*!
616  *  
617  */
618 //=============================================================================
619
620 ostream & operator <<(ostream & save, StdMeshers_NumberOfSegments & hyp)
621 {
622   return hyp.SaveTo( save );
623 }
624
625 //=============================================================================
626 /*!
627  *  
628  */
629 //=============================================================================
630
631 istream & operator >>(istream & load, StdMeshers_NumberOfSegments & hyp)
632 {
633   return hyp.LoadFrom( load );
634 }
635
636 //================================================================================
637 /*!
638  * \brief Initialize number of segments by the mesh built on the geometry
639  * \param theMesh - the built mesh
640  * \param theShape - the geometry of interest
641  * \retval bool - true if parameter values have been successfully defined
642  */
643 //================================================================================
644
645 bool StdMeshers_NumberOfSegments::SetParametersByMesh(const SMESH_Mesh*   theMesh,
646                                                       const TopoDS_Shape& theShape)
647 {
648   if ( !theMesh || theShape.IsNull() )
649     return false;
650
651   _numberOfSegments = 0;
652   _distrType = DT_Regular;
653
654   int nbEdges = 0;
655   TopTools_IndexedMapOfShape edgeMap;
656   TopExp::MapShapes( theShape, TopAbs_EDGE, edgeMap );
657   for ( int i = 1; i <= edgeMap.Extent(); ++i )
658   {
659     // get current segment length
660     SMESHDS_Mesh* aMeshDS = const_cast< SMESH_Mesh* >( theMesh )->GetMeshDS();
661     SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( edgeMap( i ));
662     if ( eSubMesh && eSubMesh->NbElements())
663       _numberOfSegments += eSubMesh->NbElements();
664
665     ++nbEdges;
666   }
667   if ( nbEdges )
668     _numberOfSegments /= nbEdges;
669
670   return nbEdges;
671 }