[vtkusers] events freeze X using vtk with wxPython
John Hunter
jdhunter at ace.bsd.uchicago.edu
Sat Nov 17 09:29:43 EST 2001
>>>>> "Prabhu" == Prabhu Ramachandran <prabhu at aero.iitm.ernet.in> writes:
Prabhu> Thats really strange. Could you mail me the
Prabhu> wxPython.lib.vtk code that ships with your CVS version of
Prabhu> wxPython? Let me see if there is something that I've
Prabhu> fixed in my version.
Sure. Thanks for taking a look.
One other detail that I forgot to mention is that after certain
events, like resizing, I get a lot of memory leak warnings from when I
try to exit the application (this happens when the app doesn't
freeze). The warnings look like this:
Generic Warning: In
/home/jdhunter/c/src/VTK/Common/vtkDebugLeaks.cxx, line 330
vtkDebugLeaks has detected LEAKS!
Generic Warning: In
/home/jdhunter/c/src/VTK/Common/vtkDebugLeaks.cxx, line 104 Class
vtkXOpenGLRenderWindow has 1 instances still around
Here is wxPython.lib.vtk I am using:
#----------------------------------------------------------------------
# Name: wxPython.lib.vtk
# Purpose: Provides a wrapper around the vtkRenderWindow from the
# VTK Visualization Toolkit. Requires the VTK Python
# extensions from http://www.kitware.com/
#
# Author: Robin Dunn
#
# Created: 16-Nov-1999
# RCS-ID: $Id: vtk.py,v 1.7 2001/07/06 17:31:06 RD Exp $
# Copyright: (c) 1999 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
# This class has been rewritten and improved by Prabhu Ramachandran
# <prabhu at aero.iitm.ernet.in>. It has been tested under Win32 and
# Linux. Many thanks to Eric Boix <frog at creatis.insa-lyon.fr> for
# testing it under Windows and finding and fixing many errors.
# Thanks also to Sebastien BARRE <sebastien at barre.nom.fr> for his
# suggestions.
try:
from vtkpython import *
except ImportError:
raise ImportError, "VTK extension module not found"
from wxPython.wx import *
import math
#----------------------------------------------------------------------
DEBUG = 0
def debug(msg):
if DEBUG:
print msg
class wxVTKRenderWindowBase(wxWindow):
"""
A base class that enables one to embed a vtkRenderWindow into
a wxPython widget. This class embeds the RenderWindow correctly
under different platforms. Provided are some empty methods that
can be overloaded to provide a user defined interaction behaviour.
The event handling functions have names that are similar to the
ones in the vtkInteractorStyle class included with VTK.
"""
def __init__(self, parent, id, position=wxDefaultPosition,
size=wxDefaultSize, style=0):
wxWindow.__init__(self, parent, id, position, size, style | wxWANTS_CHARS)
self._RenderWindow = vtkRenderWindow()
self.__InExpose = 0
self.__Created = 0
if wxPlatform != '__WXMSW__':
# We can't get the handle in wxGTK until after the widget
# is created, the window create event happens later so we'll
# catch it there
EVT_WINDOW_CREATE(self, self.OnCreateWindow)
EVT_PAINT (self, self.OnExpose)
else:
# but in MSW, the window create event happens durring the above
# call to __init__ so we have to do it here.
hdl = self.GetHandle()
self._RenderWindow.SetWindowInfo(str(hdl))
EVT_PAINT (self, self.OnExpose)
self.__Created = 1
# common for all platforms
EVT_SIZE (self, self.OnConfigure)
# setup the user defined events.
self.SetupEvents()
def SetupEvents(self):
"Setup the user defined event bindings."
# Remember to bind everything to self.box and NOT self
EVT_LEFT_DOWN (self, self.OnLeftButtonDown)
EVT_MIDDLE_DOWN (self, self.OnMiddleButtonDown)
EVT_RIGHT_DOWN (self, self.OnRightButtonDown)
EVT_LEFT_UP (self, self.OnLeftButtonUp)
EVT_MIDDLE_UP (self, self.OnMiddleButtonUp)
EVT_RIGHT_UP (self, self.OnRightButtonUp)
EVT_MOTION (self, self.OnMouseMove)
EVT_ENTER_WINDOW (self, self.OnEnter)
EVT_LEAVE_WINDOW (self, self.OnLeave)
EVT_CHAR (self, self.OnChar)
# Add your bindings if you want them in the derived class.
def GetRenderer(self):
self._RenderWindow.GetRenderers().InitTraversal()
return self._RenderWindow.GetRenderers().GetNextItem()
def GetRenderWindow(self):
return self._RenderWindow
def Render(self):
if self.__Created:
# if block needed because calls to render before creation
# will prevent the renderwindow from being embedded into a
# wxPython widget.
self._RenderWindow.Render()
def OnExpose(self, event):
# I need this for the MDIDemo. Somehow OnCreateWindow was
# not getting called.
if not self.__Created:
self.OnCreateWindow(event)
if (not self.__InExpose):
self.__InExpose = 1
dc = wxPaintDC(self)
self._RenderWindow.Render()
self.__InExpose = 0
def OnCreateWindow(self, event):
hdl = self.GetHandle()
try:
self._RenderWindow.SetParentInfo(str(hdl))
except:
self._RenderWindow.SetWindowInfo(str(hdl))
msg = "Warning:\n "\
"Unable to call vtkRenderWindow.SetParentInfo\n\n"\
"Using the SetWindowInfo method instead. This\n"\
"is likely to cause a lot of flicker when\n"\
"rendering in the vtkRenderWindow. Please\n"\
"use a recent Nightly VTK release (later than\n"\
"March 10 2001) to eliminate this problem."
dlg = wxMessageDialog(NULL, msg, "Warning!",
wxOK |wxICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
self.__Created = 1
def OnConfigure(self, event):
sz = self.GetSize()
self.SetSize(sz)
# Ugly hack that according to Eric Boix is necessary under
# Windows. If possible Try commenting this out and test under
# Windows.
#self._RenderWindow.GetSize()
#
self._RenderWindow.SetSize(sz.width, sz.height)
def OnLeftButtonDown(self, event):
"Left mouse button pressed."
pass
def OnMiddleButtonDown(self, event):
"Middle mouse button pressed."
pass
def OnRightButtonDown(self, event):
"Right mouse button pressed."
pass
def OnLeftButtonUp(self, event):
"Left mouse button released."
pass
def OnMiddleButtonUp(self, event):
"Middle mouse button released."
pass
def OnRightButtonUp(self, event):
"Right mouse button released."
pass
def OnMouseMove(self, event):
"Mouse has moved."
pass
def OnEnter(self, event):
"Entering the vtkRenderWindow."
pass
def OnLeave(self, event):
"Leaving the vtkRenderWindow."
pass
def OnChar(self, event):
"Process Key events."
pass
def OnKeyDown(self, event):
"Key pressed down."
pass
def OnKeyUp(self, event):
"Key released."
pass
class wxVTKRenderWindow(wxVTKRenderWindowBase):
"""
An example of a fully functional wxVTKRenderWindow that is
based on the vtkRenderWidget.py provided with the VTK sources.
"""
def __init__(self, parent, id, position=wxDefaultPosition,
size=wxDefaultSize, style=0):
wxVTKRenderWindowBase.__init__(self, parent, id, position, size,
style)
self._CurrentRenderer = None
self._CurrentCamera = None
self._CurrentZoom = 1.0
self._CurrentLight = None
self._ViewportCenterX = 0
self._ViewportCenterY = 0
self._Picker = vtkCellPicker()
self._PickedAssembly = None
self._PickedProperty = vtkProperty()
self._PickedProperty.SetColor(1,0,0)
self._PrePickedProperty = None
self._OldFocus = None
# these record the previous mouse position
self._LastX = 0
self._LastY = 0
def OnLeftButtonDown(self, event):
"Left mouse button pressed."
self.StartMotion(event)
def OnMiddleButtonDown(self, event):
"Middle mouse button pressed."
self.StartMotion(event)
def OnRightButtonDown(self, event):
"Right mouse button pressed."
self.StartMotion(event)
def OnLeftButtonUp(self, event):
"Left mouse button released."
self.EndMotion(event)
def OnMiddleButtonUp(self, event):
"Middle mouse button released."
self.EndMotion(event)
def OnRightButtonUp(self, event):
"Right mouse button released."
self.EndMotion(event)
def OnMouseMove(self, event):
event.x, event.y = event.GetPositionTuple()
if event.LeftIsDown():
if event.ShiftDown():
self.Pan(event.x, event.y)
else:
self.Rotate(event.x, event.y)
elif event.MiddleIsDown():
self.Pan(event.x, event.y)
elif event.RightIsDown():
self.Zoom(event.x, event.y)
def OnEnter(self, event):
self.__OldFocus = wxWindow_FindFocus()
self.SetFocus()
x, y = event.GetPositionTuple()
self.UpdateRenderer(x,y)
def OnLeave(self, event):
if (self._OldFocus != None):
self.__OldFocus.SetFocus()
def OnChar(self, event):
key = event.KeyCode()
if (key == ord('r')) or (key == ord('R')):
self.Reset()
elif (key == ord('w')) or (key == ord('W')):
self.Wireframe()
elif (key == ord('s')) or (key == ord('S')):
self.Surface()
elif (key == ord('p')) or (key == ord('P')):
x, y = event.GetPositionTuple()
self.PickActor(x, y)
else:
event.Skip()
# Start of internal functions
def GetZoomFactor(self):
return self._CurrentZoom
def SetZoomFactor(self, zf):
self._CurrentZoom = zf
def GetPicker(self):
return self._Picker
def Render(self):
if (self._CurrentLight):
light = self._CurrentLight
light.SetPosition(self._CurrentCamera.GetPosition())
light.SetFocalPoint(self._CurrentCamera.GetFocalPoint())
wxVTKRenderWindowBase.Render(self)
def UpdateRenderer(self, x, y):
"""
UpdateRenderer will identify the renderer under the mouse and set
up _CurrentRenderer, _CurrentCamera, and _CurrentLight.
"""
sz = self.GetSize()
windowX = sz.width
windowY = sz.height
renderers = self._RenderWindow.GetRenderers()
numRenderers = renderers.GetNumberOfItems()
self._CurrentRenderer = None
renderers.InitTraversal()
for i in range(0,numRenderers):
renderer = renderers.GetNextItem()
vx,vy = (0,0)
if (windowX > 1):
vx = float (x)/(windowX-1)
if (windowY > 1):
vy = (windowY-float(y)-1)/(windowY-1)
(vpxmin,vpymin,vpxmax,vpymax) = renderer.GetViewport()
if (vx >= vpxmin and vx <= vpxmax and
vy >= vpymin and vy <= vpymax):
self._CurrentRenderer = renderer
self._ViewportCenterX = float(windowX)*(vpxmax-vpxmin)/2.0\
+vpxmin
self._ViewportCenterY = float(windowY)*(vpymax-vpymin)/2.0\
+vpymin
self._CurrentCamera = self._CurrentRenderer.GetActiveCamera()
lights = self._CurrentRenderer.GetLights()
lights.InitTraversal()
self._CurrentLight = lights.GetNextItem()
break
self._LastX = x
self._LastY = y
def GetCurrentRenderer(self):
return self._CurrentRenderer
def StartMotion(self, event):
x, y = event.GetPositionTuple()
self.UpdateRenderer(x,y)
self.CaptureMouse()
def EndMotion(self, event=None):
if self._CurrentRenderer:
self.Render()
self.ReleaseMouse()
def Rotate(self,x,y):
if self._CurrentRenderer:
self._CurrentCamera.Azimuth(self._LastX - x)
self._CurrentCamera.Elevation(y - self._LastY)
self._CurrentCamera.OrthogonalizeViewUp()
self._LastX = x
self._LastY = y
self._CurrentRenderer.ResetCameraClippingRange()
self.Render()
def PanAbsolute(self, x_vec, y_vec):
if self._CurrentRenderer:
renderer = self._CurrentRenderer
camera = self._CurrentCamera
(pPoint0,pPoint1,pPoint2) = camera.GetPosition()
(fPoint0,fPoint1,fPoint2) = camera.GetFocalPoint()
if (camera.GetParallelProjection()):
renderer.SetWorldPoint(fPoint0,fPoint1,fPoint2,1.0)
renderer.WorldToDisplay()
fx,fy,fz = renderer.GetDisplayPoint()
renderer.SetDisplayPoint(fx+x_vec,
fy+y_vec,
fz)
renderer.DisplayToWorld()
fx,fy,fz,fw = renderer.GetWorldPoint()
camera.SetFocalPoint(fx,fy,fz)
renderer.SetWorldPoint(pPoint0,pPoint1,pPoint2,1.0)
renderer.WorldToDisplay()
fx,fy,fz = renderer.GetDisplayPoint()
renderer.SetDisplayPoint(fx+x_vec,
fy+y_vec,
fz)
renderer.DisplayToWorld()
fx,fy,fz,fw = renderer.GetWorldPoint()
camera.SetPosition(fx,fy,fz)
else:
(fPoint0,fPoint1,fPoint2) = camera.GetFocalPoint()
# Specify a point location in world coordinates
renderer.SetWorldPoint(fPoint0,fPoint1,fPoint2,1.0)
renderer.WorldToDisplay()
# Convert world point coordinates to display coordinates
dPoint = renderer.GetDisplayPoint()
focalDepth = dPoint[2]
aPoint0 = self._ViewportCenterX + x_vec
aPoint1 = self._ViewportCenterY + y_vec
renderer.SetDisplayPoint(aPoint0,aPoint1,focalDepth)
renderer.DisplayToWorld()
(rPoint0,rPoint1,rPoint2,rPoint3) = renderer.GetWorldPoint()
if (rPoint3 != 0.0):
rPoint0 = rPoint0/rPoint3
rPoint1 = rPoint1/rPoint3
rPoint2 = rPoint2/rPoint3
camera.SetFocalPoint((fPoint0 - rPoint0) + fPoint0,
(fPoint1 - rPoint1) + fPoint1,
(fPoint2 - rPoint2) + fPoint2)
camera.SetPosition((fPoint0 - rPoint0) + pPoint0,
(fPoint1 - rPoint1) + pPoint1,
(fPoint2 - rPoint2) + pPoint2)
self.Render()
def Pan(self, x, y):
self.PanAbsolute(x - self._LastX, - y + self._LastY)
self._LastX = x
self._LastY = y
def Zoom(self,x,y):
if self._CurrentRenderer:
renderer = self._CurrentRenderer
camera = self._CurrentCamera
zoomFactor = math.pow(1.02,(0.5*(self._LastY - y)))
self._CurrentZoom = self._CurrentZoom * zoomFactor
if camera.GetParallelProjection():
parallelScale = camera.GetParallelScale()/zoomFactor
camera.SetParallelScale(parallelScale)
else:
camera.Dolly(zoomFactor)
renderer.ResetCameraClippingRange()
self._LastX = x
self._LastY = y
self.Render()
def Reset(self):
if self._CurrentRenderer:
self._CurrentRenderer.ResetCamera()
self.Render()
def Wireframe(self):
actors = self._CurrentRenderer.GetActors()
numActors = actors.GetNumberOfItems()
actors.InitTraversal()
for i in range(0,numActors):
actor = actors.GetNextItem()
actor.GetProperty().SetRepresentationToWireframe()
self.Render()
def Surface(self):
actors = self._CurrentRenderer.GetActors()
numActors = actors.GetNumberOfItems()
actors.InitTraversal()
for i in range(0,numActors):
actor = actors.GetNextItem()
actor.GetProperty().SetRepresentationToSurface()
self.Render()
def PickActor(self,x,y):
if self._CurrentRenderer:
renderer = self._CurrentRenderer
picker = self._Picker
windowY = self.GetSize().height
picker.Pick(x,(windowY - y - 1),0.0,renderer)
assembly = picker.GetAssembly()
if (self._PickedAssembly != None and
self._PrePickedProperty != None):
self._PickedAssembly.SetProperty(self._PrePickedProperty)
# release hold of the property
self._PrePickedProperty.UnRegister(self._PrePickedProperty)
self._PrePickedProperty = None
if (assembly != None):
self._PickedAssembly = assembly
self._PrePickedProperty = self._PickedAssembly.GetProperty()
# hold onto the property
self._PrePickedProperty.Register(self._PrePickedProperty)
self._PickedAssembly.SetProperty(self._PickedProperty)
self.Render()
More information about the vtkusers
mailing list