]> SALOME platform Git repositories - modules/gui.git/blob - src/SALOME_PY/SalomePy.cxx
Salome HOME
Copyright update 2020
[modules/gui.git] / src / SALOME_PY / SalomePy.cxx
1 // Copyright (C) 2007-2020  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, int toKeepDetached = 0 ) {
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           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());
176           if ( aVM ) {
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] );
182           }
183         }
184       }
185     }
186   }
187   return aVW;
188 }
189
190 /*!
191   \fn PyObject* getRenderer( int toCreate = 0 );
192   \brief Get VTK renderer (vtkRenderer).
193   
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
196   is opened.
197
198   If \a toCreate parameter is non-zero, the function always creates
199   new VTK window.
200
201   If VTK window could not be found and or created, the None Python object
202   is returned.
203
204   \param toCreate window creation mode
205   \return VTK window renderer object
206 */
207
208 class SALOMEPY_EXPORT TGetRendererEvent: public SALOME_Event
209 {
210 public:
211   typedef PyObject* TResult;
212   TResult myResult;
213   int     myCreate;
214   int     myKeepDetached;
215   TGetRendererEvent( bool toCreate, bool toKeepDetached )
216     : myResult( Py_None ), myCreate( toCreate ), myKeepDetached( toKeepDetached ) {}
217   virtual void Execute()
218   {
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 );
226 #else
227       myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
228 #endif
229     }
230   }
231 };
232
233 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderer( PyObject* self, PyObject* args )
234 {
235   PyObject* aResult = Py_None;
236   int toCreate = 0;
237   int toKeepDetached = 0;
238   if ( !PyArg_ParseTuple( args, "|ii:getRenderer", &toCreate, &toKeepDetached ) )
239     PyErr_Print();
240   else
241     aResult = ProcessEvent( new TGetRendererEvent( toCreate, toKeepDetached ) );
242   return aResult;
243 }
244
245 /*!
246   \fn PyObject* getRenderWindow( int toCreate = 0 );
247   \brief Get VTK render window (vtkRenderWindow).
248   
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
251   is opened.
252
253   If \a toCreate parameter is non-zero, the function always creates
254   new VTK window.
255
256   If VTK window could not be found and or created, the None Python object
257   is returned.
258
259   \param toCreate window creation mode
260   \return VTK window render window object
261 */
262
263 class SALOMEPY_EXPORT TGetRenderWindowEvent: public SALOME_Event
264 {
265 public:
266   typedef PyObject* TResult;
267   TResult myResult;
268   int     myCreate;
269   int     myKeepDetached;
270   TGetRenderWindowEvent( bool toCreate, bool toKeepDetached )
271     : myResult( Py_None ), myCreate( toCreate ), myKeepDetached( toKeepDetached ) {}
272   virtual void Execute()
273   {
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 );
281 #else
282       myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
283 #endif
284     }
285   }
286 };
287
288 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderWindow( PyObject* self, PyObject* args )
289 {
290   PyObject* aResult = Py_None;
291   int toCreate = 0;
292   int toKeepDetached = 0;
293   if ( !PyArg_ParseTuple( args, "|ii:getRenderWindow", &toCreate, &toKeepDetached ) )
294     PyErr_Print();
295   else
296     aResult = ProcessEvent( new TGetRenderWindowEvent( toCreate, toKeepDetached ) );
297   return aResult;
298 }
299
300 /*!
301   \fn PyObject* getRenderWindowInteractor( int toCreate = 0 );
302   \brief Get VTK render window interactor (getRenderWindowInteractor).
303   
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
306   is opened.
307
308   If \a toCreate parameter is non-zero, the function always creates
309   new VTK window.
310
311   If VTK window could not be found and or created, the None Python object
312   is returned.
313
314   \param toCreate window creation mode
315   \return VTK window render window interactor object
316 */
317
318 class SALOMEPY_EXPORT TGetRenderWindowInteractorEvent: public SALOME_Event
319 {
320 public:
321   typedef PyObject* TResult;
322   TResult myResult;
323   int     myCreate;
324   int     myKeepDetached;
325   TGetRenderWindowInteractorEvent( bool toCreate, bool toKeepDetached )
326     : myResult( Py_None ), myCreate( toCreate ), myKeepDetached( toKeepDetached ) {}
327   virtual void Execute()
328   {
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 );
336 #else
337       myResult = PyVTKObject_FromPointer( aPyClass, NULL, aVTKObject );
338 #endif
339     }
340   }
341 };
342
343 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderWindowInteractor( PyObject* self, PyObject* args )
344 {
345   PyObject* aResult = Py_None;
346   int toCreate = 0;
347   int toKeepDetached = 0;
348   if ( !PyArg_ParseTuple( args, "|ii:getRenderWindowInteractor", &toCreate, &toKeepDetached ) )
349     PyErr_Print();
350   else
351     aResult = ProcessEvent( new TGetRenderWindowInteractorEvent( toCreate, toKeepDetached ) );
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 libSalomePy_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 struct module_state {
510     PyObject *error;
511 };
512
513 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
514
515 static int libSalomePy_traverse(PyObject *m, visitproc visit, void *arg) {
516     Py_VISIT(GETSTATE(m)->error);
517     return 0;
518 }
519
520 static int libSalomePy_clear(PyObject *m) {
521     Py_CLEAR(GETSTATE(m)->error);
522     return 0;
523 }
524
525 static struct PyModuleDef moduledef = {
526         PyModuleDef_HEAD_INIT,
527         "libSalomePy",
528         NULL,
529         sizeof(struct module_state),
530         libSalomePy_methods,
531         NULL,
532         libSalomePy_traverse,
533         libSalomePy_clear,
534         NULL
535 };
536
537 /*!
538   \brief Python module initialization.
539   \internal
540 */
541 extern "C" SALOMEPY_EXPORT PyMODINIT_FUNC PyInit_libSalomePy(void)
542 {
543   // init module
544   PyObject *aModule = PyModule_Create(&moduledef);
545   if( PyErr_Occurred() ) {
546     PyErr_Print();
547     return NULL;
548   }
549
550   // get module's dictionary
551   PyObject *aModuleDict = PyModule_GetDict( aModule );
552   if ( aModuleDict == NULL )
553     return NULL;
554
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 );
562
563   return aModule;
564 }