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