Salome HOME
Join modifications from branch OCC_development_for_3_2_0a2
[modules/smesh.git] / src / StdMeshersGUI / StdMeshersGUI_DistrPreview.cxx
1
2 #include "StdMeshersGUI_DistrPreview.h"
3 #include "CASCatch.hxx"
4
5 #include <Expr_NamedUnknown.hxx>
6 #include <Expr_GeneralExpression.hxx>
7
8 StdMeshersGUI_DistrPreview::StdMeshersGUI_DistrPreview( QWidget* p, StdMeshers::StdMeshers_NumberOfSegments_ptr h )
9 : QwtPlot( p ),
10   myPoints( 50 ),
11   myIsTable( false ),
12   myVars( 1, 1 ),
13   myValues( 1, 1 ),
14   myConv( CUT_NEGATIVE ),
15   myIsDone( true ),
16   myNbSeg( 1 )
17 {
18   myHypo = StdMeshers::StdMeshers_NumberOfSegments::_duplicate( h );
19   myVars.ChangeValue( 1 ) = new Expr_NamedUnknown( "t" );
20   myDensity = insertCurve( QString() );
21   myDistr = insertCurve( QString() );
22   myMsg = insertMarker( new QwtPlotMarker( this ) );
23   setMarkerPos( myMsg, 0.5, 0.5 );
24   setMarkerLabelPen( myMsg, QPen( Qt::red, 1 ) );
25   QFont f = markerFont( myMsg );
26   f.setPointSize( 14 );
27   f.setBold( true );
28   setMarkerFont( myMsg, f );
29   setCurvePen( myDensity, QPen( Qt::red, 1 ) );
30
31   QColor dc = Qt::blue;
32   setCurvePen( myDistr, QPen( dc, 1 ) );
33   setCurveSymbol( myDistr, QwtSymbol( QwtSymbol::XCross, QBrush( dc ), QPen( dc ), QSize( 5, 5 ) ) );
34   setAutoLegend( true );
35   enableLegend( true );
36   setLegendPos( Qwt::Bottom );
37   setCurveTitle( myDensity, tr( "SMESH_DENSITY_FUNC" ) );
38   setCurveTitle( myDistr, tr( "SMESH_DISTR" ) );
39 }
40
41 StdMeshersGUI_DistrPreview::~StdMeshersGUI_DistrPreview()
42 {
43 }
44
45 bool StdMeshersGUI_DistrPreview::isTableFunc() const
46 {
47   return myIsTable;
48 }
49
50 void StdMeshersGUI_DistrPreview::tableFunc( SMESH::double_array& f ) const
51 {
52   f = myTableFunc;
53 }
54
55 QString StdMeshersGUI_DistrPreview::function() const
56 {
57   return myFunction;
58 }
59
60 int StdMeshersGUI_DistrPreview::nbSeg() const
61 {
62   return myNbSeg;
63 }
64
65 int StdMeshersGUI_DistrPreview::pointsCount() const
66 {
67   return myPoints;
68 }
69
70 void StdMeshersGUI_DistrPreview::setConversion( Conversion conv, const bool upd )
71 {
72   myConv = conv;
73   if( upd )
74     update();
75 }
76
77 bool StdMeshersGUI_DistrPreview::setParams( const QString& func, const int nbSeg, const int points, const bool upd )
78 {
79   myIsTable = false;
80   myTableFunc = SMESH::double_array();
81   myFunction = func.isEmpty() ? "0" : func;
82   myPoints = points>0 ? points : 2;
83   myNbSeg = nbSeg>0 ? nbSeg : 1;
84   bool res = init( func );
85   if( upd )
86     update();
87   return res;
88 }
89
90 bool StdMeshersGUI_DistrPreview::setParams( const SMESH::double_array& f, const int nbSeg, const bool upd )
91 {
92   myIsTable = true;
93   myTableFunc = f;
94   if( myTableFunc.length()%2==1 )
95     myTableFunc.length( myTableFunc.length()-1 );
96
97   myFunction = "0";
98   myPoints = myTableFunc.length()/2;
99   myNbSeg = nbSeg>0 ? nbSeg : 1;
100
101   if( upd )
102     update();
103
104   return myTableFunc.length()>0;
105 }
106
107 bool StdMeshersGUI_DistrPreview::createTable( SMESH::double_array& func )
108 {
109   if( myExpr.IsNull() )
110   {
111     func.length( 0 );
112     return false;
113   }
114
115   const double xmin = 0.0, xmax = 1.0;
116
117   double d = (xmax-xmin)/double(myPoints-1);
118   func.length( 2*myPoints );
119   int err = 0;
120   for( int i=0, j=0; i<myPoints; j++ )
121   {
122     bool ok;
123     double t = xmin + d*j, f = funcValue( t, ok );
124     if( ok )
125     {
126       func[2*i] = t;
127       func[2*i+1] = f;
128       i++;
129     }
130     else
131       err++;
132   }
133   func.length( func.length()-2*err );
134   return err==0;
135 }
136
137 void StdMeshersGUI_DistrPreview::update()
138 {
139   SMESH::double_array graph, distr;
140   if( isTableFunc() )
141   {
142     myIsDone = true;
143     graph = myTableFunc;
144   }
145   else
146     myIsDone = createTable( graph );
147
148   if( graph.length()>=2 )
149   {
150     StdMeshers::StdMeshers_NumberOfSegments_var h = 
151       StdMeshers::StdMeshers_NumberOfSegments::_narrow( myHypo );
152
153     if( !CORBA::is_nil( h.in() ) )
154     {
155       SMESH::double_array* arr = 0;
156       if( isTableFunc() )
157         arr = h->BuildDistributionTab( myTableFunc, myNbSeg, ( int )myConv );
158       else
159         arr = h->BuildDistributionExpr( myFunction.latin1(), myNbSeg, ( int )myConv );
160       if( arr )
161       {
162         distr = *arr;
163         delete arr;
164       }
165     }
166   }
167
168   bool correct = graph.length()>=2 && distr.length()>=2;
169   if( !correct )
170   {
171     showError();
172     return;
173   }
174   else
175     setMarkerLabel( myMsg, QString() );
176
177   int size = graph.length()/2;
178   double* x = new double[size], *y = new double[size];
179   double min_x, max_x, min_y, max_y;
180   for( int i=0; i<size; i++ )
181   {
182     x[i] = graph[2*i];
183     y[i] = graph[2*i+1];
184     if( !convert( y[i] ) )
185     {
186       min_x = 0.0; max_x = 1.0; min_y = 0.0; max_y = 1.0;
187       delete[] x; delete[] y;
188       x = y = 0;
189       showError();
190       return;
191     }
192     if( i==0 || y[i]<min_y )
193       min_y = y[i];
194     if( i==0 || y[i]>max_y )
195       max_y = y[i];
196     if( i==0 || x[i]<min_x )
197       min_x = x[i];
198     if( i==0 || x[i]>max_x )
199       max_x = x[i];
200   }
201
202   setAxisScale( curveXAxis( myDensity ), min_x, max_x );
203   setAxisScale( curveYAxis( myDensity ), min( 0.0, min_y ), max( 0.0, max_y ) );
204   setCurveData( myDensity, x, y, size );
205   if( x )
206     delete[] x;
207   if( y )
208     delete[] y;
209   x = y = 0;
210
211   size = distr.length();
212   x = new double[size];
213   y = new double[size];
214   for( int i=0; i<size; i++ )
215   {
216     x[i] = distr[i];
217     y[i] = 0;
218   }
219   setCurveData( myDistr, x, y, size );
220   delete[] x;
221   delete[] y;
222   x = y = 0;
223
224   CASCatch_TRY
225   {   
226     replot();
227   }
228   CASCatch_CATCH(Standard_Failure)
229   {
230     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
231   }
232 }
233
234 void StdMeshersGUI_DistrPreview::showError()
235 {
236   setAxisScale( curveXAxis( myDensity ), 0.0, 1.0 );
237   setAxisScale( curveYAxis( myDensity ), 0.0, 1.0 );
238   setCurveData( myDensity, 0, 0, 0 );
239   setCurveData( myDistr, 0, 0, 0 );
240   setMarkerLabel( myMsg, tr( "SMESH_INVALID_FUNCTION" ) );
241   replot();
242 }
243
244 bool isCorrectArg( const Handle( Expr_GeneralExpression )& expr )
245 {
246   Handle( Expr_NamedUnknown ) sub = Handle( Expr_NamedUnknown )::DownCast( expr );
247   if( !sub.IsNull() )
248     return sub->GetName()=="t";
249
250   bool res = true;
251   for( int i=1, n=expr->NbSubExpressions(); i<=n && res; i++ )
252   {
253     Handle( Expr_GeneralExpression ) sub = expr->SubExpression( i );
254     Handle( Expr_NamedUnknown ) name = Handle( Expr_NamedUnknown )::DownCast( sub );
255     if( !name.IsNull() )
256     {
257       if( name->GetName()!="t" )
258         res = false;
259     }
260     else
261       res = isCorrectArg( sub );
262   }
263   return res;
264 }
265
266 bool StdMeshersGUI_DistrPreview::init( const QString& str )
267 {
268   bool parsed_ok = true;
269   CASCatch_TRY
270   {
271     myExpr = ExprIntrp_GenExp::Create();
272     myExpr->Process( ( Standard_CString ) str.latin1() );
273   }
274   CASCatch_CATCH(Standard_Failure)
275   {
276     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
277     parsed_ok = false;
278   }
279
280   bool syntax = false, args = false;
281   if( parsed_ok && myExpr->IsDone() )
282   {
283     syntax = true;
284     args = isCorrectArg( myExpr->Expression() );
285   }
286
287   bool res = parsed_ok && syntax && args;
288   if( !res )
289     myExpr.Nullify();
290   return res;
291 }
292
293 double StdMeshersGUI_DistrPreview::funcValue( const double t, bool& ok )
294 {
295   if( myExpr.IsNull() )
296     return 0;
297
298   myValues.ChangeValue( 1 ) = t;
299
300   ok = true;
301   double res = calc( ok );
302
303   return res;
304 }
305
306 double StdMeshersGUI_DistrPreview::calc( bool& ok )
307 {
308   double res = 0.0;
309
310   ok = true;
311   CASCatch_TRY {   
312     res = myExpr->Expression()->Evaluate( myVars, myValues );
313   }
314   CASCatch_CATCH(Standard_Failure) {
315     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
316     ok = false;
317     res = 0.0;
318   }
319
320   return res;
321 }
322
323 bool StdMeshersGUI_DistrPreview::isDone() const
324 {
325   return myIsDone;
326 }
327
328 bool StdMeshersGUI_DistrPreview::convert( double& v ) const
329 {
330   bool ok = true;
331   switch( myConv )
332   {
333   case EXPONENT:
334     {
335       CASCatch_TRY
336       { 
337         // in StdMeshers_NumberOfSegments.cc
338         // const double PRECISION = 1e-7;
339         //
340         if(v < -7) v = -7.0;
341         v = pow( 10.0, v );
342       }
343       CASCatch_CATCH(Standard_Failure)
344       {
345         Handle(Standard_Failure) aFail = Standard_Failure::Caught();
346         v = 0.0;
347         ok = false;
348       }
349     }
350     break;
351
352   case CUT_NEGATIVE:
353     if( v<0 )
354       v = 0;
355     break;
356   }
357
358   return ok;
359 }