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