]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/vtk.py
Patch from Will Sadkin:
[wxWidgets.git] / wxPython / wx / lib / vtk.py
1 """
2 VTK is now including a package for using VTK with wxPython, so this
3 module is now officially nothing but ancient history. If for some
4 strange reason you really need this code (I don't know why, it didn't
5 work all that well anyway,) then just remove the triple quotes below.
6 I'm told that the module from Kitware is excellent and so you should
7 really use it. See the URL below to get a copy from CVS.
8
9 http://public.kitware.com/cgi-bin/cvsweb.cgi/VTK/Wrapping/Python/vtk/wx/
10 """
11
12 print __doc__
13
14 '''
15 #----------------------------------------------------------------------
16 # Name: wxPython.lib.vtk
17 # Purpose: Provides a wrapper around the vtkRenderWindow from the
18 # VTK Visualization Toolkit. Requires the VTK Python
19 # extensions from http://www.kitware.com/
20 #
21 # Author: Robin Dunn
22 #
23 # Created: 16-Nov-1999
24 # RCS-ID: $Id$
25 # Copyright: (c) 1999 by Total Control Software
26 # Licence: wxWindows license
27 #----------------------------------------------------------------------
28
29 # This class has been rewritten and improved by Prabhu Ramachandran
30 # <prabhu@aero.iitm.ernet.in>. It has been tested under Win32 and
31 # Linux. Many thanks to Eric Boix <frog@creatis.insa-lyon.fr> for
32 # testing it under Windows and finding and fixing many errors.
33 # Thanks also to Sebastien BARRE <sebastien@barre.nom.fr> for his
34 # suggestions.
35
36
37 try:
38 from vtkpython import *
39 except ImportError:
40 raise ImportError, "VTK extension module not found"
41
42 from wxPython.wx import *
43 import math
44
45 #----------------------------------------------------------------------
46
47 DEBUG = 0
48
49 def debug(msg):
50 if DEBUG:
51 print msg
52
53
54 class wxVTKRenderWindowBase(wxWindow):
55 """
56 A base class that enables one to embed a vtkRenderWindow into
57 a wxPython widget. This class embeds the RenderWindow correctly
58 under different platforms. Provided are some empty methods that
59 can be overloaded to provide a user defined interaction behaviour.
60 The event handling functions have names that are similar to the
61 ones in the vtkInteractorStyle class included with VTK.
62 """
63
64 def __init__(self, parent, id, position=wxDefaultPosition,
65 size=wxDefaultSize, style=0):
66 wxWindow.__init__(self, parent, id, position, size, style | wxWANTS_CHARS)
67 self._RenderWindow = vtkRenderWindow()
68
69 self.__InExpose = 0
70 self.__Created = 0
71
72 if wxPlatform != '__WXMSW__':
73 # We can't get the handle in wxGTK until after the widget
74 # is created, the window create event happens later so we'll
75 # catch it there
76 EVT_WINDOW_CREATE(self, self.OnCreateWindow)
77 EVT_PAINT (self, self.OnExpose)
78 else:
79 # but in MSW, the window create event happens durring the above
80 # call to __init__ so we have to do it here.
81 hdl = self.GetHandle()
82 self._RenderWindow.SetWindowInfo(str(hdl))
83 EVT_PAINT (self, self.OnExpose)
84 self.__Created = 1
85
86 # common for all platforms
87 EVT_SIZE (self, self.OnConfigure)
88
89 # setup the user defined events.
90 self.SetupEvents()
91
92
93 def SetupEvents(self):
94 "Setup the user defined event bindings."
95 # Remember to bind everything to self.box and NOT self
96 EVT_LEFT_DOWN (self, self.OnLeftButtonDown)
97 EVT_MIDDLE_DOWN (self, self.OnMiddleButtonDown)
98 EVT_RIGHT_DOWN (self, self.OnRightButtonDown)
99 EVT_LEFT_UP (self, self.OnLeftButtonUp)
100 EVT_MIDDLE_UP (self, self.OnMiddleButtonUp)
101 EVT_RIGHT_UP (self, self.OnRightButtonUp)
102 EVT_MOTION (self, self.OnMouseMove)
103 EVT_ENTER_WINDOW (self, self.OnEnter)
104 EVT_LEAVE_WINDOW (self, self.OnLeave)
105 EVT_CHAR (self, self.OnChar)
106 # Add your bindings if you want them in the derived class.
107
108
109 def GetRenderer(self):
110 self._RenderWindow.GetRenderers().InitTraversal()
111 return self._RenderWindow.GetRenderers().GetNextItem()
112
113
114 def GetRenderWindow(self):
115 return self._RenderWindow
116
117
118 def Render(self):
119 if self.__Created:
120 # if block needed because calls to render before creation
121 # will prevent the renderwindow from being embedded into a
122 # wxPython widget.
123 self._RenderWindow.Render()
124
125
126 def OnExpose(self, event):
127 # I need this for the MDIDemo. Somehow OnCreateWindow was
128 # not getting called.
129 if not self.__Created:
130 self.OnCreateWindow(event)
131 if (not self.__InExpose):
132 self.__InExpose = 1
133 dc = wxPaintDC(self)
134 self._RenderWindow.Render()
135 self.__InExpose = 0
136
137
138 def OnCreateWindow(self, event):
139 hdl = self.GetHandle()
140 try:
141 self._RenderWindow.SetParentInfo(str(hdl))
142 except:
143 self._RenderWindow.SetWindowInfo(str(hdl))
144 msg = "Warning:\n "\
145 "Unable to call vtkRenderWindow.SetParentInfo\n\n"\
146 "Using the SetWindowInfo method instead. This\n"\
147 "is likely to cause a lot of flicker when\n"\
148 "rendering in the vtkRenderWindow. Please\n"\
149 "use a recent Nightly VTK release (later than\n"\
150 "March 10 2001) to eliminate this problem."
151 dlg = wxMessageDialog(NULL, msg, "Warning!",
152 wxOK |wxICON_INFORMATION)
153 dlg.ShowModal()
154 dlg.Destroy()
155 self.__Created = 1
156
157
158 def OnConfigure(self, event):
159 sz = self.GetSize()
160 self.SetSize(sz)
161 # Ugly hack that according to Eric Boix is necessary under
162 # Windows. If possible Try commenting this out and test under
163 # Windows.
164 #self._RenderWindow.GetSize()
165 #
166 self._RenderWindow.SetSize(sz.width, sz.height)
167
168
169 def OnLeftButtonDown(self, event):
170 "Left mouse button pressed."
171 pass
172
173
174 def OnMiddleButtonDown(self, event):
175 "Middle mouse button pressed."
176 pass
177
178
179 def OnRightButtonDown(self, event):
180 "Right mouse button pressed."
181 pass
182
183
184 def OnLeftButtonUp(self, event):
185 "Left mouse button released."
186 pass
187
188
189 def OnMiddleButtonUp(self, event):
190 "Middle mouse button released."
191 pass
192
193
194 def OnRightButtonUp(self, event):
195 "Right mouse button released."
196 pass
197
198
199 def OnMouseMove(self, event):
200 "Mouse has moved."
201 pass
202
203
204 def OnEnter(self, event):
205 "Entering the vtkRenderWindow."
206 pass
207
208
209 def OnLeave(self, event):
210 "Leaving the vtkRenderWindow."
211 pass
212
213
214 def OnChar(self, event):
215 "Process Key events."
216 pass
217
218
219 def OnKeyDown(self, event):
220 "Key pressed down."
221 pass
222
223
224 def OnKeyUp(self, event):
225 "Key released."
226 pass
227
228
229
230
231 class wxVTKRenderWindow(wxVTKRenderWindowBase):
232 """
233 An example of a fully functional wxVTKRenderWindow that is
234 based on the vtkRenderWidget.py provided with the VTK sources.
235 """
236
237 def __init__(self, parent, id, position=wxDefaultPosition,
238 size=wxDefaultSize, style=0):
239 wxVTKRenderWindowBase.__init__(self, parent, id, position, size,
240 style)
241
242 self._CurrentRenderer = None
243 self._CurrentCamera = None
244 self._CurrentZoom = 1.0
245 self._CurrentLight = None
246
247 self._ViewportCenterX = 0
248 self._ViewportCenterY = 0
249
250 self._Picker = vtkCellPicker()
251 self._PickedAssembly = None
252 self._PickedProperty = vtkProperty()
253 self._PickedProperty.SetColor(1,0,0)
254 self._PrePickedProperty = None
255
256 self._OldFocus = None
257
258 # these record the previous mouse position
259 self._LastX = 0
260 self._LastY = 0
261
262
263 def OnLeftButtonDown(self, event):
264 "Left mouse button pressed."
265 self.StartMotion(event)
266
267
268 def OnMiddleButtonDown(self, event):
269 "Middle mouse button pressed."
270 self.StartMotion(event)
271
272
273 def OnRightButtonDown(self, event):
274 "Right mouse button pressed."
275 self.StartMotion(event)
276
277
278 def OnLeftButtonUp(self, event):
279 "Left mouse button released."
280 self.EndMotion(event)
281
282
283 def OnMiddleButtonUp(self, event):
284 "Middle mouse button released."
285 self.EndMotion(event)
286
287
288 def OnRightButtonUp(self, event):
289 "Right mouse button released."
290 self.EndMotion(event)
291
292
293 def OnMouseMove(self, event):
294 event.x, event.y = event.GetPositionTuple()
295 if event.LeftIsDown():
296 if event.ShiftDown():
297 self.Pan(event.x, event.y)
298 else:
299 self.Rotate(event.x, event.y)
300
301 elif event.MiddleIsDown():
302 self.Pan(event.x, event.y)
303
304 elif event.RightIsDown():
305 self.Zoom(event.x, event.y)
306
307
308 def OnEnter(self, event):
309 self.__OldFocus = wxWindow_FindFocus()
310 self.SetFocus()
311 x, y = event.GetPositionTuple()
312 self.UpdateRenderer(x,y)
313
314
315 def OnLeave(self, event):
316 if (self._OldFocus != None):
317 self.__OldFocus.SetFocus()
318
319
320 def OnChar(self, event):
321 key = event.KeyCode()
322 if (key == ord('r')) or (key == ord('R')):
323 self.Reset()
324 elif (key == ord('w')) or (key == ord('W')):
325 self.Wireframe()
326 elif (key == ord('s')) or (key == ord('S')):
327 self.Surface()
328 elif (key == ord('p')) or (key == ord('P')):
329 x, y = event.GetPositionTuple()
330 self.PickActor(x, y)
331 else:
332 event.Skip()
333
334
335 # Start of internal functions
336 def GetZoomFactor(self):
337 return self._CurrentZoom
338
339
340 def SetZoomFactor(self, zf):
341 self._CurrentZoom = zf
342
343
344 def GetPicker(self):
345 return self._Picker
346
347
348 def Render(self):
349 if (self._CurrentLight):
350 light = self._CurrentLight
351 light.SetPosition(self._CurrentCamera.GetPosition())
352 light.SetFocalPoint(self._CurrentCamera.GetFocalPoint())
353
354 wxVTKRenderWindowBase.Render(self)
355
356
357 def UpdateRenderer(self, x, y):
358 """
359 UpdateRenderer will identify the renderer under the mouse and set
360 up _CurrentRenderer, _CurrentCamera, and _CurrentLight.
361 """
362 sz = self.GetSize()
363 windowX = sz.width
364 windowY = sz.height
365
366 renderers = self._RenderWindow.GetRenderers()
367 numRenderers = renderers.GetNumberOfItems()
368
369 self._CurrentRenderer = None
370 renderers.InitTraversal()
371 for i in range(0,numRenderers):
372 renderer = renderers.GetNextItem()
373 vx,vy = (0,0)
374 if (windowX > 1):
375 vx = float (x)/(windowX-1)
376 if (windowY > 1):
377 vy = (windowY-float(y)-1)/(windowY-1)
378 (vpxmin,vpymin,vpxmax,vpymax) = renderer.GetViewport()
379
380 if (vx >= vpxmin and vx <= vpxmax and
381 vy >= vpymin and vy <= vpymax):
382 self._CurrentRenderer = renderer
383 self._ViewportCenterX = float(windowX)*(vpxmax-vpxmin)/2.0\
384 +vpxmin
385 self._ViewportCenterY = float(windowY)*(vpymax-vpymin)/2.0\
386 +vpymin
387 self._CurrentCamera = self._CurrentRenderer.GetActiveCamera()
388 lights = self._CurrentRenderer.GetLights()
389 lights.InitTraversal()
390 self._CurrentLight = lights.GetNextItem()
391 break
392
393 self._LastX = x
394 self._LastY = y
395
396
397 def GetCurrentRenderer(self):
398 return self._CurrentRenderer
399
400
401 def StartMotion(self, event):
402 x, y = event.GetPositionTuple()
403 self.UpdateRenderer(x,y)
404 self.CaptureMouse()
405
406
407 def EndMotion(self, event=None):
408 if self._CurrentRenderer:
409 self.Render()
410 self.ReleaseMouse()
411
412
413 def Rotate(self,x,y):
414 if self._CurrentRenderer:
415
416 self._CurrentCamera.Azimuth(self._LastX - x)
417 self._CurrentCamera.Elevation(y - self._LastY)
418 self._CurrentCamera.OrthogonalizeViewUp()
419
420 self._LastX = x
421 self._LastY = y
422
423 self._CurrentRenderer.ResetCameraClippingRange()
424 self.Render()
425
426
427 def PanAbsolute(self, x_vec, y_vec):
428 if self._CurrentRenderer:
429
430 renderer = self._CurrentRenderer
431 camera = self._CurrentCamera
432 (pPoint0,pPoint1,pPoint2) = camera.GetPosition()
433 (fPoint0,fPoint1,fPoint2) = camera.GetFocalPoint()
434
435 if (camera.GetParallelProjection()):
436 renderer.SetWorldPoint(fPoint0,fPoint1,fPoint2,1.0)
437 renderer.WorldToDisplay()
438 fx,fy,fz = renderer.GetDisplayPoint()
439 renderer.SetDisplayPoint(fx+x_vec,
440 fy+y_vec,
441 fz)
442 renderer.DisplayToWorld()
443 fx,fy,fz,fw = renderer.GetWorldPoint()
444 camera.SetFocalPoint(fx,fy,fz)
445
446 renderer.SetWorldPoint(pPoint0,pPoint1,pPoint2,1.0)
447 renderer.WorldToDisplay()
448 fx,fy,fz = renderer.GetDisplayPoint()
449 renderer.SetDisplayPoint(fx+x_vec,
450 fy+y_vec,
451 fz)
452 renderer.DisplayToWorld()
453 fx,fy,fz,fw = renderer.GetWorldPoint()
454 camera.SetPosition(fx,fy,fz)
455
456 else:
457 (fPoint0,fPoint1,fPoint2) = camera.GetFocalPoint()
458 # Specify a point location in world coordinates
459 renderer.SetWorldPoint(fPoint0,fPoint1,fPoint2,1.0)
460 renderer.WorldToDisplay()
461 # Convert world point coordinates to display coordinates
462 dPoint = renderer.GetDisplayPoint()
463 focalDepth = dPoint[2]
464
465 aPoint0 = self._ViewportCenterX + x_vec
466 aPoint1 = self._ViewportCenterY + y_vec
467
468 renderer.SetDisplayPoint(aPoint0,aPoint1,focalDepth)
469 renderer.DisplayToWorld()
470
471 (rPoint0,rPoint1,rPoint2,rPoint3) = renderer.GetWorldPoint()
472 if (rPoint3 != 0.0):
473 rPoint0 = rPoint0/rPoint3
474 rPoint1 = rPoint1/rPoint3
475 rPoint2 = rPoint2/rPoint3
476
477 camera.SetFocalPoint((fPoint0 - rPoint0) + fPoint0,
478 (fPoint1 - rPoint1) + fPoint1,
479 (fPoint2 - rPoint2) + fPoint2)
480
481 camera.SetPosition((fPoint0 - rPoint0) + pPoint0,
482 (fPoint1 - rPoint1) + pPoint1,
483 (fPoint2 - rPoint2) + pPoint2)
484
485 self.Render()
486
487
488 def Pan(self, x, y):
489 self.PanAbsolute(x - self._LastX, - y + self._LastY)
490 self._LastX = x
491 self._LastY = y
492
493
494 def Zoom(self,x,y):
495 if self._CurrentRenderer:
496
497 renderer = self._CurrentRenderer
498 camera = self._CurrentCamera
499
500 zoomFactor = math.pow(1.02,(0.5*(self._LastY - y)))
501 self._CurrentZoom = self._CurrentZoom * zoomFactor
502
503 if camera.GetParallelProjection():
504 parallelScale = camera.GetParallelScale()/zoomFactor
505 camera.SetParallelScale(parallelScale)
506 else:
507 camera.Dolly(zoomFactor)
508 renderer.ResetCameraClippingRange()
509
510 self._LastX = x
511 self._LastY = y
512
513 self.Render()
514
515
516 def Reset(self):
517 if self._CurrentRenderer:
518 self._CurrentRenderer.ResetCamera()
519
520 self.Render()
521
522
523 def Wireframe(self):
524 actors = self._CurrentRenderer.GetActors()
525 numActors = actors.GetNumberOfItems()
526 actors.InitTraversal()
527 for i in range(0,numActors):
528 actor = actors.GetNextItem()
529 actor.GetProperty().SetRepresentationToWireframe()
530
531 self.Render()
532
533
534 def Surface(self):
535 actors = self._CurrentRenderer.GetActors()
536 numActors = actors.GetNumberOfItems()
537 actors.InitTraversal()
538 for i in range(0,numActors):
539 actor = actors.GetNextItem()
540 actor.GetProperty().SetRepresentationToSurface()
541
542 self.Render()
543
544
545 def PickActor(self,x,y):
546 if self._CurrentRenderer:
547 renderer = self._CurrentRenderer
548 picker = self._Picker
549
550 windowY = self.GetSize().height
551 picker.Pick(x,(windowY - y - 1),0.0,renderer)
552 assembly = picker.GetAssembly()
553
554 if (self._PickedAssembly != None and
555 self._PrePickedProperty != None):
556 self._PickedAssembly.SetProperty(self._PrePickedProperty)
557 # release hold of the property
558 self._PrePickedProperty.UnRegister(self._PrePickedProperty)
559 self._PrePickedProperty = None
560
561 if (assembly != None):
562 self._PickedAssembly = assembly
563 self._PrePickedProperty = self._PickedAssembly.GetProperty()
564 # hold onto the property
565 self._PrePickedProperty.Register(self._PrePickedProperty)
566 self._PickedAssembly.SetProperty(self._PickedProperty)
567
568 self.Render()
569 '''