1 // Copyright (C) 2010-2022 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Adrien BRUNETON
24 // see https://docs.scipy.org/doc/numpy/reference/c-api.array.html?highlight=import_array
25 // and https://docs.scipy.org/doc/numpy-1.15.0/reference/c-api.deprecations.html
26 #define PY_ARRAY_UNIQUE_SYMBOL CURVEPLOT_ARRAY_API
27 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
28 #include <numpy/ndarraytypes.h>
29 #include <numpy/ndarrayobject.h>
30 #include <PyInterp_Utils.h> // GUI
32 #include "CurvePlot.hxx"
33 #include "CurvePlot_Exception.hxx"
37 PyObject * strToPyUnicode(std::string s)
39 return PyUnicode_DecodeUTF8(s.c_str(), s.size(), (char*)"strict");
42 void HandleAndPrintPyError(std::string msg)
47 throw CURVEPLOT::Exception(msg);
55 * To be called before doing anything
57 void* InitializeCurvePlot()
60 // TODO: discuss where the below should really happen:
61 // doc: http://docs.scipy.org/doc/numpy/reference/c-api.array.html#importing-the-api
62 import_array(); // a macro really which contains a return
66 class ColumnVector::Internal
69 Internal() : _npArray(0) {}
72 PyArrayObject * _npArray;
75 ColumnVector::ColumnVector()
77 _impl = new Internal();
80 ColumnVector::~ColumnVector()
85 int ColumnVector::size() const
91 int ndim = PyArray_NDIM(_impl->_npArray);
93 throw Exception("ColumnVector::size() : wrong number of dimensions for internal array!!");
94 npy_intp * dims = PyArray_DIMS(_impl->_npArray);
99 ColumnVector ColumnVector::BuildFromCMemory(double * data, int size)
104 npy_intp dims[1] = {size};
108 PyObject * obj = PyArray_SimpleNewFromData(1,dims,NPY_DOUBLE, data);
109 PyArrayObject * aobj = (PyArrayObject * )obj;
111 // Make Numpy responsible of the memory of the array (the memory will be freed
112 // as soon as the array is released in NumPy)
113 PyArray_ENABLEFLAGS(aobj, NPY_ARRAY_OWNDATA);
115 ret._impl->_npArray = aobj;
120 ColumnVector ColumnVector::BuildFromStdVector(const std::vector<double> & vec)
126 double * c_mem = (double *)malloc(sizeof(double) * vec.size());
128 throw Exception("ColumnVector::BuildFromStdVector() : memory allocation error!");
129 const double * data = &vec.front();
130 std::copy(data, data+vec.size(), c_mem);
131 npy_intp dims[1] = {(intptr_t) vec.size()};
135 PyObject * obj = PyArray_SimpleNewFromData(1,dims,NPY_DOUBLE, c_mem);
136 PyArrayObject * aobj = (PyArrayObject * )obj;
138 // Make Numpy responsible of the memory of the array (the memory will be freed
139 // as soon as the array is released in NumPy)
140 PyArray_ENABLEFLAGS(aobj, NPY_ARRAY_OWNDATA);
142 ret._impl->_npArray = aobj;
147 std::string ColumnVector::toStdString() const
149 std::string ret_str = "(None)";
150 if (!_impl->_npArray)
156 PyObject_CallMethod((PyObject *)_impl->_npArray, (char *)"__str__", NULL)
158 // Now extract the returned string
159 if(!PyUnicode_Check(ret_py))
160 throw Exception("CurvePlot::toStdString(): Unexpected returned type!");
162 const char *ptr = PyUnicode_AsUTF8AndSize(ret_py, &size);
163 ret_str = std::string(ptr);
168 void ColumnVector::createPythonVar(std::string varName) const
170 PyObject* main_module = PyImport_AddModule((char*)"__main__");
171 PyObject* global_dict = PyModule_GetDict(main_module);
172 PyDict_SetItemString(global_dict, varName.c_str(), (PyObject *)_impl->_npArray);
175 void ColumnVector::cleanPythonVar(std::string varName) const
177 // Could be a static method really ...
179 std::string s = std::string("del ") + varName;
180 const char * cmd = s.c_str();
181 PyRun_SimpleString(cmd);
184 CurvePlot * CurvePlot::_instance = NULL;
186 class CurvePlot::Internal
189 Internal() : _controller(0) {}
190 ///! Plot2d controller from Python:
191 PyObject * _controller;
194 CurvePlot::CurvePlot(bool test_mode)
196 // TODO: do not use an intermediate variable '__cont', but use directly Py***CallMethod()
197 _impl = new Internal();
202 code = std::string("import curveplot; from curveplot.SalomePyQt_MockUp import SalomePyQt;") +
203 std::string("__cont=curveplot.PlotController.GetInstance(sgPyQt=SalomePyQt())");
205 code = std::string("import curveplot;")+
206 std::string("__cont=curveplot.PlotController.GetInstance()");
208 int ret = PyRun_SimpleString(const_cast<char*>(code.c_str()));
210 throw Exception("CurvePlot::CurvePlot(): Unable to load curveplot Python module!");
212 // Now get the reference to __engine and save the pointer.
213 // All the calls below returns *borrowed* references
214 PyObject* main_module = PyImport_AddModule((char*)"__main__");
215 PyObject* global_dict = PyModule_GetDict(main_module);
216 PyObject* tmp = PyDict_GetItemString(global_dict, "__cont");
218 _impl->_controller = tmp;
219 Py_INCREF(_impl->_controller);
220 PyRun_SimpleString(const_cast<char*>("del __cont"));
224 CurvePlot::~CurvePlot()
226 if(_impl->_controller != NULL)
229 Py_XDECREF(_impl->_controller);
234 CurvePlot * CurvePlot::GetInstance(bool test_mode)
237 _instance = new CurvePlot(test_mode);
241 void CurvePlot::ToggleCurveBrowser(bool with_curve_browser)
244 throw Exception("CurvePlot::ToggleCurveBrowser() must be invoked before anything else!");
247 std::string bool_s = with_curve_browser ? "True" : "False";
248 std::string cod = std::string("import curveplot; curveplot.PlotController.WITH_CURVE_BROWSER=") + bool_s;
249 PyRun_SimpleString(const_cast<char *>(cod.c_str()));
250 HandleAndPrintPyError("CurvePlot::ToggleCurveBrowser(): Unable to toggle Curve Browser!");
253 PlotID CurvePlot::AddCurve(const ColumnVector & x, const ColumnVector & y,
254 PlotID & plot_set_id,
255 std::string curve_label/*=""*/, std::string x_label/*=""*/, std::string y_label/*=""*/,
256 bool append/*=true*/)
259 PyObject * cont = GetInstance()->_impl->_controller;
261 PyObject * xx = (PyObject *)x._impl->_npArray;
262 PyObject * yy = (PyObject *)y._impl->_npArray;
265 PyObject_CallMethod(cont, (char *)"AddCurve", (char *)"OOOOOi", xx, yy,
266 strToPyUnicode(curve_label), strToPyUnicode(x_label), strToPyUnicode(y_label),
269 HandleAndPrintPyError("CurvePlot::AddCurve(): unexpected error!");
270 // Now extract curve_id and plot_set_id from the returned tuple:
271 if(!PyTuple_Check(ret))
272 throw Exception("CurvePlot::AddCurve(): Unexpected returned type!");
273 PyObject * o1 = PyTuple_GetItem(ret, 0);
274 if (!PyLong_Check(o1))
275 throw Exception("CurvePlot::AddCurve(): Unexpected returned type!");
276 PlotID curveId = PyLong_AsLong(o1);
277 PyObject * o2 = PyTuple_GetItem(ret, 1);
278 if (!PyLong_Check(o2))
279 throw Exception("CurvePlot::AddCurve(): Unexpected returned type!");
280 plot_set_id = PyLong_AsLong(o2);
284 PlotID CurvePlot::AddPlotSet(std::string title/*=""*/)
287 PyObject * cont = GetInstance()->_impl->_controller;
290 PyObject_CallMethod(cont, (char *)"AddPlotSet", (char *)"O", strToPyUnicode(title))
292 HandleAndPrintPyError("CurvePlot::AddPlotSet(): unexpected error!");
293 return PyLong_AsLong(ret);
296 PlotID CurvePlot::DeleteCurve(PlotID curve_id/*=-1*/)
299 PyObject * cont = GetInstance()->_impl->_controller;
302 PyObject_CallMethod(cont, (char *)"DeleteCurve", (char *)"i", curve_id)
304 HandleAndPrintPyError("CurvePlot::DeleteCurve(): unexpected error!");
305 return PyLong_AsLong(ret);
308 PlotID CurvePlot::DeletePlotSet(PlotID plot_set_id/*=-1*/)
311 PyObject * cont = GetInstance()->_impl->_controller;
314 PyObject_CallMethod(cont, (char *)"DeletePlotSet", (char *)"i", plot_set_id)
316 HandleAndPrintPyError("CurvePlot::DeletePlotSet(): unexpected error!");
317 return PyLong_AsLong(ret);
320 PlotID CurvePlot::ClearPlotSet(PlotID plot_set_id/*=-1*/)
323 PyObject * cont = GetInstance()->_impl->_controller;
326 PyObject_CallMethod(cont, (char *)"ClearPlotSet", (char *)"i", plot_set_id)
328 HandleAndPrintPyError("CurvePlot::ClearPlotSet(): unexpected error!");
329 return PyLong_AsLong(ret);
332 bool CurvePlot::SetXLabel(std::string x_label, PlotID plot_set_id/*=-1*/)
335 PyObject * cont = GetInstance()->_impl->_controller;
338 PyObject_CallMethod(cont, (char *)"SetXLabel", (char *)"Oi", strToPyUnicode(x_label), plot_set_id)
340 HandleAndPrintPyError("CurvePlot::SetXLabel(): unexpected error!");
341 return ((PyObject *)ret == Py_True);
344 bool CurvePlot::SetYLabel(std::string y_label, PlotID plot_set_id/*=-1*/)
347 PyObject * cont = GetInstance()->_impl->_controller;
350 PyObject_CallMethod(cont, (char *)"SetYLabel", (char *)"Oi", strToPyUnicode(y_label), plot_set_id)
352 HandleAndPrintPyError("CurvePlot::SetYLabel(): unexpected error!");
353 return ((PyObject *)ret == Py_True);
356 bool CurvePlot::SetPlotSetTitle(std::string title, PlotID plot_set_id/*=-1*/)
359 PyObject * cont = GetInstance()->_impl->_controller;
362 PyObject_CallMethod(cont, (char *)"SetPlotSetTitle", (char *)"Oi", strToPyUnicode(title), plot_set_id));
363 HandleAndPrintPyError("CurvePlot::SetPlotSetTitle(): unexpected error!");
364 return ((PyObject *)ret == Py_True);
367 PlotID CurvePlot::GetPlotSetID(PlotID curve_id)
370 PyObject * cont = GetInstance()->_impl->_controller;
373 PyObject_CallMethod(cont, (char *)"GetPlotSetID", (char *)"i", curve_id)
375 HandleAndPrintPyError("CurvePlot::GetPlotSetID(): unexpected error!");
376 return PyLong_AsLong(ret);
379 PlotID CurvePlot::GetPlotSetIDByName(std::string name)
382 PyObject * cont = GetInstance()->_impl->_controller;
385 PyObject_CallMethod(cont, (char *)"GetPlotSetIDByName", (char *)"O", strToPyUnicode(name))
387 HandleAndPrintPyError("CurvePlot::GetPlotSetIDByName(): unexpected error!");
388 return PyLong_AsLong(ret);
391 PlotID CurvePlot::GetCurrentCurveID()
394 PyObject * cont = GetInstance()->_impl->_controller;
397 PyObject_CallMethod(cont, (char *)"GetCurrentCurveID", (char *)"")
399 HandleAndPrintPyError("CurvePlot::GetCurrentCurveID(): unexpected error!");
400 return PyLong_AsLong(ret);
403 PlotID CurvePlot::GetCurrentPlotSetID()
406 PyObject * cont = GetInstance()->_impl->_controller;
409 PyObject_CallMethod(cont, (char *)"GetCurrentPlotSetID", (char *)"")
411 HandleAndPrintPyError("CurvePlot::GetCurrentPlotSetID(): unexpected error!");
412 return PyLong_AsLong(ret);
415 bool CurvePlot::IsValidPlotSetID(PlotID plot_set_id)
418 PyObject * cont = GetInstance()->_impl->_controller;
421 PyObject_CallMethod(cont, (char *)"IsValidPlotSetID", (char *)"i", plot_set_id));
422 HandleAndPrintPyError("CurvePlot::IsValidPlotSetID(): unexpected error!");
423 return ((PyObject *)ret == Py_True);
426 int CurvePlot::GetSalomeViewID(PlotID plot_set_id)
429 PyObject * cont = GetInstance()->_impl->_controller;
432 PyObject_CallMethod(cont, (char *)"GetSalomeViewID", (char *)"i", plot_set_id));
433 HandleAndPrintPyError("CurvePlot::GetSalomeViewID(): unexpected error!");
434 return PyLong_AsLong(ret);
437 void CurvePlot::OnSalomeViewTryClose(int salome_view_id)
440 PyObject * cont = GetInstance()->_impl->_controller;
443 PyObject_CallMethod(cont, (char *)"OnSalomeViewTryClose", (char *)"i", salome_view_id));
444 HandleAndPrintPyError("CurvePlot::OnSalomeViewTryClose(): unexpected error!");