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