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