I’ve a Volume with mapper vtkGPUVolumeRayCastMapper and vtkFixedPointVolumeRayCastMapper and I wanted to make to try to make a basic scissors (scalpel), decided to start with vtkPolyLineWidget and vtkPolyLineRepresentation (and try for start on basic vtkPolyDataMapper).
So in short I wanted from N-Points (translating from camera/display to world position when placing) of polyline generate N-vtkPlane (aka rays) to cut mapper with AddClippingPlane except I’m at loss due not able to understand how to correctly generate vtkPlanes which would cut mapper as I want, taking simple two points (i and i+1) kinda doesn’t work correctly.
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkFiltersSources import vtkCylinderSource
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
from vtkmodules.vtkInteractionWidgets import (
vtkCameraOrientationWidget,
vtkSplineWidget,
vtkPolyLineWidget,
vtkPolyLineRepresentation,
)
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkPolyDataMapper,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkRenderer,
vtkCoordinate,
)
import vtk
class MyInteractorStyle(vtkInteractorStyleTrackballCamera):
def __init__(self, parent=None):
self.father = parent
#Change Trackball Mouse Buttons to make Left Button inactive but Right button to use Left Button functions (rotate)
self.AddObserver('LeftButtonPressEvent', self.leftButtonPressEvent)
self.AddObserver('LeftButtonReleaseEvent', self.leftButtonReleaseEvent)
self.AddObserver('RightButtonPressEvent', self.rightButtonPressEvent)
self.AddObserver('RightButtonReleaseEvent', self.rightButtonReleaseEvent)
# self.AddObserver('MiddleButtonPressEvent', self.middle_button_press_event)
# self.AddObserver('MiddleButtonReleaseEvent', self.middle_button_release_event)
def rightButtonPressEvent(self, obj, event):
self.OnLeftButtonDown()
return
def rightButtonReleaseEvent(self, obj, event):
self.OnLeftButtonUp()
return
def leftButtonPressEvent(self, obj, event):
self.father.managePolyLine()
return
def leftButtonReleaseEvent(self, obj, event):
return
class RunVTK():
def __init__(self) -> None:
self.init_main()
def init_main(self):
colors = vtkNamedColors()
colors.SetColor('ParaViewBkg', [82, 87, 110, 255])
has_cow = False
# if vtk_version_ok(9, 0, 20210718):
cam_orient_manipulator = vtkCameraOrientationWidget()
has_cow = True
window_width = 800
window_height = 600
self.ren_win = vtkRenderWindow()
self.ren_win.SetSize(window_width, window_height)
iren = vtkRenderWindowInteractor()
iren.SetRenderWindow(self.ren_win)
style = MyInteractorStyle(self)
iren.SetInteractorStyle(style)
self.renderer = vtkRenderer()
self.renderer.SetBackground(colors.GetColor3d('ParaViewBkg'))
# Create a cylinder.
cylinder = vtkCylinderSource()
cylinder.SetCenter(0.0, 0.0, 0.0)
cylinder.SetRadius(3.0)
cylinder.SetHeight(5.0)
cylinder.SetResolution(100)
# Create a mapper and actor
self.mapper = vtkPolyDataMapper()
self.mapper.SetInputConnection(cylinder.GetOutputPort())
self.actor = vtkActor()
self.actor.GetProperty().SetColor(colors.GetColor3d('Cornsilk'))
self.actor.SetMapper(self.mapper)
# Add the actor to the scene
self.renderer.AddActor(self.actor)
self.ren_win.AddRenderer(self.renderer)
# Important: The interactor must be set prior to enabling the widget.
iren.SetRenderWindow(self.ren_win)
if has_cow:
cam_orient_manipulator.SetParentRenderer(self.renderer)
# Enable the widget.
cam_orient_manipulator.On()
self.ren_win.Render()
self.ren_win.SetWindowName('PolyLine Scissors')
iren.Start()
def managePolyLine(self):
if not hasattr(self, "polyline"):
print("Creating PoliLine")
self.polyline_rep = vtkPolyLineRepresentation()
self.polyline = vtkPolyLineWidget()
self.polyline.SetRepresentation(self.polyline_rep)
interactor = self.ren_win.GetInteractor()
self.polyline.SetInteractor(interactor)
self.polyline_rep.SetLineColor(255, 0, 0)
self.polyline_rep.SetNumberOfHandles(1)
self.polyline.On()
self.polyline_rep.ClosedOn()
x, y = interactor.GetEventPosition()
coords = vtk.vtkCoordinate()
coords.SetCoordinateSystemToDisplay()
coords.SetValue(x, y, 0)
x, y, z = coords.GetComputedWorldValue(self.renderer)
del coords
self.polyline_rep.SetHandlePosition(0, x, y, z)
else:
interactor = self.ren_win.GetInteractor()
x, y = interactor.GetEventPosition()
handles_count = self.polyline_rep.GetNumberOfHandles()
self.polyline_rep.SetNumberOfHandles(handles_count + 1)
coords = vtkCoordinate()
coords.SetCoordinateSystemToDisplay()
coords.SetValue(x, y, 0)
x, y, z = coords.GetComputedWorldValue(self.renderer)
del coords
self.polyline_rep.SetHandlePosition(handles_count, x, y, z)
#Test Version of Cutting should occur if points reaches beyond 4
if self.polyline_rep.GetNumberOfHandles() == 4:
vtk_array = self.polyline_rep.GetHandlePositions()
vtk_array: vtk.vtkTypeFloat64Array
for i in range(3):
x1, y1, z1 = vtk_array.GetTuple(i)
x2, y2, z2 = vtk_array.GetTuple(i+1)
self.ren_win.Render()
if __name__ == '__main__':
main = RunVTK()