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