Salome HOME
Merge branch 'rnv/23406'
[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 = PyInt_FromLong( i ) ) == NULL ) return; \
95   rc = PyDict_SetItemString( aModuleDict, #i, w );   \
96   Py_DECREF( w );                                    \
97   if ( rc < 0 ) return;                              \
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 #if VTK_XVERSION < 30000
122     aVTKModule = PyImport_ImportModule( "libVTKGraphicsPython" ); 
123 #elif VTK_XVERSION < 50700
124     aVTKModule = PyImport_ImportModule( "vtk.libvtkRenderingPython" ); 
125 #elif VTK_XVERSION < 60000
126     aVTKModule = PyImport_ImportModule( "vtkRenderingPython" ); 
127 #else
128     aVTKModule = PyImport_ImportModule( "vtkRenderingCorePython" ); 
129 #endif
130     if( PyErr_Occurred() ) {
131       PyErr_Print();
132     }
133   }
134   if ( aVTKModule ) {
135     PyObject* aVTKDict = PyModule_GetDict( aVTKModule );
136     aPyClass = PyDict_GetItemString(aVTKDict, const_cast<char*>( theClassName ) );
137     if (!PyType_Check(aPyClass))
138       return 0;
139   }
140   return (PyTypeObject *)aPyClass;
141 }
142
143 /*!
144   \brief VTK window find/create mode
145   \internal
146 */
147 enum { 
148   __Find,          // try to find VTK window; if not found, do nothing
149   __FindOrCreate,  // try to find VTK window; if not found, create new one
150   __Create };      // create new VTK window
151
152 /*!
153   \brief Find or create VTK window.
154   \internal
155   \param toCreate window find/create mode
156   \return VTK window pointer or 0 if it could not be found/created
157 */
158 static SVTK_ViewWindow* GetVTKViewWindow( int toCreate = __FindOrCreate ) {
159   SVTK_ViewWindow* aVW = 0;
160   if ( SUIT_Session::session() ) {
161     // get application
162     LightApp_Application* anApp = dynamic_cast<LightApp_Application*>( SUIT_Session::session()->activeApplication() );
163     if ( anApp ) {
164       // get active study
165       LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>( anApp->activeStudy() );
166       if ( aStudy ) {
167         // find or create VTK view manager
168         if ( toCreate == __Create ) {
169           SVTK_ViewManager* aVM = dynamic_cast<SVTK_ViewManager*>( anApp->createViewManager( "VTKViewer" ) );
170           if ( aVM ) {
171             aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getActiveView() );
172             if ( !aVW )
173               aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->createViewWindow() );
174             // VSR : When new view window is created it can be not active yet at this moment,
175             // so the following is a some workaround
176             if ( !aVW && !aVM->getViews().isEmpty() )
177               aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getViews()[0] );
178           }
179         }
180         else {
181           SVTK_ViewManager* aVM = dynamic_cast<SVTK_ViewManager*>( anApp->getViewManager( "VTKViewer", toCreate == __FindOrCreate ) );
182           if ( aVM ) {
183             aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getActiveView() );
184             // VSR : When new view window is created it can be not active yet at this moment,
185             // so the following is a some workaround
186             if ( !aVW && !aVM->getViews().isEmpty() )
187               aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getViews()[0] );
188           }
189         }
190       }
191     }
192   }
193   return aVW;
194 }
195
196 /*!
197   \fn PyObject* getRenderer( int toCreate = 0 );
198   \brief Get VTK renderer (vtkRenderer).
199   
200   If \a toCreate parameter is 0 (by default) the function tries to find
201   and reuse existing VTK window; if it is not found, the new VTK window
202   is opened.
203
204   If \a toCreate parameter is non-zero, the function always creates
205   new VTK window.
206
207   If VTK window could not be found and or created, the None Python object
208   is returned.
209
210   \param toCreate window creation mode
211   \return VTK window renderer object
212 */
213
214 class SALOMEPY_EXPORT TGetRendererEvent: public SALOME_Event
215 {
216 public:
217   typedef PyObject* TResult;
218   TResult myResult;
219   int     myCreate;
220   TGetRendererEvent( bool toCreate )
221     : myResult( Py_None ), myCreate( toCreate ) {}
222   virtual void Execute()
223   {
224     PyTypeObject* aPyClass = ::GetPyClass( "vtkRenderer" );
225     SVTK_ViewWindow* aVTKViewWindow = 
226       ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate );
227     if( aVTKViewWindow && aPyClass ) {
228       vtkRenderer* aVTKObject = aVTKViewWindow->getRenderer();
229 #if VTK_XVERSION < 50700
230       myResult = PyVTKObject_New( aPyClass, aVTKObject );
231 #else
232       myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
233 #endif
234     }
235   }
236 };
237
238 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderer( PyObject* self, PyObject* args )
239 {
240   PyObject* aResult = Py_None;
241   int toCreate = 0;
242   if ( !PyArg_ParseTuple( args, "|i:getRenderer", &toCreate ) )
243     PyErr_Print();
244   else
245     aResult = ProcessEvent( new TGetRendererEvent( toCreate ) );
246   return aResult;
247 }
248
249 /*!
250   \fn PyObject* getRenderWindow( int toCreate = 0 );
251   \brief Get VTK render window (vtkRenderWindow).
252   
253   If \a toCreate parameter is 0 (by default) the function tries to find 
254   and reuse existing VTK window; if it is not found, the new VTK window
255   is opened.
256
257   If \a toCreate parameter is non-zero, the function always creates
258   new VTK window.
259
260   If VTK window could not be found and or created, the None Python object
261   is returned.
262
263   \param toCreate window creation mode
264   \return VTK window render window object
265 */
266
267 class SALOMEPY_EXPORT TGetRenderWindowEvent: public SALOME_Event
268 {
269 public:
270   typedef PyObject* TResult;
271   TResult myResult;
272   int     myCreate;
273   TGetRenderWindowEvent( bool toCreate )
274     : myResult( Py_None ), myCreate( toCreate ) {}
275   virtual void Execute()
276   {
277     PyTypeObject* aPyClass = ::GetPyClass( "vtkRenderWindow" );
278     SVTK_ViewWindow* aVTKViewWindow = 
279       ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate );
280     if( aVTKViewWindow && aPyClass ) {
281       vtkRenderWindow* aVTKObject = aVTKViewWindow->getRenderWindow();
282 #if VTK_XVERSION < 50700
283       myResult = PyVTKObject_New( aPyClass, aVTKObject );
284 #else
285       myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
286 #endif
287     }
288   }
289 };
290
291 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderWindow( PyObject* self, PyObject* args )
292 {
293   PyObject* aResult = Py_None;
294   int toCreate = 0;
295   if ( !PyArg_ParseTuple( args, "|i:getRenderWindow", &toCreate ) )
296     PyErr_Print();
297   else
298     aResult = ProcessEvent( new TGetRenderWindowEvent( toCreate ) );
299   return aResult;
300 }
301
302 /*!
303   \fn PyObject* getRenderWindowInteractor( int toCreate = 0 );
304   \brief Get VTK render window interactor (getRenderWindowInteractor).
305   
306   If \a toCreate parameter is 0 (by default) the function tries to find 
307   and reuse existing VTK window; if it is not found, the new VTK window
308   is opened.
309
310   If \a toCreate parameter is non-zero, the function always creates
311   new VTK window.
312
313   If VTK window could not be found and or created, the None Python object
314   is returned.
315
316   \param toCreate window creation mode
317   \return VTK window render window interactor object
318 */
319
320 class SALOMEPY_EXPORT TGetRenderWindowInteractorEvent: public SALOME_Event
321 {
322 public:
323   typedef PyObject* TResult;
324   TResult myResult;
325   int     myCreate;
326   TGetRenderWindowInteractorEvent( bool toCreate )
327     : myResult( Py_None ), myCreate( toCreate ) {}
328   virtual void Execute()
329   {
330     PyTypeObject* aPyClass = ::GetPyClass( "vtkRenderWindowInteractor" );
331     SVTK_ViewWindow* aVTKViewWindow = 
332       ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate );
333     if( aVTKViewWindow && aPyClass ) {
334       vtkRenderWindowInteractor* aVTKObject = aVTKViewWindow->getInteractor();
335 #if VTK_XVERSION < 50700
336       myResult = PyVTKObject_New( aPyClass, aVTKObject );
337 #else
338       myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
339 #endif
340     }
341   }
342 };
343
344 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderWindowInteractor( PyObject* self, PyObject* args )
345 {
346   PyObject* aResult = Py_None;
347   int toCreate = 0;
348   if ( !PyArg_ParseTuple( args, "|i:getRenderWindowInteractor", &toCreate ) )
349     PyErr_Print();
350   else
351     aResult = ProcessEvent( new TGetRenderWindowInteractorEvent( toCreate ) );
352   return aResult;
353 }
354
355 /*!
356   \fn PyObject* showTrihedron( int show );
357   \brief Show/hide trihedron in the current VTK viewer.
358
359   If there is no active VTK viewer, nothing happens.
360   
361   \param show new trihedron visibility state
362   \return nothing (Py_None)
363 */
364
365 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_showTrihedron( PyObject* self, PyObject* args )
366 {
367   class TEvent: public SALOME_Event
368   {
369   public:
370     int myShow;
371     TEvent( int bShow )
372       : myShow( bShow ) {}
373     virtual void Execute()
374     {
375       if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
376         if ( aVTKViewWindow->isTrihedronDisplayed() != myShow )
377           aVTKViewWindow->onViewTrihedron(myShow);
378       }
379     }
380   };
381   
382   PyObject* aResult = Py_None;
383   int bShow = 0;
384   if ( !PyArg_ParseTuple( args, "i:showTrihedron", &bShow ) )
385     PyErr_Print();
386   else
387     ProcessVoidEvent( new TEvent( bShow ) );
388   return aResult;
389 }
390
391 /*!
392   \fn PyObject* fitAll();
393   \brief Fit all the contents in the current VTK viewer.
394
395   If there is no active VTK viewer, nothing happens.
396
397   \return nothing (Py_None)
398 */
399
400 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_fitAll( PyObject* self, PyObject* args )
401 {
402   class TEvent: public SALOME_Event
403   {
404   public:
405     TEvent() {}
406     virtual void Execute()
407     {
408       if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
409         aVTKViewWindow->onFitAll();
410       }
411     }
412   };
413   
414   ProcessVoidEvent( new TEvent() );
415   return Py_None;
416 }
417
418 /*!
419   \fn PyObject* setView( int type );
420   \brief Set view type for the current VTK viewer.
421
422   If there is no active VTK viewer, nothing happens.
423   
424   \param type view type
425   \return nothing (Py_None)
426 */
427
428 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_setView( PyObject* self, PyObject* args )
429 {
430   class TEvent: public SALOME_Event
431   {
432   public:
433     long myType;
434     TEvent( long type ) : myType( type) {}
435     virtual void Execute()
436     {
437       if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
438         switch( myType ) {
439         case ViewFront:
440           aVTKViewWindow->onFrontView();  break;
441         case ViewBack:
442           aVTKViewWindow->onBackView();   break;
443         case ViewTop:
444           aVTKViewWindow->onTopView();    break;
445         case ViewBottom:
446           aVTKViewWindow->onBottomView(); break;
447         case ViewRight:
448           aVTKViewWindow->onRightView();  break;
449         case ViewLeft:
450           aVTKViewWindow->onLeftView();   break;
451         default:
452           PyErr_Format(PyExc_ValueError,"setView: wrong parameter value; must be between %d and %d", ViewFront, ViewLeft );
453           break;
454         }
455       }
456     }
457   };
458   
459   long type = -1;
460   if ( !PyArg_ParseTuple( args, "l:setView", &type ) )
461     PyErr_Print();
462   else {
463     ProcessVoidEvent( new TEvent( type ) );
464     if( PyErr_Occurred() )
465       PyErr_Print();
466   }
467   return Py_None;
468 }
469
470 /*!
471   \fn PyObject* resetView();
472   \brief Reset contents of the current VTK viewer.
473
474   If there is no active VTK viewer, nothing happens.
475   
476   \return nothing (Py_None)
477 */
478
479 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_resetView( PyObject* self, PyObject* args )
480 {
481   class TEvent: public SALOME_Event
482   {
483   public:
484     TEvent() {}
485     virtual void Execute()
486     {
487       if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
488         aVTKViewWindow->onResetView();
489       }
490     }
491   };
492   
493   ProcessVoidEvent( new TEvent() );
494   return Py_None;
495 }
496
497 static PyMethodDef Module_Methods[] = 
498 {
499   { "getRenderer",               libSalomePy_getRenderer,               METH_VARARGS },
500   { "getRenderWindow",           libSalomePy_getRenderWindow,           METH_VARARGS },
501   { "getRenderWindowInteractor", libSalomePy_getRenderWindowInteractor, METH_VARARGS },
502   { "showTrihedron",             libSalomePy_showTrihedron,             METH_VARARGS },
503   { "fitAll",                    libSalomePy_fitAll,                    METH_NOARGS  },
504   { "setView",                   libSalomePy_setView,                   METH_VARARGS },
505   { "resetView",                 libSalomePy_resetView,                 METH_NOARGS  },
506   { NULL, NULL }
507 };
508
509 /*!
510   \brief Python module initialization.
511   \internal
512 */
513 extern "C" SALOMEPY_EXPORT void initlibSalomePy()
514 {
515   static char* modulename = (char*)"libSalomePy";
516
517   // init module
518   PyObject* aModule = Py_InitModule( modulename, Module_Methods );
519   if( PyErr_Occurred() ) {
520     PyErr_Print();
521     return;
522   }
523
524   // get module's dictionary
525   PyObject *aModuleDict = PyModule_GetDict( aModule );
526   if ( aModuleDict == NULL )
527     return;
528
529   // export View type enumeration
530   PUBLISH_ENUM( ViewFront );
531   PUBLISH_ENUM( ViewBack );
532   PUBLISH_ENUM( ViewTop );
533   PUBLISH_ENUM( ViewBottom );
534   PUBLISH_ENUM( ViewRight );
535   PUBLISH_ENUM( ViewLeft );
536 }