1 // Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SALOME SALOME_PY : binding of VTK graphics and Python
24 // File : SalomePy.cxx
25 // Author : Paul RASCLE, EDF
28 // E.A. : On windows with python 2.6, there is a conflict
29 // E.A. : between pymath.h and Standard_math.h which define
30 // E.A. : some same symbols : acosh, asinh, ...
31 #include <Standard_math.hxx>
36 #include <vtkPythonUtil.h>
38 #include <vtkVersion.h>
39 #include <vtkRenderer.h>
40 #include <vtkRenderWindow.h>
41 #include <vtkRenderWindowInteractor.h>
43 #include <SALOME_Event.h>
45 #include <SUIT_Session.h>
46 #include <LightApp_Application.h>
47 #include <LightApp_Study.h>
49 #include <SVTK_ViewManager.h>
50 #include <SVTK_ViewWindow.h>
52 #define VTK_XVERSION (VTK_MAJOR_VERSION*10000+VTK_MINOR_VERSION*100+VTK_BUILD_VERSION)
55 \brief Python wrappings for VTK viewer of the SALOME desktop.
57 All methods are implemented using Event mechanism. The module
58 provides the following functions:
61 - getRenderWindowInteractor()
70 renderer = SalomePy.getRenderer() # get VTK renderer
71 window = SalomePy.getRenderWindow() # get render window
74 The methods getRenderer(), getRenderWindow() and getRenderWindowInteractor()
75 open new VTK viewer if there is no one opened.
76 In case of any error these methods return None object to the Python.
80 #if defined SALOMEPY_EXPORTS || defined SalomePy_EXPORTS
81 #define SALOMEPY_EXPORT __declspec( dllexport )
83 #define SALOMEPY_EXPORT __declspec( dllimport )
86 #define SALOMEPY_EXPORT
90 #define PUBLISH_ENUM(i) \
94 if ( ( w = PyLong_FromLong( i ) ) == NULL ) return NULL; \
95 rc = PyDict_SetItemString( aModuleDict, #i, w ); \
97 if ( rc < 0 ) return NULL; \
100 //! View operation type
102 ViewFront, //!< front view
103 ViewBack, //!< back view
104 ViewTop, //!< top view
105 ViewBottom, //!< bottom view
106 ViewRight, //!< right view
107 ViewLeft //!< left view
111 \brief Get Python class object by name
113 \param theClassName Python class name
114 \return Python class object or None object if class is not found
116 static PyTypeObject* GetPyClass( const char* theClassName )
118 static PyObject* aVTKModule = 0;
119 PyObject* aPyClass = 0;
121 aVTKModule = PyImport_ImportModule( "vtk.vtkRenderingCorePython" );
122 if( PyErr_Occurred() ) {
127 PyObject* aVTKDict = PyModule_GetDict( aVTKModule );
128 aPyClass = PyDict_GetItemString(aVTKDict, const_cast<char*>( theClassName ) );
129 if (!PyType_Check(aPyClass))
132 return (PyTypeObject *)aPyClass;
136 \brief VTK window find/create mode
140 __Find, // try to find VTK window; if not found, do nothing
141 __FindOrCreate, // try to find VTK window; if not found, create new one
142 __Create }; // create new VTK window
145 \brief Find or create VTK window.
147 \param toCreate window find/create mode
148 \return VTK window pointer or 0 if it could not be found/created
150 static SVTK_ViewWindow* GetVTKViewWindow( int toCreate = __FindOrCreate, int toKeepDetached = 0 ) {
151 SVTK_ViewWindow* aVW = 0;
152 if ( SUIT_Session::session() ) {
154 LightApp_Application* anApp = dynamic_cast<LightApp_Application*>( SUIT_Session::session()->activeApplication() );
157 LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>( anApp->activeStudy() );
159 // find or create VTK view manager
160 if ( toCreate == __Create ) {
161 SVTK_ViewManager* aVM = dynamic_cast<SVTK_ViewManager*>( anApp->createViewManager( "VTKViewer" ) );
163 aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getActiveView() );
165 aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->createViewWindow() );
166 // VSR : When new view window is created it can be not active yet at this moment,
167 // so the following is a some workaround
168 if ( !aVW && !aVM->getViews().isEmpty() )
169 aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getViews()[0] );
173 anApp->setProperty("keep_detached", toKeepDetached != 0 );
174 SVTK_ViewManager* aVM = dynamic_cast<SVTK_ViewManager*>( anApp->getViewManager( "VTKViewer", toCreate == __FindOrCreate ) );
175 anApp->setProperty("keep_detached", QVariant());
177 aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getActiveView() );
178 // VSR : When new view window is created it can be not active yet at this moment,
179 // so the following is a some workaround
180 if ( !aVW && !aVM->getViews().isEmpty() )
181 aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getViews()[0] );
191 \fn PyObject* getRenderer( int toCreate = 0 );
192 \brief Get VTK renderer (vtkRenderer).
194 If \a toCreate parameter is 0 (by default) the function tries to find
195 and reuse existing VTK window; if it is not found, the new VTK window
198 If \a toCreate parameter is non-zero, the function always creates
201 If VTK window could not be found and or created, the None Python object
204 \param toCreate window creation mode
205 \return VTK window renderer object
208 class SALOMEPY_EXPORT TGetRendererEvent: public SALOME_Event
211 typedef PyObject* TResult;
215 TGetRendererEvent( bool toCreate, bool toKeepDetached )
216 : myResult( Py_None ), myCreate( toCreate ), myKeepDetached( toKeepDetached ) {}
217 virtual void Execute()
219 PyTypeObject* aPyClass = ::GetPyClass( "vtkRenderer" );
220 SVTK_ViewWindow* aVTKViewWindow =
221 ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate, myKeepDetached );
222 if( aVTKViewWindow && aPyClass ) {
223 vtkRenderer* aVTKObject = aVTKViewWindow->getRenderer();
224 #if VTK_XVERSION < 50700
225 myResult = PyVTKObject_New( aPyClass, aVTKObject );
227 myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
233 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderer( PyObject* /*self*/, PyObject* args )
235 PyObject* aResult = Py_None;
237 int toKeepDetached = 0;
238 if ( !PyArg_ParseTuple( args, "|ii:getRenderer", &toCreate, &toKeepDetached ) )
241 aResult = ProcessEvent( new TGetRendererEvent( toCreate, toKeepDetached ) );
246 \fn PyObject* getRenderWindow( int toCreate = 0 );
247 \brief Get VTK render window (vtkRenderWindow).
249 If \a toCreate parameter is 0 (by default) the function tries to find
250 and reuse existing VTK window; if it is not found, the new VTK window
253 If \a toCreate parameter is non-zero, the function always creates
256 If VTK window could not be found and or created, the None Python object
259 \param toCreate window creation mode
260 \return VTK window render window object
263 class SALOMEPY_EXPORT TGetRenderWindowEvent: public SALOME_Event
266 typedef PyObject* TResult;
270 TGetRenderWindowEvent( bool toCreate, bool toKeepDetached )
271 : myResult( Py_None ), myCreate( toCreate ), myKeepDetached( toKeepDetached ) {}
272 virtual void Execute()
274 PyTypeObject* aPyClass = ::GetPyClass( "vtkRenderWindow" );
275 SVTK_ViewWindow* aVTKViewWindow =
276 ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate, myKeepDetached );
277 if( aVTKViewWindow && aPyClass ) {
278 vtkRenderWindow* aVTKObject = aVTKViewWindow->getRenderWindow();
279 #if VTK_XVERSION < 50700
280 myResult = PyVTKObject_New( aPyClass, aVTKObject );
282 myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
288 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderWindow( PyObject* /*self*/, PyObject* args )
290 PyObject* aResult = Py_None;
292 int toKeepDetached = 0;
293 if ( !PyArg_ParseTuple( args, "|ii:getRenderWindow", &toCreate, &toKeepDetached ) )
296 aResult = ProcessEvent( new TGetRenderWindowEvent( toCreate, toKeepDetached ) );
301 \fn PyObject* getRenderWindowInteractor( int toCreate = 0 );
302 \brief Get VTK render window interactor (getRenderWindowInteractor).
304 If \a toCreate parameter is 0 (by default) the function tries to find
305 and reuse existing VTK window; if it is not found, the new VTK window
308 If \a toCreate parameter is non-zero, the function always creates
311 If VTK window could not be found and or created, the None Python object
314 \param toCreate window creation mode
315 \return VTK window render window interactor object
318 class SALOMEPY_EXPORT TGetRenderWindowInteractorEvent: public SALOME_Event
321 typedef PyObject* TResult;
325 TGetRenderWindowInteractorEvent( bool toCreate, bool toKeepDetached )
326 : myResult( Py_None ), myCreate( toCreate ), myKeepDetached( toKeepDetached ) {}
327 virtual void Execute()
329 PyTypeObject* aPyClass = ::GetPyClass( "vtkRenderWindowInteractor" );
330 SVTK_ViewWindow* aVTKViewWindow =
331 ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate, myKeepDetached );
332 if( aVTKViewWindow && aPyClass ) {
333 vtkRenderWindowInteractor* aVTKObject = aVTKViewWindow->getInteractor();
334 #if VTK_XVERSION < 50700
335 myResult = PyVTKObject_New( aPyClass, aVTKObject );
337 myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
343 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderWindowInteractor( PyObject* /*self*/, PyObject* args )
345 PyObject* aResult = Py_None;
347 int toKeepDetached = 0;
348 if ( !PyArg_ParseTuple( args, "|ii:getRenderWindowInteractor", &toCreate, &toKeepDetached ) )
351 aResult = ProcessEvent( new TGetRenderWindowInteractorEvent( toCreate, toKeepDetached ) );
356 \fn PyObject* showTrihedron( int show );
357 \brief Show/hide trihedron in the current VTK viewer.
359 If there is no active VTK viewer, nothing happens.
361 \param show new trihedron visibility state
362 \return nothing (Py_None)
365 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_showTrihedron( PyObject* /*self*/, PyObject* args )
367 class TEvent: public SALOME_Event
373 virtual void Execute()
375 if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
376 if ( aVTKViewWindow->isTrihedronDisplayed() != (bool)myShow )
377 aVTKViewWindow->onViewTrihedron(myShow);
382 PyObject* aResult = Py_None;
384 if ( !PyArg_ParseTuple( args, "i:showTrihedron", &bShow ) )
387 ProcessVoidEvent( new TEvent( bShow ) );
392 \fn PyObject* fitAll();
393 \brief Fit all the contents in the current VTK viewer.
395 If there is no active VTK viewer, nothing happens.
397 \return nothing (Py_None)
400 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_fitAll( PyObject* /*self*/, PyObject* /*args*/ )
402 class TEvent: public SALOME_Event
406 virtual void Execute()
408 if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
409 aVTKViewWindow->onFitAll();
414 ProcessVoidEvent( new TEvent() );
419 \fn PyObject* setView( int type );
420 \brief Set view type for the current VTK viewer.
422 If there is no active VTK viewer, nothing happens.
424 \param type view type
425 \return nothing (Py_None)
428 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_setView( PyObject* /*self*/, PyObject* args )
430 class TEvent: public SALOME_Event
434 TEvent( long type ) : myType( type) {}
435 virtual void Execute()
437 if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
440 aVTKViewWindow->onFrontView(); break;
442 aVTKViewWindow->onBackView(); break;
444 aVTKViewWindow->onTopView(); break;
446 aVTKViewWindow->onBottomView(); break;
448 aVTKViewWindow->onRightView(); break;
450 aVTKViewWindow->onLeftView(); break;
452 PyErr_Format(PyExc_ValueError,"setView: wrong parameter value; must be between %d and %d", ViewFront, ViewLeft );
460 if ( !PyArg_ParseTuple( args, "l:setView", &type ) )
463 ProcessVoidEvent( new TEvent( type ) );
464 if( PyErr_Occurred() )
471 \fn PyObject* resetView();
472 \brief Reset contents of the current VTK viewer.
474 If there is no active VTK viewer, nothing happens.
476 \return nothing (Py_None)
479 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_resetView( PyObject* /*self*/, PyObject* /*args*/ )
481 class TEvent: public SALOME_Event
485 virtual void Execute()
487 if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
488 aVTKViewWindow->onResetView();
493 ProcessVoidEvent( new TEvent() );
497 static PyMethodDef libSalomePy_methods[] =
499 { "getRenderer", libSalomePy_getRenderer, METH_VARARGS, PyDoc_STR("Get renderer from current vtk view") },
500 { "getRenderWindow", libSalomePy_getRenderWindow, METH_VARARGS, PyDoc_STR("Get render window from current vtk view") },
501 { "getRenderWindowInteractor", libSalomePy_getRenderWindowInteractor, METH_VARARGS, PyDoc_STR("Get interactor from current vtk view") },
502 { "showTrihedron", libSalomePy_showTrihedron, METH_VARARGS, PyDoc_STR("Show/hide trihedron in current vtk view") },
503 { "fitAll", libSalomePy_fitAll, METH_NOARGS, PyDoc_STR("Fit current vtk view to show all contents") },
504 { "setView", libSalomePy_setView, METH_VARARGS, PyDoc_STR("Set side view for the current VTK viewer") },
505 { "resetView", libSalomePy_resetView, METH_NOARGS, PyDoc_STR("Reset camera for current vtk view") },
509 struct module_state {
513 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
515 static int libSalomePy_traverse(PyObject *m, visitproc visit, void *arg) {
516 Py_VISIT(GETSTATE(m)->error);
520 static int libSalomePy_clear(PyObject *m) {
521 Py_CLEAR(GETSTATE(m)->error);
525 static struct PyModuleDef moduledef = {
526 PyModuleDef_HEAD_INIT,
529 sizeof(struct module_state),
532 libSalomePy_traverse,
538 \brief Python module initialization.
541 extern "C" SALOMEPY_EXPORT PyMODINIT_FUNC PyInit_libSalomePy(void)
544 PyObject *aModule = PyModule_Create(&moduledef);
545 if( PyErr_Occurred() ) {
550 // get module's dictionary
551 PyObject *aModuleDict = PyModule_GetDict( aModule );
552 if ( aModuleDict == NULL )
555 // export View type enumeration
556 PUBLISH_ENUM( ViewFront );
557 PUBLISH_ENUM( ViewBack );
558 PUBLISH_ENUM( ViewTop );
559 PUBLISH_ENUM( ViewBottom );
560 PUBLISH_ENUM( ViewRight );
561 PUBLISH_ENUM( ViewLeft );