Salome HOME
0054504: Exception when accessing VTK renderer with libSalomePy module
[modules/gui.git] / src / SALOME_PY / SalomePy.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
23 //  SALOME SALOME_PY : binding of VTK graphics and Python
24 //  File   : SalomePy.cxx
25 //  Author : Paul RASCLE, EDF
26 //
27 #ifdef WIN32
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>
32 #include <pymath.h>
33 #endif
34
35 #include <Python.h>
36 #include <vtkPythonUtil.h>
37
38 #include <vtkVersion.h>
39 #include <vtkRenderer.h>
40 #include <vtkRenderWindow.h>
41 #include <vtkRenderWindowInteractor.h>
42
43 #include <SALOME_Event.h>
44
45 #include <SUIT_Session.h>
46 #include <LightApp_Application.h>
47 #include <LightApp_Study.h>
48
49 #include <SVTK_ViewManager.h>
50 #include <SVTK_ViewWindow.h>
51
52 #define VTK_XVERSION (VTK_MAJOR_VERSION*10000+VTK_MINOR_VERSION*100+VTK_BUILD_VERSION)
53
54 /*!
55   \brief Python wrappings for VTK viewer of the SALOME desktop.
56
57   All methods are implemented using Event mechanism. The module
58   provides the following functions:
59   - getRenderer()
60   - getRenderWindow()
61   - getRenderWindowInteractor()
62   - showTrihedron()
63   - fitAll()
64   - setView()
65   - resetView()
66
67   Usage in Python:
68   \code
69   import SalomePy
70   renderer = SalomePy.getRenderer()     # get VTK renderer
71   window   = SalomePy.getRenderWindow() # get render window
72   \endcode
73
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.
77 */
78
79 #ifdef WIN32
80  #if defined SALOMEPY_EXPORTS || defined SalomePy_EXPORTS
81   #define SALOMEPY_EXPORT __declspec( dllexport )
82  #else
83   #define SALOMEPY_EXPORT __declspec( dllimport )
84  #endif
85 #else
86  #define SALOMEPY_EXPORT
87 #endif
88
89
90 #define PUBLISH_ENUM(i)                              \
91 {                                                    \
92   PyObject *w;                                       \
93   int rc;                                            \
94   if ( ( w = PyLong_FromLong( i ) ) == NULL ) return NULL; \
95   rc = PyDict_SetItemString( aModuleDict, #i, w );   \
96   Py_DECREF( w );                                    \
97   if ( rc < 0 ) return NULL;                              \
98 }
99
100 //! View operation type
101 enum {
102   ViewFront,     //!< front view
103   ViewBack,      //!< back view
104   ViewTop,       //!< top view
105   ViewBottom,    //!< bottom view
106   ViewRight,     //!< right view
107   ViewLeft       //!< left view
108 };
109
110 /*!
111   \brief Get Python class object by name
112   \internal
113   \param theClassName Python class name
114   \return Python class object or None object if class is not found
115 */
116 static PyTypeObject* GetPyClass( const char* theClassName )
117 {
118   static PyObject* aVTKModule = 0;
119   PyObject* aPyClass = 0;
120   if( !aVTKModule ) {
121     aVTKModule = PyImport_ImportModule( "vtk.vtkRenderingCorePython" ); 
122     if( PyErr_Occurred() ) {
123       PyErr_Print();
124     }
125   }
126   if ( aVTKModule ) {
127     PyObject* aVTKDict = PyModule_GetDict( aVTKModule );
128     aPyClass = PyDict_GetItemString(aVTKDict, const_cast<char*>( theClassName ) );
129     if (!PyType_Check(aPyClass))
130       return 0;
131   }
132   return (PyTypeObject *)aPyClass;
133 }
134
135 /*!
136   \brief VTK window find/create mode
137   \internal
138 */
139 enum { 
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
143
144 /*!
145   \brief Find or create VTK window.
146   \internal
147   \param toCreate window find/create mode
148   \return VTK window pointer or 0 if it could not be found/created
149 */
150 static SVTK_ViewWindow* GetVTKViewWindow( int toCreate = __FindOrCreate ) {
151   SVTK_ViewWindow* aVW = 0;
152   if ( SUIT_Session::session() ) {
153     // get application
154     LightApp_Application* anApp = dynamic_cast<LightApp_Application*>( SUIT_Session::session()->activeApplication() );
155     if ( anApp ) {
156       // get active study
157       LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>( anApp->activeStudy() );
158       if ( aStudy ) {
159         // find or create VTK view manager
160         if ( toCreate == __Create ) {
161           SVTK_ViewManager* aVM = dynamic_cast<SVTK_ViewManager*>( anApp->createViewManager( "VTKViewer" ) );
162           if ( aVM ) {
163             aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getActiveView() );
164             if ( !aVW )
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] );
170           }
171         }
172         else {
173           SVTK_ViewManager* aVM = dynamic_cast<SVTK_ViewManager*>( anApp->getViewManager( "VTKViewer", toCreate == __FindOrCreate ) );
174           if ( aVM ) {
175             aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getActiveView() );
176             // VSR : When new view window is created it can be not active yet at this moment,
177             // so the following is a some workaround
178             if ( !aVW && !aVM->getViews().isEmpty() )
179               aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getViews()[0] );
180           }
181         }
182       }
183     }
184   }
185   return aVW;
186 }
187
188 /*!
189   \fn PyObject* getRenderer( int toCreate = 0 );
190   \brief Get VTK renderer (vtkRenderer).
191   
192   If \a toCreate parameter is 0 (by default) the function tries to find
193   and reuse existing VTK window; if it is not found, the new VTK window
194   is opened.
195
196   If \a toCreate parameter is non-zero, the function always creates
197   new VTK window.
198
199   If VTK window could not be found and or created, the None Python object
200   is returned.
201
202   \param toCreate window creation mode
203   \return VTK window renderer object
204 */
205
206 class SALOMEPY_EXPORT TGetRendererEvent: public SALOME_Event
207 {
208 public:
209   typedef PyObject* TResult;
210   TResult myResult;
211   int     myCreate;
212   TGetRendererEvent( bool toCreate )
213     : myResult( Py_None ), myCreate( toCreate ) {}
214   virtual void Execute()
215   {
216     PyTypeObject* aPyClass = ::GetPyClass( "vtkRenderer" );
217     SVTK_ViewWindow* aVTKViewWindow = 
218       ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate );
219     if( aVTKViewWindow && aPyClass ) {
220       vtkRenderer* aVTKObject = aVTKViewWindow->getRenderer();
221 #if VTK_XVERSION < 50700
222       myResult = PyVTKObject_New( aPyClass, aVTKObject );
223 #else
224       myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
225 #endif
226     }
227   }
228 };
229
230 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderer( PyObject* self, PyObject* args )
231 {
232   PyObject* aResult = Py_None;
233   int toCreate = 0;
234   if ( !PyArg_ParseTuple( args, "|i:getRenderer", &toCreate ) )
235     PyErr_Print();
236   else
237     aResult = ProcessEvent( new TGetRendererEvent( toCreate ) );
238   return aResult;
239 }
240
241 /*!
242   \fn PyObject* getRenderWindow( int toCreate = 0 );
243   \brief Get VTK render window (vtkRenderWindow).
244   
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
247   is opened.
248
249   If \a toCreate parameter is non-zero, the function always creates
250   new VTK window.
251
252   If VTK window could not be found and or created, the None Python object
253   is returned.
254
255   \param toCreate window creation mode
256   \return VTK window render window object
257 */
258
259 class SALOMEPY_EXPORT TGetRenderWindowEvent: public SALOME_Event
260 {
261 public:
262   typedef PyObject* TResult;
263   TResult myResult;
264   int     myCreate;
265   TGetRenderWindowEvent( bool toCreate )
266     : myResult( Py_None ), myCreate( toCreate ) {}
267   virtual void Execute()
268   {
269     PyTypeObject* aPyClass = ::GetPyClass( "vtkRenderWindow" );
270     SVTK_ViewWindow* aVTKViewWindow = 
271       ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate );
272     if( aVTKViewWindow && aPyClass ) {
273       vtkRenderWindow* aVTKObject = aVTKViewWindow->getRenderWindow();
274 #if VTK_XVERSION < 50700
275       myResult = PyVTKObject_New( aPyClass, aVTKObject );
276 #else
277       myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
278 #endif
279     }
280   }
281 };
282
283 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderWindow( PyObject* self, PyObject* args )
284 {
285   PyObject* aResult = Py_None;
286   int toCreate = 0;
287   if ( !PyArg_ParseTuple( args, "|i:getRenderWindow", &toCreate ) )
288     PyErr_Print();
289   else
290     aResult = ProcessEvent( new TGetRenderWindowEvent( toCreate ) );
291   return aResult;
292 }
293
294 /*!
295   \fn PyObject* getRenderWindowInteractor( int toCreate = 0 );
296   \brief Get VTK render window interactor (getRenderWindowInteractor).
297   
298   If \a toCreate parameter is 0 (by default) the function tries to find 
299   and reuse existing VTK window; if it is not found, the new VTK window
300   is opened.
301
302   If \a toCreate parameter is non-zero, the function always creates
303   new VTK window.
304
305   If VTK window could not be found and or created, the None Python object
306   is returned.
307
308   \param toCreate window creation mode
309   \return VTK window render window interactor object
310 */
311
312 class SALOMEPY_EXPORT TGetRenderWindowInteractorEvent: public SALOME_Event
313 {
314 public:
315   typedef PyObject* TResult;
316   TResult myResult;
317   int     myCreate;
318   TGetRenderWindowInteractorEvent( bool toCreate )
319     : myResult( Py_None ), myCreate( toCreate ) {}
320   virtual void Execute()
321   {
322     PyTypeObject* aPyClass = ::GetPyClass( "vtkRenderWindowInteractor" );
323     SVTK_ViewWindow* aVTKViewWindow = 
324       ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate );
325     if( aVTKViewWindow && aPyClass ) {
326       vtkRenderWindowInteractor* aVTKObject = aVTKViewWindow->getInteractor();
327 #if VTK_XVERSION < 50700
328       myResult = PyVTKObject_New( aPyClass, aVTKObject );
329 #else
330       myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
331 #endif
332     }
333   }
334 };
335
336 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderWindowInteractor( PyObject* self, PyObject* args )
337 {
338   PyObject* aResult = Py_None;
339   int toCreate = 0;
340   if ( !PyArg_ParseTuple( args, "|i:getRenderWindowInteractor", &toCreate ) )
341     PyErr_Print();
342   else
343     aResult = ProcessEvent( new TGetRenderWindowInteractorEvent( toCreate ) );
344   return aResult;
345 }
346
347 /*!
348   \fn PyObject* showTrihedron( int show );
349   \brief Show/hide trihedron in the current VTK viewer.
350
351   If there is no active VTK viewer, nothing happens.
352   
353   \param show new trihedron visibility state
354   \return nothing (Py_None)
355 */
356
357 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_showTrihedron( PyObject* self, PyObject* args )
358 {
359   class TEvent: public SALOME_Event
360   {
361   public:
362     int myShow;
363     TEvent( int bShow )
364       : myShow( bShow ) {}
365     virtual void Execute()
366     {
367       if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
368         if ( aVTKViewWindow->isTrihedronDisplayed() != myShow )
369           aVTKViewWindow->onViewTrihedron(myShow);
370       }
371     }
372   };
373   
374   PyObject* aResult = Py_None;
375   int bShow = 0;
376   if ( !PyArg_ParseTuple( args, "i:showTrihedron", &bShow ) )
377     PyErr_Print();
378   else
379     ProcessVoidEvent( new TEvent( bShow ) );
380   return aResult;
381 }
382
383 /*!
384   \fn PyObject* fitAll();
385   \brief Fit all the contents in the current VTK viewer.
386
387   If there is no active VTK viewer, nothing happens.
388
389   \return nothing (Py_None)
390 */
391
392 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_fitAll( PyObject* self, PyObject* args )
393 {
394   class TEvent: public SALOME_Event
395   {
396   public:
397     TEvent() {}
398     virtual void Execute()
399     {
400       if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
401         aVTKViewWindow->onFitAll();
402       }
403     }
404   };
405   
406   ProcessVoidEvent( new TEvent() );
407   return Py_None;
408 }
409
410 /*!
411   \fn PyObject* setView( int type );
412   \brief Set view type for the current VTK viewer.
413
414   If there is no active VTK viewer, nothing happens.
415   
416   \param type view type
417   \return nothing (Py_None)
418 */
419
420 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_setView( PyObject* self, PyObject* args )
421 {
422   class TEvent: public SALOME_Event
423   {
424   public:
425     long myType;
426     TEvent( long type ) : myType( type) {}
427     virtual void Execute()
428     {
429       if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
430         switch( myType ) {
431         case ViewFront:
432           aVTKViewWindow->onFrontView();  break;
433         case ViewBack:
434           aVTKViewWindow->onBackView();   break;
435         case ViewTop:
436           aVTKViewWindow->onTopView();    break;
437         case ViewBottom:
438           aVTKViewWindow->onBottomView(); break;
439         case ViewRight:
440           aVTKViewWindow->onRightView();  break;
441         case ViewLeft:
442           aVTKViewWindow->onLeftView();   break;
443         default:
444           PyErr_Format(PyExc_ValueError,"setView: wrong parameter value; must be between %d and %d", ViewFront, ViewLeft );
445           break;
446         }
447       }
448     }
449   };
450   
451   long type = -1;
452   if ( !PyArg_ParseTuple( args, "l:setView", &type ) )
453     PyErr_Print();
454   else {
455     ProcessVoidEvent( new TEvent( type ) );
456     if( PyErr_Occurred() )
457       PyErr_Print();
458   }
459   return Py_None;
460 }
461
462 /*!
463   \fn PyObject* resetView();
464   \brief Reset contents of the current VTK viewer.
465
466   If there is no active VTK viewer, nothing happens.
467   
468   \return nothing (Py_None)
469 */
470
471 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_resetView( PyObject* self, PyObject* args )
472 {
473   class TEvent: public SALOME_Event
474   {
475   public:
476     TEvent() {}
477     virtual void Execute()
478     {
479       if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
480         aVTKViewWindow->onResetView();
481       }
482     }
483   };
484   
485   ProcessVoidEvent( new TEvent() );
486   return Py_None;
487 }
488
489 static PyMethodDef libSalomePy_methods[] = 
490 {
491   { "getRenderer",               libSalomePy_getRenderer,               METH_VARARGS },
492   { "getRenderWindow",           libSalomePy_getRenderWindow,           METH_VARARGS },
493   { "getRenderWindowInteractor", libSalomePy_getRenderWindowInteractor, METH_VARARGS },
494   { "showTrihedron",             libSalomePy_showTrihedron,             METH_VARARGS },
495   { "fitAll",                    libSalomePy_fitAll,                    METH_NOARGS  },
496   { "setView",                   libSalomePy_setView,                   METH_VARARGS },
497   { "resetView",                 libSalomePy_resetView,                 METH_NOARGS  },
498   { NULL, NULL }
499 };
500
501 struct module_state {
502     PyObject *error;
503 };
504
505 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
506
507 static int libSalomePy_traverse(PyObject *m, visitproc visit, void *arg) {
508     Py_VISIT(GETSTATE(m)->error);
509     return 0;
510 }
511
512 static int libSalomePy_clear(PyObject *m) {
513     Py_CLEAR(GETSTATE(m)->error);
514     return 0;
515 }
516
517 static struct PyModuleDef moduledef = {
518         PyModuleDef_HEAD_INIT,
519         "libSalomePy",
520         NULL,
521         sizeof(struct module_state),
522         libSalomePy_methods,
523         NULL,
524         libSalomePy_traverse,
525         libSalomePy_clear,
526         NULL
527 };
528
529 /*!
530   \brief Python module initialization.
531   \internal
532 */
533 extern "C" SALOMEPY_EXPORT PyMODINIT_FUNC PyInit_libSalomePy(void)
534 {
535   // init module
536   PyObject *aModule = PyModule_Create(&moduledef);
537   if( PyErr_Occurred() ) {
538     PyErr_Print();
539     return NULL;
540   }
541
542   // get module's dictionary
543   PyObject *aModuleDict = PyModule_GetDict( aModule );
544   if ( aModuleDict == NULL )
545     return NULL;
546
547   // export View type enumeration
548   PUBLISH_ENUM( ViewFront );
549   PUBLISH_ENUM( ViewBack );
550   PUBLISH_ENUM( ViewTop );
551   PUBLISH_ENUM( ViewBottom );
552   PUBLISH_ENUM( ViewRight );
553   PUBLISH_ENUM( ViewLeft );
554
555   return aModule;
556 }