利用点击鼠标左键来对三维网格模型进行拾点,是很简单方便的,但鼠标左键的功能不只是用来拾点的,很多交互式操作都需要鼠标点击。所以,可以加入按键事件,但我按一下键盘上的某个按键时,此时鼠标左键才进行拾点,代码如下:
程序描述:
任务:交互式拾取两个点,点1和点2
操作:按键盘1键,此时用鼠标左键点击拾取点1
按键盘2键,此时用鼠标左键点击拾取点2
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonCore import vtkMinimalStandardRandomSequence
from vtkmodules.vtkFiltersSources import vtkSphereSource
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkPolyDataMapper,
vtkPropPicker,
vtkProperty,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkRenderer
)
import vtk
''' 对Actor的属性进行设置 '''
def SetupActor(actor, color=None, opa=None, pos=None, bVis=None, renderer=None):
if color != None: # 设置颜色
actor.GetProperty().SetColor(color[0], color[1], color[2])
if opa != None: # 设置透明度
actor.GetProperty().SetOpacity(opa)
if pos != None: # 设置位置
actor.SetPosition(pos)
if bVis != None: # 设置可见性
actor.SetVisibility(bVis)
if renderer != None: # 加入渲染器
renderer.AddActor(actor)
''' 使用小球对坐标进行可视化 '''
def MarkWithSphere(actor, color=None, opa=None, pos=None, bVis=None, renderer=None):
sphere = vtk.vtkSphereSource()
sphere.Update()
sphereMapper = vtkPolyDataMapper()
sphereMapper.SetInputConnection(sphere.GetOutputPort())
actor.SetMapper(sphereMapper)
SetupActor(actor, color, opa, pos, bVis, renderer)
class MouseInteractorHighLightActor(vtkInteractorStyleTrackballCamera):
def __init__(self, renderer):
self.AddObserver("LeftButtonPressEvent", self.leftButtonPressEvent) # 鼠标左键消息
self.AddObserver('KeyPressEvent', self.key_press_event) # 按键消息
self.renderer = renderer
self.sphereActor1 = vtkActor() # 定义一个球形,用来标记第一个拾取点
self.sphereActor2 = vtkActor() # 定义一个球形,用来标记第二个拾取点
self.mode = 0 # mode=0的时候表示不选点, mode=1的时候表示选第一个点, mode=2的选第二个点
MarkWithSphere(self.sphereActor1, color=[1, 1, 0], renderer=self.renderer, bVis=False)
MarkWithSphere(self.sphereActor2, color=[0, 1, 0], renderer=self.renderer, bVis=False)
def leftButtonPressEvent(self, obj, event):
if self.mode != 0:
picker = vtk.vtkPointPicker() # 指定拾取器
pos = self.GetInteractor().GetEventPosition() # 获取事件二维屏幕坐标
ren = self.GetDefaultRenderer() # 记得预先通过SetDefaultRenderer指定渲染器
picker.Pick(pos[0], pos[1], 0, ren)
world_position = picker.GetPickPosition() # 获取拾取点的三维坐标
print(world_position)
id = picker.GetPointId()
print(id)
if self.mode == 1:
self.sphereActor1.VisibilityOn() # 显示球型
self.sphereActor1.SetPosition(world_position) # 将球型的中心设为拾取点的坐标
self.mode = 0
elif self.mode == 2:
self.sphereActor2.VisibilityOn() # 显示球型
self.sphereActor2.SetPosition(world_position) # 将球型的中心设为拾取点的坐标
self.mode = 0
self.OnLeftButtonDown()
return
def key_press_event(self, obj, event):
key = self.GetInteractor().GetKeySym()
# if key.lower() == "1" and self.mode == 0: # 指定第一个点
if key.lower() == "1":
self.mode = 1
elif key.lower() == "2":
self.mode = 2
def main():
colors = vtkNamedColors()
# 渲染和窗口
renderer = vtkRenderer()
renderer.SetBackground(colors.GetColor3d('SteelBlue'))
renwin = vtkRenderWindow()
renwin.AddRenderer(renderer)
renwin.SetSize(640, 480)
renwin.SetWindowName('HighlightPickedActor')
# 交互器
interactor = vtkRenderWindowInteractor()
interactor.SetRenderWindow(renwin)
# add the custom style
style = MouseInteractorHighLightActor(renderer)
style.SetDefaultRenderer(renderer)
interactor.SetInteractorStyle(style)
reader = vtk.vtkOBJReader()
reader.SetFileName("00OMSZGW_upper.obj")
reader.Update()
mesh = reader.GetOutput()
mapper = vtkPolyDataMapper()
mapper.SetInputData(mesh)
actor = vtkActor()
actor.SetMapper(mapper)
renderer.AddActor(actor)
# Start
interactor.Initialize()
renwin.Render()
interactor.Start()
if __name__ == '__main__':
main()
结果: