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