Salome HOME
98dac7e8439a66d993600907f5661b1005430dd6
[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         throw SALOME_Exception( LOCALIZED( "invalid value"));
239         return;
240       }
241     }
242     else if( _convMode==1 && val<0.0 )
243       val = 0.0;
244
245     if ( par < 0 || par > 1)
246       throw SALOME_Exception(LOCALIZED("parameter of table function is out of range [0,1]"));
247     if ( fabs(par-prev) < PRECISION )
248       throw SALOME_Exception(LOCALIZED("two parameters are the same"));
249     if ( val < 0 )
250       throw SALOME_Exception(LOCALIZED("value of table function is not positive"));
251     if( val > PRECISION )
252       pos = true;
253     if (isSame)
254     {
255       double oldpar = _table[i*2];
256       double oldval = _table[i*2+1];
257       if ( fabs(par - oldpar) > PRECISION || fabs(val - oldval) > PRECISION )
258         isSame = false;
259     }
260     prev = par;
261   }
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 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   Kernel_Utils::Localizer loc;
324
325   bool parsed_ok = true;
326   Handle( ExprIntrp_GenExp ) myExpr;
327   try {
328     OCC_CATCH_SIGNALS;
329     myExpr = ExprIntrp_GenExp::Create();
330     myExpr->Process( str.ToCString() );
331   } catch(Standard_Failure) {
332     parsed_ok = false;
333   }
334
335   syntax = false;
336   args = false;
337   if( parsed_ok && myExpr->IsDone() )
338   {
339     syntax = true;
340     args = isCorrectArg( myExpr->Expression() );
341   }
342
343   bool res = parsed_ok && syntax && args;
344   if( !res )
345     myExpr.Nullify();
346
347   non_neg = true;
348   singulars = false;
349   non_zero = false;
350
351   if( res )
352   {
353     FunctionExpr f( str.ToCString(), convMode );
354     const int max = 500;
355     for( int i=0; i<=max; i++ )
356     {
357       double t = double(i)/double(max), val;
358       if( !f.value( t, val ) )
359       {
360         sing_point = t;
361         singulars = true;
362         break;
363       }
364       if( val<0 )
365       {
366         non_neg = false;
367         break;
368       }
369       if( val>PRECISION )
370         non_zero = true;
371     }
372   }
373
374   return res && non_neg && non_zero && ( !singulars );
375 }
376
377 //================================================================================
378 /*!
379  * 
380  */
381 //================================================================================
382
383 void StdMeshers_NumberOfSegments::SetExpressionFunction(const char* expr)
384   throw(SALOME_Exception)
385 {
386   if (_distrType != DT_ExprFunc)
387     _distrType = DT_ExprFunc;
388
389   string func = CheckExpressionFunction( expr, _convMode );
390   if( _func != func )
391   {
392     _func = func;
393     NotifySubMeshesHypothesisModification();
394   }
395 }
396
397 //=======================================================================
398 //function : CheckExpressionFunction
399 //purpose  : Checks validity of  the expression of the function f(t), e.g. "sin(t)".
400 //           In case of validity returns a cleaned expression
401 //=======================================================================
402
403 std::string
404 StdMeshers_NumberOfSegments::CheckExpressionFunction( const std::string& expr,
405                                                       const int          convMode)
406     throw (SALOME_Exception)
407 {
408   // remove white spaces
409   TCollection_AsciiString str((Standard_CString)expr.c_str());
410   str.RemoveAll(' ');
411   str.RemoveAll('\t');
412   str.RemoveAll('\r');
413   str.RemoveAll('\n');
414
415   bool syntax, args, non_neg, singulars, non_zero;
416   double sing_point;
417   bool res = process( str, convMode, syntax, args, non_neg, non_zero, singulars, sing_point );
418   if( !res )
419   {
420     if( !syntax )
421       throw SALOME_Exception(SMESH_Comment("invalid expression syntax: ") << str );
422     if( !args )
423       throw SALOME_Exception(LOCALIZED("only 't' may be used as function argument"));
424     if( !non_neg )
425       throw SALOME_Exception(LOCALIZED("only non-negative function can be used"));
426     if( singulars )
427     {
428       char buf[1024];
429       sprintf( buf, "Function has singular point in %.3f", sing_point );
430       throw SALOME_Exception( buf );
431     }
432     if( !non_zero )
433       throw SALOME_Exception(LOCALIZED("f(t)=0 cannot be used"));
434   }
435  
436   return str.ToCString();
437 }
438
439 //================================================================================
440 /*!
441  * 
442  */
443 //================================================================================
444
445 const char* StdMeshers_NumberOfSegments::GetExpressionFunction() const
446   throw(SALOME_Exception)
447 {
448   if (_distrType != DT_ExprFunc)
449     throw SALOME_Exception(LOCALIZED("not an expression function distribution"));
450   return _func.c_str();
451 }
452
453 //================================================================================
454 /*!
455  * 
456  */
457 //================================================================================
458
459 void StdMeshers_NumberOfSegments::SetConversionMode( int conv )
460   throw(SALOME_Exception)
461 {
462 //   if (_distrType != DT_TabFunc && _distrType != DT_ExprFunc)
463 //     throw SALOME_Exception(LOCALIZED("not a functional distribution"));
464
465   if( conv != _convMode )
466   {
467     _convMode = conv;
468     NotifySubMeshesHypothesisModification();
469   }
470 }
471
472 //================================================================================
473 /*!
474  * 
475  */
476 //================================================================================
477
478 int StdMeshers_NumberOfSegments::ConversionMode() const
479   throw(SALOME_Exception)
480 {
481 //   if (_distrType != DT_TabFunc && _distrType != DT_ExprFunc)
482 //     throw SALOME_Exception(LOCALIZED("not a functional distribution"));
483   return _convMode;
484 }
485
486 //=============================================================================
487 /*!
488  *  
489  */
490 //=============================================================================
491
492 ostream & StdMeshers_NumberOfSegments::SaveTo(ostream & save)
493 {
494   int listSize = _edgeIDs.size();
495   save << _numberOfSegments << " " << (int)_distrType;
496   switch (_distrType)
497   {
498   case DT_Scale:
499     save << " " << _scaleFactor;
500     break;
501   case DT_TabFunc:
502     save << " " << _table.size();
503     for ( size_t i = 0; i < _table.size(); i++ )
504       save << " " << _table[i];
505     break;
506   case DT_ExprFunc:
507     save << " " << _func;
508     break;
509   case DT_Regular:
510   default:
511     break;
512   }
513
514   if (_distrType == DT_TabFunc || _distrType == DT_ExprFunc)
515     save << " " << _convMode;
516
517   if ( _distrType != DT_Regular && listSize > 0 ) {
518     save << " " << listSize;
519     for ( int i = 0; i < listSize; i++ )
520       save << " " << _edgeIDs[i];
521     save << " " << _objEntry;
522   }
523   
524   return save;
525 }
526
527 //=============================================================================
528 /*!
529  *  
530  */
531 //=============================================================================
532
533 istream & StdMeshers_NumberOfSegments::LoadFrom(istream & load)
534 {
535   bool isOK = true;
536   int a;
537
538   // read number of segments
539   isOK = static_cast<bool>(load >> a);
540   if (isOK)
541     _numberOfSegments = a;
542   else
543     load.clear(ios::badbit | load.rdstate());
544
545   // read second stored value. It can be two variants here:
546   // 1. If the hypothesis is stored in old format (nb.segments and scale factor),
547   //    we wait here the scale factor, which is double.
548   // 2. If the hypothesis is stored in new format
549   //    (nb.segments, distr.type, some other params.),
550   //    we wait here the ditribution type, which is integer
551   double scale_factor;
552   isOK = static_cast<bool>(load >> scale_factor);
553   a = (int)scale_factor;
554
555   // try to interprete ditribution type,
556   // supposing that this hypothesis was written in the new format
557   if (isOK)
558   {
559     if (a < DT_Regular || a > DT_ExprFunc)
560       _distrType = DT_Regular;
561     else
562       _distrType = (DistrType) a;
563   }
564   else
565     load.clear(ios::badbit | load.rdstate());
566
567   // parameters of distribution
568   double b;
569   switch (_distrType)
570   {
571   case DT_Scale:
572     {
573       isOK = static_cast<bool>(load >> b);
574       if (isOK)
575         _scaleFactor = b;
576       else
577       {
578         load.clear(ios::badbit | load.rdstate());
579         // this can mean, that the hypothesis is stored in old format
580         _distrType = DT_Regular;
581         _scaleFactor = scale_factor;
582       }
583     }
584     break;
585   case DT_TabFunc:
586     {
587       isOK = static_cast<bool>(load >> a);
588       if (isOK)
589       {
590         _table.resize(a, 0.);
591         for ( size_t i=0; i < _table.size(); i++ )
592         {
593           isOK = static_cast<bool>(load >> b);
594           if (isOK)
595             _table[i] = b;
596           else
597             load.clear(ios::badbit | load.rdstate());
598         }
599       }
600       else
601       {
602         load.clear(ios::badbit | load.rdstate());
603         // this can mean, that the hypothesis is stored in old format
604         _distrType = DT_Regular;
605         _scaleFactor = scale_factor;
606       }
607     }
608     break;
609   case DT_ExprFunc:
610     {
611       string str;
612       isOK = static_cast<bool>(load >> str);
613       if (isOK)
614         _func = str;
615       else
616       {
617         load.clear(ios::badbit | load.rdstate());
618         // this can mean, that the hypothesis is stored in old format
619         _distrType = DT_Regular;
620         _scaleFactor = scale_factor;
621       }
622     }
623     break;
624   case DT_Regular:
625   default:
626     break;
627   }
628
629   if (_distrType == DT_TabFunc || _distrType == DT_ExprFunc)
630   {
631     isOK = static_cast<bool>(load >> a);
632     if (isOK)
633       _convMode = a;
634     else
635       load.clear(ios::badbit | load.rdstate());
636   }
637
638   // load reversed edges IDs
639   int intVal;
640   isOK = static_cast<bool>(load >> intVal);
641   if ( isOK && _distrType != DT_Regular && intVal > 0 ) {
642     _edgeIDs.reserve( intVal );
643     for ( size_t i = 0; i < _edgeIDs.capacity() && isOK; i++) {
644       isOK = static_cast<bool>(load >> intVal);
645       if ( isOK ) _edgeIDs.push_back( intVal );
646     }
647     isOK = static_cast<bool>(load >> _objEntry);
648   }
649
650   return load;
651 }
652
653 //=============================================================================
654 /*!
655  *
656  */
657 //=============================================================================
658
659 ostream & operator <<(ostream & save, StdMeshers_NumberOfSegments & hyp)
660 {
661   return hyp.SaveTo( save );
662 }
663
664 //=============================================================================
665 /*!
666  *  
667  */
668 //=============================================================================
669
670 istream & operator >>(istream & load, StdMeshers_NumberOfSegments & hyp)
671 {
672   return hyp.LoadFrom( load );
673 }
674
675 //================================================================================
676 /*!
677  * \brief Initialize number of segments by the mesh built on the geometry
678  * \param theMesh - the built mesh
679  * \param theShape - the geometry of interest
680  * \retval bool - true if parameter values have been successfully defined
681  */
682 //================================================================================
683
684 bool StdMeshers_NumberOfSegments::SetParametersByMesh(const SMESH_Mesh*   theMesh,
685                                                       const TopoDS_Shape& theShape)
686 {
687   if ( !theMesh || theShape.IsNull() )
688     return false;
689
690   _numberOfSegments = 0;
691   _distrType = DT_Regular;
692
693   int nbEdges = 0;
694   TopTools_IndexedMapOfShape edgeMap;
695   TopExp::MapShapes( theShape, TopAbs_EDGE, edgeMap );
696   SMESHDS_Mesh* aMeshDS = const_cast< SMESH_Mesh* >( theMesh )->GetMeshDS();
697   for ( int i = 1; i <= edgeMap.Extent(); ++i )
698   {
699     // get current segment length
700     SMESHDS_SubMesh * eSubMesh = aMeshDS->MeshElements( edgeMap( i ));
701     if ( eSubMesh && eSubMesh->NbElements())
702       _numberOfSegments += eSubMesh->NbElements();
703
704     ++nbEdges;
705   }
706   if ( nbEdges )
707     _numberOfSegments /= nbEdges;
708
709   if (_numberOfSegments == 0) _numberOfSegments = 1;
710
711   return nbEdges;
712 }
713 //================================================================================
714 /*!
715  * \brief Initialize my parameter values by default parameters.
716  *  \retval bool - true if parameter values have been successfully defined
717  */
718 //================================================================================
719
720 bool StdMeshers_NumberOfSegments::SetParametersByDefaults(const TDefaults&  dflts,
721                                                           const SMESH_Mesh* /*theMesh*/)
722 {
723   return (_numberOfSegments = dflts._nbSegments );
724 }
725
726 //=============================================================================
727 /*!
728  *  
729  */
730 //=============================================================================
731
732 void StdMeshers_NumberOfSegments::SetReversedEdges( std::vector<int>& ids )
733 {
734   if ( ids != _edgeIDs ) {
735     _edgeIDs = ids;
736
737     NotifySubMeshesHypothesisModification();
738   }
739 }
740