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