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