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