1 // Copyright (C) 2007-2023 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.vtkRenderingCore" );
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 myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
229 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderer( PyObject* /*self*/, PyObject* args )
231 PyObject* aResult = Py_None;
233 int toKeepDetached = 0;
234 if ( !PyArg_ParseTuple( args, "|ii:getRenderer", &toCreate, &toKeepDetached ) )
237 aResult = ProcessEvent( new TGetRendererEvent( toCreate, toKeepDetached ) );
242 \fn PyObject* getRenderWindow( int toCreate = 0 );
243 \brief Get VTK render window (vtkRenderWindow).
245 If \a toCreate parameter is 0 (by default) the function tries to find
246 and reuse existing VTK window; if it is not found, the new VTK window
249 If \a toCreate parameter is non-zero, the function always creates
252 If VTK window could not be found and or created, the None Python object
255 \param toCreate window creation mode
256 \return VTK window render window object
259 class SALOMEPY_EXPORT TGetRenderWindowEvent: public SALOME_Event
262 typedef PyObject* TResult;
266 TGetRenderWindowEvent( bool toCreate, bool toKeepDetached )
267 : myResult( Py_None ), myCreate( toCreate ), myKeepDetached( toKeepDetached ) {}
268 virtual void Execute()
270 PyTypeObject* aPyClass = ::GetPyClass( "vtkRenderWindow" );
271 SVTK_ViewWindow* aVTKViewWindow =
272 ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate, myKeepDetached );
273 if( aVTKViewWindow && aPyClass ) {
274 vtkRenderWindow* aVTKObject = aVTKViewWindow->getRenderWindow();
275 myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
280 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderWindow( PyObject* /*self*/, PyObject* args )
282 PyObject* aResult = Py_None;
284 int toKeepDetached = 0;
285 if ( !PyArg_ParseTuple( args, "|ii:getRenderWindow", &toCreate, &toKeepDetached ) )
288 aResult = ProcessEvent( new TGetRenderWindowEvent( toCreate, toKeepDetached ) );
293 \fn PyObject* getRenderWindowInteractor( int toCreate = 0 );
294 \brief Get VTK render window interactor (getRenderWindowInteractor).
296 If \a toCreate parameter is 0 (by default) the function tries to find
297 and reuse existing VTK window; if it is not found, the new VTK window
300 If \a toCreate parameter is non-zero, the function always creates
303 If VTK window could not be found and or created, the None Python object
306 \param toCreate window creation mode
307 \return VTK window render window interactor object
310 class SALOMEPY_EXPORT TGetRenderWindowInteractorEvent: public SALOME_Event
313 typedef PyObject* TResult;
317 TGetRenderWindowInteractorEvent( bool toCreate, bool toKeepDetached )
318 : myResult( Py_None ), myCreate( toCreate ), myKeepDetached( toKeepDetached ) {}
319 virtual void Execute()
321 PyTypeObject* aPyClass = ::GetPyClass( "vtkRenderWindowInteractor" );
322 SVTK_ViewWindow* aVTKViewWindow =
323 ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate, myKeepDetached );
324 if( aVTKViewWindow && aPyClass ) {
325 vtkRenderWindowInteractor* aVTKObject = aVTKViewWindow->getInteractor();
326 myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
331 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderWindowInteractor( PyObject* /*self*/, PyObject* args )
333 PyObject* aResult = Py_None;
335 int toKeepDetached = 0;
336 if ( !PyArg_ParseTuple( args, "|ii:getRenderWindowInteractor", &toCreate, &toKeepDetached ) )
339 aResult = ProcessEvent( new TGetRenderWindowInteractorEvent( toCreate, toKeepDetached ) );
344 \fn PyObject* showTrihedron( int show );
345 \brief Show/hide trihedron in the current VTK viewer.
347 If there is no active VTK viewer, nothing happens.
349 \param show new trihedron visibility state
350 \return nothing (Py_None)
353 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_showTrihedron( PyObject* /*self*/, PyObject* args )
355 class TEvent: public SALOME_Event
361 virtual void Execute()
363 if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
364 if ( aVTKViewWindow->isTrihedronDisplayed() != (bool)myShow )
365 aVTKViewWindow->onViewTrihedron(myShow);
370 PyObject* aResult = Py_None;
372 if ( !PyArg_ParseTuple( args, "i:showTrihedron", &bShow ) )
375 ProcessVoidEvent( new TEvent( bShow ) );
380 \fn PyObject* fitAll();
381 \brief Fit all the contents in the current VTK viewer.
383 If there is no active VTK viewer, nothing happens.
385 \return nothing (Py_None)
388 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_fitAll( PyObject* /*self*/, PyObject* /*args*/ )
390 class TEvent: public SALOME_Event
394 virtual void Execute()
396 if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
397 aVTKViewWindow->onFitAll();
402 ProcessVoidEvent( new TEvent() );
407 \fn PyObject* setView( int type );
408 \brief Set view type for the current VTK viewer.
410 If there is no active VTK viewer, nothing happens.
412 \param type view type
413 \return nothing (Py_None)
416 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_setView( PyObject* /*self*/, PyObject* args )
418 class TEvent: public SALOME_Event
422 TEvent( long type ) : myType( type) {}
423 virtual void Execute()
425 if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
428 aVTKViewWindow->onFrontView(); break;
430 aVTKViewWindow->onBackView(); break;
432 aVTKViewWindow->onTopView(); break;
434 aVTKViewWindow->onBottomView(); break;
436 aVTKViewWindow->onRightView(); break;
438 aVTKViewWindow->onLeftView(); break;
440 PyErr_Format(PyExc_ValueError,"setView: wrong parameter value; must be between %d and %d", ViewFront, ViewLeft );
448 if ( !PyArg_ParseTuple( args, "l:setView", &type ) )
451 ProcessVoidEvent( new TEvent( type ) );
452 if( PyErr_Occurred() )
459 \fn PyObject* resetView();
460 \brief Reset contents of the current VTK viewer.
462 If there is no active VTK viewer, nothing happens.
464 \return nothing (Py_None)
467 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_resetView( PyObject* /*self*/, PyObject* /*args*/ )
469 class TEvent: public SALOME_Event
473 virtual void Execute()
475 if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
476 aVTKViewWindow->onResetView();
481 ProcessVoidEvent( new TEvent() );
485 static PyMethodDef libSalomePy_methods[] =
487 { "getRenderer", libSalomePy_getRenderer, METH_VARARGS, PyDoc_STR("Get renderer from current vtk view") },
488 { "getRenderWindow", libSalomePy_getRenderWindow, METH_VARARGS, PyDoc_STR("Get render window from current vtk view") },
489 { "getRenderWindowInteractor", libSalomePy_getRenderWindowInteractor, METH_VARARGS, PyDoc_STR("Get interactor from current vtk view") },
490 { "showTrihedron", libSalomePy_showTrihedron, METH_VARARGS, PyDoc_STR("Show/hide trihedron in current vtk view") },
491 { "fitAll", libSalomePy_fitAll, METH_NOARGS, PyDoc_STR("Fit current vtk view to show all contents") },
492 { "setView", libSalomePy_setView, METH_VARARGS, PyDoc_STR("Set side view for the current VTK viewer") },
493 { "resetView", libSalomePy_resetView, METH_NOARGS, PyDoc_STR("Reset camera for current vtk view") },
497 struct module_state {
501 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
503 static int libSalomePy_traverse(PyObject *m, visitproc visit, void *arg) {
504 Py_VISIT(GETSTATE(m)->error);
508 static int libSalomePy_clear(PyObject *m) {
509 Py_CLEAR(GETSTATE(m)->error);
513 static struct PyModuleDef moduledef = {
514 PyModuleDef_HEAD_INIT,
517 sizeof(struct module_state),
520 libSalomePy_traverse,
526 \brief Python module initialization.
529 extern "C" SALOMEPY_EXPORT PyMODINIT_FUNC PyInit_libSalomePy(void)
532 PyObject *aModule = PyModule_Create(&moduledef);
533 if( PyErr_Occurred() ) {
538 // get module's dictionary
539 PyObject *aModuleDict = PyModule_GetDict( aModule );
540 if ( aModuleDict == NULL )
543 // export View type enumeration
544 PUBLISH_ENUM( ViewFront );
545 PUBLISH_ENUM( ViewBack );
546 PUBLISH_ENUM( ViewTop );
547 PUBLISH_ENUM( ViewBottom );
548 PUBLISH_ENUM( ViewRight );
549 PUBLISH_ENUM( ViewLeft );