Salome HOME
Merge from V6_main 01/04/2013
[modules/gui.git] / src / Plot2d / Plot2d_AnalyticalParser.cxx
1 // Copyright (C) 2007-2013  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 //  File   : Plot2d_AnalyticalParser.cxx
23 //  Author : Roman NIKOLAEV, Open CASCADE S.A.S. (roman.nikolaev@opencascade.com)
24 #include "Plot2d_AnalyticalParser.h"
25 #include <structmember.h>
26
27
28 /* ==================================
29  * ===========  PYTHON ==============
30  * ==================================*/
31
32 typedef struct {
33   PyObject_HEAD
34   int softspace;
35   std::string *out;
36   } PyStdOut;
37
38 static void
39 PyStdOut_dealloc(PyStdOut *self)
40 {
41   PyObject_Del(self);
42 }
43
44 static PyObject *
45 PyStdOut_write(PyStdOut *self, PyObject *args)
46 {
47   char *c;
48   int l;
49   if (!PyArg_ParseTuple(args, "t#:write",&c, &l))
50     return NULL;
51
52   //std::cerr << c ;
53   *(self->out)=*(self->out)+c;
54
55   Py_INCREF(Py_None);
56   return Py_None;
57 }
58
59 static PyMethodDef PyStdOut_methods[] = {
60   {"write",  (PyCFunction)PyStdOut_write,  METH_VARARGS,
61     PyDoc_STR("write(string) -> None")},
62   {NULL,    NULL}   /* sentinel */
63 };
64
65 static PyMemberDef PyStdOut_memberlist[] = {
66   {(char*)"softspace", T_INT,  offsetof(PyStdOut, softspace), 0,
67    (char*)"flag indicating that a space needs to be printed; used by print"},
68   {NULL} /* Sentinel */
69 };
70
71 static PyTypeObject PyStdOut_Type = {
72   /* The ob_type field must be initialized in the module init function
73    * to be portable to Windows without using C++. */
74   PyObject_HEAD_INIT(NULL)
75   0,                            /*ob_size*/
76   "PyOut",                      /*tp_name*/
77   sizeof(PyStdOut),             /*tp_basicsize*/
78   0,                            /*tp_itemsize*/
79   /* methods */
80   (destructor)PyStdOut_dealloc, /*tp_dealloc*/
81   0,                            /*tp_print*/
82   0,                            /*tp_getattr*/
83   0,                            /*tp_setattr*/
84   0,                            /*tp_compare*/
85   0,                            /*tp_repr*/
86   0,                            /*tp_as_number*/
87   0,                            /*tp_as_sequence*/
88   0,                            /*tp_as_mapping*/
89   0,                            /*tp_hash*/
90   0,                            /*tp_call*/
91   0,                            /*tp_str*/
92   PyObject_GenericGetAttr,      /*tp_getattro*/
93   /* softspace is writable:  we must supply tp_setattro */
94   PyObject_GenericSetAttr,      /* tp_setattro */
95   0,                            /*tp_as_buffer*/
96   Py_TPFLAGS_DEFAULT,           /*tp_flags*/
97   0,                            /*tp_doc*/
98   0,                            /*tp_traverse*/
99   0,                            /*tp_clear*/
100   0,                            /*tp_richcompare*/
101   0,                            /*tp_weaklistoffset*/
102   0,                            /*tp_iter*/
103   0,                            /*tp_iternext*/
104   PyStdOut_methods,             /*tp_methods*/
105   PyStdOut_memberlist,          /*tp_members*/
106   0,                            /*tp_getset*/
107   0,                            /*tp_base*/
108   0,                            /*tp_dict*/
109   0,                            /*tp_descr_get*/
110   0,                            /*tp_descr_set*/
111   0,                            /*tp_dictoffset*/
112   0,                            /*tp_init*/
113   0,                            /*tp_alloc*/
114   0,                            /*tp_new*/
115   0,                            /*tp_free*/
116   0,                            /*tp_is_gc*/
117 };
118
119 PyObject * newPyStdOut( std::string& out )
120 {
121   PyStdOut *self;
122   self = PyObject_New(PyStdOut, &PyStdOut_Type);
123   if (self == NULL)
124     return NULL;
125   self->softspace = 0;
126   self->out=&out;
127   return (PyObject*)self;
128 }
129
130
131 ////////////////////////END PYTHON///////////////////////////
132
133
134 //! The only one instance of Parser
135 Plot2d_AnalyticalParser* Plot2d_AnalyticalParser::myParser = 0;
136
137 //Define the script
138 QString Plot2d_AnalyticalParser::myScript = QString("");
139
140 /*!
141   \brief Return the only instance of the Plot2d_AnalyticalParser
142   \return instance of the Plot2d_AnalyticalParser
143 */
144 Plot2d_AnalyticalParser* Plot2d_AnalyticalParser::parser()
145 {
146   if ( !myParser )
147     myParser = new Plot2d_AnalyticalParser();
148   return myParser;
149 }
150
151 /*!
152   \brief Constructor.
153
154   Construct the Parser and initialize python interpritator.
155 */
156 Plot2d_AnalyticalParser::Plot2d_AnalyticalParser() 
157 {
158   /* Initialize the Python interpreter */
159   if (Py_IsInitialized()) {
160     PyGILState_STATE gstate = PyGILState_Ensure();
161     myMainMod = PyImport_AddModule("__main__");
162     myMainDict = PyModule_GetDict(myMainMod);
163     PyGILState_Release(gstate);
164     initScript();
165   }
166 }
167
168 int Plot2d_AnalyticalParser::calculate( const QString& theExpr,
169                                       const double theMin,
170                                       const double theMax,
171                                       const int theNbStep,
172                                       double** theX,
173                                       double** theY) {
174   
175   QString aPyScript = myScript;
176   aPyScript = aPyScript.arg(theExpr);
177   int result = -1;
178   PyGILState_STATE gstate = PyGILState_Ensure();
179   PyObject* obj = PyRun_String(qPrintable(aPyScript), Py_file_input, myMainDict, NULL);
180
181   if(obj == NULL) {
182     PyErr_Print();
183     PyGILState_Release(gstate);        
184     return result;
185     
186   } else {
187     Py_DECREF(obj);
188   }
189   
190   PyObject* func = NULL;
191   PyObject* f_y = NULL;
192   
193   if(PyObject_HasAttrString(myMainMod, "Y")) {
194     f_y = PyObject_GetAttrString(myMainMod, "Y");
195   }
196
197   if(PyObject_HasAttrString(myMainMod, "coordCalculator")) {
198     func = PyObject_GetAttrString(myMainMod, "coordCalculator");
199   }
200
201   PyObject* new_stderr = NULL;
202   
203   if( f_y == NULL || func == NULL )  {
204     fflush(stderr);
205     std::string err_description="";
206     new_stderr = newPyStdOut(err_description);
207     PySys_SetObject((char*)"stderr", new_stderr);
208     PyErr_Print();
209     PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
210     Py_DECREF(new_stderr);
211     PyGILState_Release(gstate);
212     return result;
213   }
214     
215   PyObject* coords;
216   coords = PyObject_CallFunction(func,(char*)"(d, d, i)", theMin, theMax, theNbStep );
217
218   new_stderr = NULL;
219   
220   if (coords == NULL){
221     fflush(stderr);
222     std::string err_description="";
223     new_stderr = newPyStdOut(err_description);
224     PySys_SetObject((char*)"stderr", new_stderr);
225     PyErr_Print();
226     PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
227     Py_DECREF(new_stderr);
228     PyGILState_Release(gstate);
229     return result;
230   }
231
232   Py_ssize_t size = PyList_Size( coords );
233   if( size <= 0 ) {
234     Py_DECREF(coords);
235     return result;
236   }
237
238   result = size;
239
240   *theX = new double[size];
241   *theY = new double[size];
242   
243   for ( Py_ssize_t i = 0; i< size; ++i ) {
244     PyObject* coord = PyList_GetItem( coords, i );
245     (*theX)[i] =  PyFloat_AsDouble(PyList_GetItem(coord, 0));
246     (*theY)[i] =  PyFloat_AsDouble(PyList_GetItem(coord, 1));
247   }
248
249   PyGILState_Release(gstate);
250   return result;
251 }
252
253 /*!
254   \brief Initialize python script.
255 */
256 void Plot2d_AnalyticalParser::initScript() {
257   myScript.clear();
258   myScript += "from math import *                      \n";
259   myScript += "def Y(x):                               \n";
260   myScript += "    return ";
261   myScript += "%1\n";
262
263   myScript += "def coordCalculator(xmin, xmax, nstep):     \n";
264   myScript += "   coords = []                              \n";
265   myScript += "   xstep  = (xmax - xmin) / nstep           \n";
266   myScript += "   n = 0                                    \n";
267   myScript += "   while n <= nstep :                       \n";
268   myScript += "      x = xmin + n*xstep                    \n";
269   myScript += "      try:                                  \n";
270   myScript += "                 y = Y(x)                           \n";
271   myScript += "                 coords.append([x,y])               \n";
272   myScript += "      except ValueError, ZeroDivisionError: \n";
273   myScript += "                 pass                               \n";
274   myScript += "      n = n+1                               \n";
275   myScript += "   return coords                            \n";
276 }