Hi all,
I’ve managed to resolve my second question above using the code found at the end of this message. The gist is that I assigned an “ID” to each cell of the vtkPolyLine
object by attaching a data array to the object. As this array persists through the application of the tube filter, I can then conduct a selection based on this ID array, thus allowing me to grab all cells in the output of the tube filter that correspond to one cell in the vtkPolyLine
object!
import vtk
from trame.app import get_server
from trame.widgets import vuetify, vtk as vtk_widgets
from trame.ui.vuetify import SinglePageLayout
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkPolyDataMapper,
vtkDataSetMapper,
vtkRenderer,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkCellPicker
)
from vtkmodules.numpy_interface import dataset_adapter as dsa
from vtkmodules.vtkFiltersCore import vtkTubeFilter
from vtkmodules.vtkFiltersExtraction import vtkExtractSelection
from vtkmodules.vtkCommonDataModel import vtkSelection, vtkSelectionNode
import vtk.util.numpy_support as vtknumpy
import numpy as np
# -----------------------------------------------------------------------------
# Generate dataset
# -----------------------------------------------------------------------------
points = vtk.vtkPoints()
points.SetNumberOfPoints(4)
line = vtk.vtkLine()
lines = vtk.vtkCellArray()
# create first line segment
points.SetPoint(0, 0, 0, 0)
line.GetPointIds().SetId(0, 0)
points.SetPoint(1, 1, 1, 1)
line.GetPointIds().SetId(1, 1)
lines.InsertNextCell(line)
# create second line segment
points.SetPoint(2, 1, 1, 1)
line.GetPointIds().SetId(0, 2)
points.SetPoint(3, 2, 2, 2)
line.GetPointIds().SetId(1, 3)
lines.InsertNextCell(line)
linesPolyData = vtk.vtkPolyData()
linesPolyData.SetPoints(points)
linesPolyData.SetLines(lines)
vtkfields= vtknumpy.numpy_to_vtk([0,1])
vtkfields.SetName("og_id")
vtkfields.SetNumberOfComponents(1)
og_ids = vtknumpy.numpy_to_vtk([0,1]) # TODO: change to be a function of number of lines
og_ids.SetName("og_id")
og_ids.SetNumberOfComponents(1)
linesPolyData.GetCellData().AddArray(og_ids)
# -----------------------------------------------------------------------------
# Trame initialization
# -----------------------------------------------------------------------------
server = get_server()
state, ctrl = server.state, server.controller
# -----------------------------------------------------------------------------
# Interactions
# -----------------------------------------------------------------------------
def update_selection(pickData, **kwargs):
data = pickData
picker = vtkCellPicker()
picker.SetTolerance(0.0005) # based on example
pos = data["position"]
picker.Pick(pos["x"], pos["y"], pos["z"], renderer)
idx = picker.GetCellId()
if idx != -1:
SELECTED_IDX = np.array(tubes_filter.GetOutput().GetCellData().GetArray("og_id"))[idx].tolist()
else:
SELECTED_IDX = []
sel_node = vtkSelectionNode()
sel_node.GetProperties().Set(vtkSelectionNode.CONTENT_TYPE(), vtkSelectionNode.VALUES)
sel_node.GetProperties().Set(vtkSelectionNode.FIELD_TYPE(), vtkSelectionNode.CELL)
sel_node.GetProperties().Set(vtkSelectionNode.COMPONENT_NUMBER(), 0)
selected_cells = vtknumpy.numpy_to_vtk(SELECTED_IDX)
selected_cells.SetName("og_id")
selected_cells.SetNumberOfComponents(1)
sel_node.SetSelectionList(selected_cells)
sel = vtkSelection()
sel.AddNode(sel_node)
selection_extract.SetInputConnection(tubes_filter.GetOutputPort())
selection_extract.SetInputDataObject(1, sel)
selection_extract.Update()
selection_actor.SetVisibility(1)
# Update 3D view
ctrl.view_update()
# -----------------------------------------------------------------------------
# VTK pipeline
# -----------------------------------------------------------------------------
tubes_filter = vtkTubeFilter()
tubes_filter.SetInputData(linesPolyData)
radius = 2
tubes_filter.SetRadius(radius)
n_of_sides = 3
tubes_filter.SetNumberOfSides(n_of_sides)
tubes_filter.Update()
mapper = vtkPolyDataMapper()
mapper.SetInputConnection(tubes_filter.GetOutputPort())
actor = vtkActor()
actor.SetMapper(mapper)
# Selection
selection_extract = vtkExtractSelection()
selection_mapper = vtkDataSetMapper()
selection_mapper.SetInputConnection(selection_extract.GetOutputPort())
selection_actor = vtkActor()
selection_actor.GetProperty().SetColor(1, 0, 1)
selection_actor.SetMapper(selection_mapper)
selection_actor.SetVisibility(0)
selection_actor.SetPickable(0)
renderer = vtkRenderer()
renderer.SetBackground(1, 1, 1)
render_window = vtkRenderWindow()
render_window.AddRenderer(renderer)
rw_interactor = vtkRenderWindowInteractor()
rw_interactor.SetRenderWindow(render_window)
rw_interactor.GetInteractorStyle().SetCurrentStyleToTrackballCamera()
renderer.AddActor(actor)
renderer.AddActor(selection_actor)
renderer.ResetCamera()
# -----------------------------------------------------------------------------
# GUI layout
# -----------------------------------------------------------------------------
VTK_VIEW_SETTINGS = {
"interactive_ratio": 1,
"interactive_quality": 100,
}
with SinglePageLayout(server) as layout:
layout.icon.click = ctrl.view_reset_camera
with layout.content:
with vuetify.VContainer(fluid=True, classes="fill-height pa-0 ma-0"):
view = vtk_widgets.VtkRemoteView(
render_window,
interactor_events=("events", ["LeftButtonPress"]),
LeftButtonPress=(update_selection, "[utils.vtk.event($event)]"),
**VTK_VIEW_SETTINGS,
)
ctrl.view_update = view.update
ctrl.view_reset_camera = view.reset_camera
# -----------------------------------------------------------------------------
# Main
# -----------------------------------------------------------------------------
if __name__ == "__main__":
server.start(port=0)