我正在编写一个使用wxPython GUI在VTK中渲染点云的应用程序。我基于Sukhbinder Singh here和here的出色示例编写了代码。我现在想在数据面板中实现鼠标右键单击选项,该选项允许用户通过上下文菜单执行各种任务(例如重置相机位置)。我尝试了几种不同的情况,但是每种情况下的行为都略有错误:
A)事件“ RightButtonPressEvent”使我可以从上下文菜单中选择合适的项目并执行绑定功能,但随后将不再响应鼠标左键,并且
B)事件“ RightButtonReleaseEvent”也开始执行绑定功能,但是随后鼠标的任何移动都好像我仍然按下右键一样。在我当前的VTK渲染窗口交互器样式中,这意味着放大/缩小-直到单击鼠标左键。
我尝试了(B)随后的PostEvent调用来模拟鼠标左键单击,但无济于事。将事件直接添加到交互器而不是其样式具有相同的效果。谁能告诉我我所缺少的吗?
在Win7,wx 4.0.3,vtk 8.1.1。上使用Python 3.4 / 3.6
我的长期“最小”示例如下:
import wx
import vtk
from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor
import numpy as np
class VtkPointCloud:
def __init__(self, zMin=-10.0, zMax=10.0):
self.maxNumPoints = 1e6
self.vtkPolyData = vtk.vtkPolyData()
self.clearPoints()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(self.vtkPolyData)
mapper.SetColorModeToDefault()
mapper.SetScalarRange(zMin, zMax)
mapper.SetScalarVisibility(1)
self.vtkActor = vtk.vtkActor()
self.vtkActor.SetMapper(mapper)
def addPoint(self, point):
if self.vtkPoints.GetNumberOfPoints() < self.maxNumPoints:
pointId = self.vtkPoints.InsertNextPoint(point[:])
self.vtkDepth.InsertNextValue(point[2])
self.vtkCells.InsertNextCell(1)
self.vtkCells.InsertCellPoint(pointId)
self.vtkCells.Modified()
self.vtkPoints.Modified()
self.vtkDepth.Modified()
def clearPoints(self):
self.vtkPoints = vtk.vtkPoints()
self.vtkCells = vtk.vtkCellArray()
self.vtkDepth = vtk.vtkDoubleArray()
self.vtkDepth.SetName('DepthArray')
self.vtkPolyData.SetPoints(self.vtkPoints)
self.vtkPolyData.SetVerts(self.vtkCells)
self.vtkPolyData.GetPointData().SetScalars(self.vtkDepth)
self.vtkPolyData.GetPointData().SetActiveScalars('DepthArray')
class p1(wx.Panel):
# ---------------------------------------------------------------------------------------------
def __init__(self,parent):
wx.Panel.__init__(self, parent)
self.widget = wxVTKRenderWindowInteractor(self, -1)
self.widget.SetInteractorStyle(vtk.vtkInteractorStyleTrackballCamera())
self.widget.Enable(1)
self.widget.AddObserver("ExitEvent", lambda o,e,f=self: f.Close())
i_style = self.widget.GetInteractorStyle()
#i_style.AddObserver("RightButtonPressEvent", self._context_menu) # Freezes panel!
i_style.AddObserver("RightButtonReleaseEvent", self._context_menu)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.widget, 1, wx.EXPAND)
self.SetSizer(self.sizer)
self.Layout()
self.is_plotted = False
# ---------------------------------------------------------------------------------------------
def renderthis(self):
# open a window and create a renderer
pointCloud = VtkPointCloud()
data = 20*(np.random.rand(3,1000)-0.5)
for i in range(data.shape[1]):
pointCloud.addPoint(data[:,i])
camera = vtk.vtkCamera()
midpoint_x = 0
midpoint_y = 0
camera.SetPosition(midpoint_x, midpoint_y, -np.nanmax(data[2,:])); # eye position
camera.SetFocalPoint(midpoint_x, midpoint_y, np.nanmax(data[2,:])) # perspective vanishing point
# Save the default view
self._default_cam_pos = camera.GetPosition()
self._default_cam_focal = camera.GetFocalPoint()
self._default_view_up = camera.GetViewUp()
# Renderer
self._renderer = vtk.vtkRenderer()
self._renderer.AddActor(pointCloud.vtkActor)
self._renderer.SetBackground(0.0, 0.0, 0.0)
self._renderer.SetActiveCamera(camera)
# Render Window
self.widget.GetRenderWindow().AddRenderer(self._renderer)
# ---------------------------------------------------------------------------------------------
def _context_menu(self, caller, event):
reset_cam_ID = wx.NewId()
self.Bind(wx.EVT_MENU, self._on_reset_cam, id=reset_cam_ID)
menu = wx.Menu()
menu.Append(reset_cam_ID, "Reset camera")
self.PopupMenu(menu)
menu.Destroy()
# ---------------------------------------------------------------------------------------------
def _on_reset_cam(self, event):
cam = self._renderer.GetActiveCamera()
cam.SetPosition(self._default_cam_pos)
cam.SetFocalPoint(self._default_cam_focal)
cam.SetViewUp(self._default_view_up)
self.Refresh()
class TestFrame(wx.Frame):
# ---------------------------------------------------------------------------------------------
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(650,600),
style=(wx.MINIMIZE_BOX |
wx.SYSTEM_MENU |
wx.CAPTION |
wx.CLOSE_BOX |
wx.CLIP_CHILDREN))
self.sp = wx.SplitterWindow(self)
self.p1 = p1(self.sp)
self.p2 = wx.Panel(self.sp, style=wx.SUNKEN_BORDER)
self.sp.SplitHorizontally(self.p1, self.p2, 470)
self.statusbar = self.CreateStatusBar()
self.statusbar.SetStatusText("Click on the Plot Button")
self.plotbut = wx.Button(self.p2, -1, "Plot", size=(40,20), pos=(10,10))
self.plotbut.Bind(wx.EVT_BUTTON,self.plot)
# ---------------------------------------------------------------------------------------------
def plot(self,event):
if not self.p1.is_plotted:
self.p1.renderthis()
self.statusbar.SetStatusText("Use your mouse to interact with the model")
app = wx.App(redirect=False)
frame = TestFrame(None, "Pointcloud")
frame.Show()
app.MainLoop()