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