Salome HOME
Qt4 porting: add axis grids to plot 2d preview.
[modules/smesh.git] / src / StdMeshersGUI / StdMeshersGUI_DistrPreview.cxx
1 // Copyright (C) 2005  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
3 //
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License.
8 //
9 // This library is distributed in the hope that it will be useful
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // Lesser General Public License for more details.
13 //
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 //
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 //
20 // File   : StdMeshersGUI_DistrPreview.cxx
21 // Author : Open CASCADE S.A.S.
22 //
23
24 // SMESH includes
25 #include "StdMeshersGUI_DistrPreview.h"
26
27 // Qwt includes
28 #include <qwt_plot_curve.h>
29 #include <qwt_plot_marker.h>
30 #include <qwt_plot_grid.h>
31 #include <qwt_symbol.h>
32 #include <qwt_legend.h>
33
34 // OCCT includes
35 #include <Expr_NamedUnknown.hxx>
36 #include <Expr_GeneralExpression.hxx>
37
38 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
39 #define NO_CAS_CATCH
40 #endif
41
42 #include <Standard_Failure.hxx>
43
44 #ifdef NO_CAS_CATCH
45 #include <Standard_ErrorHandler.hxx>
46 #endif
47
48 StdMeshersGUI_DistrPreview::StdMeshersGUI_DistrPreview( QWidget* p, StdMeshers::StdMeshers_NumberOfSegments_ptr h )
49 : QwtPlot( p ),
50   myPoints( 50 ),
51   myIsTable( false ),
52   myVars( 1, 1 ),
53   myValues( 1, 1 ),
54   myConv( CUT_NEGATIVE ),
55   myIsDone( true ),
56   myNbSeg( 1 )
57 {
58   myHypo = StdMeshers::StdMeshers_NumberOfSegments::_duplicate( h );
59   myVars.ChangeValue( 1 ) = new Expr_NamedUnknown( "t" );
60   myDensity = new QwtPlotCurve( QString() );
61   myDensity->attach( this );
62   myDistr = new QwtPlotCurve( QString() );
63   myDistr->attach( this );
64   myMsg = new QwtPlotMarker();
65   myMsg->attach( this );
66   myMsg->setValue( 0.5, 0.5 );
67   QwtText mt = myMsg->label();
68   mt.setBackgroundPen( QPen( Qt::red, 1 ) );
69   QFont f = mt.font();
70   f.setPointSize( 14 ); f.setBold( true );
71   mt.setFont( f );
72   myMsg->setLabel( mt );
73   myDensity->setPen( QPen( Qt::red, 1 ) );
74
75   QColor dc = Qt::blue;
76   myDistr->setPen( QPen( dc, 1 ) );
77   myDistr->setSymbol( QwtSymbol( QwtSymbol::XCross, QBrush( dc ), QPen( dc ), QSize( 5, 5 ) ) );
78
79   QwtLegend* l = legend();
80   if ( !l ) {
81     l = new QwtLegend( this );
82     l->setFrameStyle( QFrame::Box | QFrame::Sunken );
83   }
84   insertLegend( l, QwtPlot::BottomLegend );
85
86   myDensity->setTitle( tr( "SMESH_DENSITY_FUNC" ) );
87   myDistr->setTitle( tr( "SMESH_DISTR" ) );
88   
89   QwtPlotGrid* aGrid = new QwtPlotGrid();
90   QPen aMajPen = aGrid->majPen();
91   aMajPen.setStyle( Qt::DashLine );
92   aGrid->setPen( aMajPen );
93
94   aGrid->enableX( true );
95   aGrid->enableY( true );
96
97   aGrid->attach( this );
98 }
99
100 StdMeshersGUI_DistrPreview::~StdMeshersGUI_DistrPreview()
101 {
102 }
103
104 bool StdMeshersGUI_DistrPreview::isTableFunc() const
105 {
106   return myIsTable;
107 }
108
109 void StdMeshersGUI_DistrPreview::tableFunc( SMESH::double_array& f ) const
110 {
111   f = myTableFunc;
112 }
113
114 QString StdMeshersGUI_DistrPreview::function() const
115 {
116   return myFunction;
117 }
118
119 int StdMeshersGUI_DistrPreview::nbSeg() const
120 {
121   return myNbSeg;
122 }
123
124 int StdMeshersGUI_DistrPreview::pointsCount() const
125 {
126   return myPoints;
127 }
128
129 void StdMeshersGUI_DistrPreview::setConversion( Conversion conv, const bool upd )
130 {
131   myConv = conv;
132   if( upd )
133     update();
134 }
135
136 bool StdMeshersGUI_DistrPreview::setParams( const QString& func, const int nbSeg, const int points, const bool upd )
137 {
138   myIsTable = false;
139   myTableFunc = SMESH::double_array();
140   myFunction = func.isEmpty() ? "0" : func;
141   myPoints = points>0 ? points : 2;
142   myNbSeg = nbSeg>0 ? nbSeg : 1;
143   bool res = init( func );
144   if( upd )
145     update();
146   return res;
147 }
148
149 bool StdMeshersGUI_DistrPreview::setParams( const SMESH::double_array& f, const int nbSeg, const bool upd )
150 {
151   myIsTable = true;
152   myTableFunc = f;
153   if( myTableFunc.length()%2==1 )
154     myTableFunc.length( myTableFunc.length()-1 );
155
156   myFunction = "0";
157   myPoints = myTableFunc.length()/2;
158   myNbSeg = nbSeg>0 ? nbSeg : 1;
159
160   if( upd )
161     update();
162
163   return myTableFunc.length()>0;
164 }
165
166 bool StdMeshersGUI_DistrPreview::createTable( SMESH::double_array& func )
167 {
168   if( myExpr.IsNull() )
169   {
170     func.length( 0 );
171     return false;
172   }
173
174   const double xmin = 0.0, xmax = 1.0;
175
176   double d = (xmax-xmin)/double(myPoints-1);
177   func.length( 2*myPoints );
178   int err = 0;
179   for( int i=0, j=0; i<myPoints; j++ )
180   {
181     bool ok;
182     double t = xmin + d*j, f = funcValue( t, ok );
183     if( ok )
184     {
185       func[2*i] = t;
186       func[2*i+1] = f;
187       i++;
188     }
189     else
190       err++;
191   }
192   func.length( func.length()-2*err );
193   return err==0;
194 }
195
196 void StdMeshersGUI_DistrPreview::update()
197 {
198   SMESH::double_array graph, distr;
199   if( isTableFunc() )
200   {
201     myIsDone = true;
202     graph = myTableFunc;
203   }
204   else
205     myIsDone = createTable( graph );
206
207   if( graph.length()>=2 )
208   {
209     StdMeshers::StdMeshers_NumberOfSegments_var h = 
210       StdMeshers::StdMeshers_NumberOfSegments::_narrow( myHypo );
211
212     if( !CORBA::is_nil( h.in() ) )
213     {
214       SMESH::double_array* arr = 0;
215       if( isTableFunc() )
216         arr = h->BuildDistributionTab( myTableFunc, myNbSeg, ( int )myConv );
217       else
218         arr = h->BuildDistributionExpr( myFunction.toLatin1().data(), myNbSeg, ( int )myConv );
219       if( arr )
220       {
221         distr = *arr;
222         delete arr;
223       }
224     }
225   }
226
227   bool correct = graph.length()>=2 && distr.length()>=2;
228   if( !correct )
229   {
230     showError();
231     return;
232   }
233   else
234   {
235     QwtText mt = myMsg->label();
236     mt.setText( QString() );
237     myMsg->setLabel( mt );
238   }
239
240   int size = graph.length()/2;
241   double* x = new double[size], *y = new double[size];
242   double min_x, max_x, min_y, max_y;
243   for( int i=0; i<size; i++ )
244   {
245     x[i] = graph[2*i];
246     y[i] = graph[2*i+1];
247     if( !convert( y[i] ) )
248     {
249       min_x = 0.0; max_x = 1.0; min_y = 0.0; max_y = 1.0;
250       delete[] x; delete[] y;
251       x = y = 0;
252       showError();
253       return;
254     }
255     if( i==0 || y[i]<min_y )
256       min_y = y[i];
257     if( i==0 || y[i]>max_y )
258       max_y = y[i];
259     if( i==0 || x[i]<min_x )
260       min_x = x[i];
261     if( i==0 || x[i]>max_x )
262       max_x = x[i];
263   }
264
265   setAxisScale( myDensity->xAxis(), min_x, max_x );
266   setAxisScale( myDensity->yAxis(), std::min( 0.0, min_y ), std::max( 0.0, max_y ) );
267   myDensity->setData( x, y, size );
268   if( x )
269     delete[] x;
270   if( y )
271     delete[] y;
272   x = y = 0;
273
274   size = distr.length();
275   x = new double[size];
276   y = new double[size];
277   for( int i=0; i<size; i++ )
278   {
279     x[i] = distr[i];
280     y[i] = 0;
281   }
282   myDistr->setData( x, y, size );
283   delete[] x;
284   delete[] y;
285   x = y = 0;
286
287   try {   
288 #ifdef NO_CAS_CATCH
289     OCC_CATCH_SIGNALS;
290 #endif
291     replot();
292   } catch(Standard_Failure) {
293     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
294   }
295 }
296
297 void StdMeshersGUI_DistrPreview::showError()
298 {
299   setAxisScale( myDensity->xAxis(), 0.0, 1.0 );
300   setAxisScale( myDensity->yAxis(), 0.0, 1.0 );
301   myDensity->setData( 0, 0, 0 );
302   myDistr->setData( 0, 0, 0 );
303   QwtText mt = myMsg->label();
304   mt.setText( tr( "SMESH_INVALID_FUNCTION" ) );
305   myMsg->setLabel( mt );
306   replot();
307 }
308
309 bool isCorrectArg( const Handle( Expr_GeneralExpression )& expr )
310 {
311   Handle( Expr_NamedUnknown ) sub = Handle( Expr_NamedUnknown )::DownCast( expr );
312   if( !sub.IsNull() )
313     return sub->GetName()=="t";
314
315   bool res = true;
316   for( int i=1, n=expr->NbSubExpressions(); i<=n && res; i++ )
317   {
318     Handle( Expr_GeneralExpression ) sub = expr->SubExpression( i );
319     Handle( Expr_NamedUnknown ) name = Handle( Expr_NamedUnknown )::DownCast( sub );
320     if( !name.IsNull() )
321     {
322       if( name->GetName()!="t" )
323         res = false;
324     }
325     else
326       res = isCorrectArg( sub );
327   }
328   return res;
329 }
330
331 bool StdMeshersGUI_DistrPreview::init( const QString& str )
332 {
333   bool parsed_ok = true;
334   try {
335 #ifdef NO_CAS_CATCH
336     OCC_CATCH_SIGNALS;
337 #endif
338     myExpr = ExprIntrp_GenExp::Create();
339     myExpr->Process( ( Standard_CString ) str.toLatin1().data() );
340   } catch(Standard_Failure) {
341     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
342     parsed_ok = false;
343   }
344
345   bool syntax = false, args = false;
346   if( parsed_ok && myExpr->IsDone() )
347   {
348     syntax = true;
349     args = isCorrectArg( myExpr->Expression() );
350   }
351
352   bool res = parsed_ok && syntax && args;
353   if( !res )
354     myExpr.Nullify();
355   return res;
356 }
357
358 double StdMeshersGUI_DistrPreview::funcValue( const double t, bool& ok )
359 {
360   if( myExpr.IsNull() )
361     return 0;
362
363   myValues.ChangeValue( 1 ) = t;
364
365   ok = true;
366   double res = calc( ok );
367
368   return res;
369 }
370
371 double StdMeshersGUI_DistrPreview::calc( bool& ok )
372 {
373   double res = 0.0;
374
375   ok = true;
376   try {   
377 #ifdef NO_CAS_CATCH
378     OCC_CATCH_SIGNALS;
379 #endif
380     res = myExpr->Expression()->Evaluate( myVars, myValues );
381   } catch(Standard_Failure) {
382     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
383     ok = false;
384     res = 0.0;
385   }
386
387   return res;
388 }
389
390 bool StdMeshersGUI_DistrPreview::isDone() const
391 {
392   return myIsDone;
393 }
394
395 bool StdMeshersGUI_DistrPreview::convert( double& v ) const
396 {
397   bool ok = true;
398   switch( myConv )
399   {
400   case EXPONENT:
401     {
402       try { 
403 #ifdef NO_CAS_CATCH
404         OCC_CATCH_SIGNALS;
405 #endif
406         // in StdMeshers_NumberOfSegments.cc
407         // const double PRECISION = 1e-7;
408         //
409         if(v < -7) v = -7.0;
410         v = pow( 10.0, v );
411       } catch(Standard_Failure) {
412         Handle(Standard_Failure) aFail = Standard_Failure::Caught();
413         v = 0.0;
414         ok = false;
415       }
416     }
417     break;
418
419   case CUT_NEGATIVE:
420     if( v<0 )
421       v = 0;
422     break;
423   }
424
425   return ok;
426 }