Salome HOME
Copyright update: 2016
[modules/gui.git] / src / Plot2d / Plot2d_AnalyticalParser.cxx
1 // Copyright (C) 2007-2016  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 //  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 namespace {
33   typedef struct {
34     PyObject_HEAD
35     int softspace;
36     std::string *out;
37     } PyStdOut;
38
39   static void
40   PyStdOut_dealloc(PyStdOut *self)
41   {
42     PyObject_Del(self);
43   }
44
45   static PyObject *
46   PyStdOut_write(PyStdOut *self, PyObject *args)
47   {
48     char *c;
49     int l;
50     if (!PyArg_ParseTuple(args, "t#:write",&c, &l))
51       return NULL;
52
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 = PyObject_New(PyStdOut, &PyStdOut_Type);
122     if (self) {
123       self->softspace = 0;
124       self->out=&out;
125     }
126     return (PyObject*)self;
127   }
128 }
129
130 ////////////////////////END PYTHON///////////////////////////
131
132
133 //! The only one instance of Parser
134 Plot2d_AnalyticalParser* Plot2d_AnalyticalParser::myParser = 0;
135
136 //Define the script
137 QString Plot2d_AnalyticalParser::myScript = QString("");
138
139 /*!
140   \brief Return the only instance of the Plot2d_AnalyticalParser
141   \return instance of the Plot2d_AnalyticalParser
142 */
143 Plot2d_AnalyticalParser* Plot2d_AnalyticalParser::parser()
144 {
145   if ( !myParser )
146     myParser = new Plot2d_AnalyticalParser();
147   return myParser;
148 }
149
150 /*!
151   \brief Constructor.
152
153   Construct the Parser and initialize python interpritator.
154 */
155 Plot2d_AnalyticalParser::Plot2d_AnalyticalParser() 
156 {
157   /* Initialize the Python interpreter */
158   if (Py_IsInitialized()) {
159     PyGILState_STATE gstate = PyGILState_Ensure();
160     myMainMod = PyImport_AddModule("__main__");
161     myMainDict = PyModule_GetDict(myMainMod);
162     PyGILState_Release(gstate);
163     initScript();
164   }
165 }
166
167 int Plot2d_AnalyticalParser::calculate( const QString& theExpr,
168                                       const double theMin,
169                                       const double theMax,
170                                       const int theNbStep,
171                                       double** theX,
172                                       double** theY) {
173   
174   QString aPyScript = myScript;
175   aPyScript = aPyScript.arg(theExpr);
176   int result = -1;
177   PyGILState_STATE gstate = PyGILState_Ensure();
178   PyObject* obj = PyRun_String(qPrintable(aPyScript), Py_file_input, myMainDict, NULL);
179
180   if(obj == NULL) {
181     PyErr_Print();
182     PyGILState_Release(gstate);        
183     return result;
184     
185   } else {
186     Py_DECREF(obj);
187   }
188   
189   PyObject* func = NULL;
190   PyObject* f_y = NULL;
191   
192   if(PyObject_HasAttrString(myMainMod, "Y")) {
193     f_y = PyObject_GetAttrString(myMainMod, "Y");
194   }
195
196   if(PyObject_HasAttrString(myMainMod, "coordCalculator")) {
197     func = PyObject_GetAttrString(myMainMod, "coordCalculator");
198   }
199   
200   if( f_y == NULL || func == NULL )  {
201     fflush(stderr);
202     std::string err_description="";
203     PyObject* new_stderr = newPyStdOut(err_description);
204     PyObject* old_stderr = PySys_GetObject((char*)"stderr");
205     Py_INCREF(old_stderr);
206     PySys_SetObject((char*)"stderr", new_stderr);
207     PyErr_Print();
208     PySys_SetObject((char*)"stderr", old_stderr);
209     Py_DECREF(new_stderr);
210     PyGILState_Release(gstate);
211     return result;
212   }
213     
214   PyObject* coords = PyObject_CallFunction(func,(char*)"(d, d, i)", theMin, theMax, theNbStep );
215   
216   if (coords == NULL){
217     fflush(stderr);
218     std::string err_description="";
219     PyObject* new_stderr = newPyStdOut(err_description);
220     PyObject* old_stderr = PySys_GetObject((char*)"stderr");
221     Py_INCREF(old_stderr);
222     PySys_SetObject((char*)"stderr", new_stderr);
223     PyErr_Print();
224     PySys_SetObject((char*)"stderr", old_stderr);
225     Py_DECREF(new_stderr);
226     PyGILState_Release(gstate);
227     return result;
228   }
229
230   Py_ssize_t size = PyList_Size( coords );
231   if( size <= 0 ) {
232     Py_DECREF(coords);
233     return result;
234   }
235
236   result = size;
237
238   *theX = new double[size];
239   *theY = new double[size];
240   
241   for ( Py_ssize_t i = 0; i< size; ++i ) {
242     PyObject* coord = PyList_GetItem( coords, i );
243     (*theX)[i] =  PyFloat_AsDouble(PyList_GetItem(coord, 0));
244     (*theY)[i] =  PyFloat_AsDouble(PyList_GetItem(coord, 1));
245   }
246
247   PyGILState_Release(gstate);
248   return result;
249 }
250
251 /*!
252   \brief Initialize python script.
253 */
254 void Plot2d_AnalyticalParser::initScript() {
255   myScript.clear();
256   myScript += "from math import *                      \n";
257   myScript += "def Y(x):                               \n";
258   myScript += "    return ";
259   myScript += "%1\n";
260
261   myScript += "def coordCalculator(xmin, xmax, nstep):     \n";
262   myScript += "   coords = []                              \n";
263   myScript += "   xstep  = (xmax - xmin) / nstep           \n";
264   myScript += "   n = 0                                    \n";
265   myScript += "   while n <= nstep :                       \n";
266   myScript += "      x = xmin + n*xstep                    \n";
267   myScript += "      try:                                  \n";
268   myScript += "                 y = Y(x)                           \n";
269   myScript += "                 coords.append([x,y])               \n";
270   myScript += "      except ValueError, ZeroDivisionError: \n";
271   myScript += "                 pass                               \n";
272   myScript += "      n = n+1                               \n";
273   myScript += "   return coords                            \n";
274 }