Hi VTK Community! I’m attempting to adapt the selection highlighting functionality used in this trame example, but the exhibited behavior is unexpected. I’m trying to select cells in a vtkPolyData
Object consisting of a simple 3-sided tube filter applied to a simple, two-line segment vtkPolyLine
object using a vtkRenderedAreaPicker
and toggling visibility of the associated “selection actor” to highlight the selected cells. However, selecting a particular cell sometimes results in only a subset of the tube sides for that cell being highlighted, as seen below.
Is this expected behavior? How can I ensure that all sides are highlighted upon selection of a cell?
Other times, selecting a cell highlights sides of a different cell, as seen below.
Why is this occurring?
Please consider the MRE app below, which reproduces the behavior described above and was used to generate the screenshots:
import vtk
from trame.app import get_server, jupyter # noqa (jupyter must be installed or error results)
from trame.widgets import vuetify, vtk as vtk_widgets
from trame.ui.vuetify import SinglePageLayout
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkDataSetMapper,
vtkRenderer,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkHardwareSelector,
vtkRenderedAreaPicker
)
from vtkmodules.vtkFiltersCore import vtkTubeFilter
from vtkmodules.vtkFiltersExtraction import vtkExtractSelection
from vtkmodules.vtkInteractionStyle import (
vtkInteractorStyleRubberBandPick,
vtkInteractorStyleSwitch) # noqa (needed for swtiching style of interaction to trackball camera)
from vtkmodules.vtkCommonDataModel import vtkDataObject
import vtkmodules.vtkRenderingOpenGL2 # noqa (needed for vtkHardwareSelector)
# -----------------------------------------------------------------------------
# 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)
# -----------------------------------------------------------------------------
# Trame initialization
# -----------------------------------------------------------------------------
server = get_server()
state, ctrl = server.state, server.controller
# -----------------------------------------------------------------------------
# VTK pipeline
# -----------------------------------------------------------------------------
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()
interactor_trackball = rw_interactor.GetInteractorStyle()
interactor_selection = vtkInteractorStyleRubberBandPick() #
area_picker = vtkRenderedAreaPicker()
rw_interactor.SetPicker(area_picker)
tubes = vtkTubeFilter()
tubes.SetInputData(linesPolyData)
tubes.SetRadius(2)
tubes.SetNumberOfSides(3)
tubes.Update()
print(tubes)
mapper = vtkDataSetMapper()
mapper.SetInputConnection(tubes.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)
renderer.AddActor(actor)
renderer.AddActor(selection_actor)
renderer.ResetCamera()
selector = vtkHardwareSelector()
selector.SetRenderer(renderer)
# -----------------------------------------------------------------------------
# Callbacks
# -----------------------------------------------------------------------------
@state.change("vtk_selection")
def update_interactor(vtk_selection, **kwargs):
if vtk_selection:
rw_interactor.SetInteractorStyle(interactor_selection)
interactor_selection.StartSelect()
else:
rw_interactor.SetInteractorStyle(interactor_trackball)
# -----------------------------------------------------------------------------
def on_box_selection_change(selection):
actor.GetProperty().SetOpacity(1)
selector.SetArea(
int(renderer.GetPickX1()),
int(renderer.GetPickY1()),
int(renderer.GetPickX2()),
int(renderer.GetPickY2()),
)
s = selector.Select()
print(s)
selection_extract.SetInputConnection(tubes.GetOutputPort())
selection_extract.SetInputDataObject(1, s)
selection_extract.Update()
selection_actor.SetVisibility(1)
actor.GetProperty().SetOpacity(1)
# Update 3D view
ctrl.view_update()
# disable selection mode
state.vtk_selection = False
# -----------------------------------------------------------------------------
# GUI layout
# -----------------------------------------------------------------------------
VTK_VIEW_SETTINGS = {
"interactive_ratio": 1,
"interactive_quality": 80,
}
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"):
with vuetify.VRow(dense=True, style="height: 100%;"):
with vuetify.VCol(
classes="pa-0",
style="border-right: 1px solid #ccc; position: relative;",
):
view = vtk_widgets.VtkRemoteView(
render_window,
box_selection=("vtk_selection",),
box_selection_change=(on_box_selection_change, "[$event]"),
**VTK_VIEW_SETTINGS,
)
ctrl.view_update = view.update
ctrl.view_reset_camera = view.reset_camera
vuetify.VCheckbox(
small=True,
on_icon="mdi-selection-drag",
off_icon="mdi-rotate-3d",
v_model=("vtk_selection", False),
style="position: absolute; top: 0; right: 0; z-index: 1;",
dense=True,
hide_details=True,
)
# -----------------------------------------------------------------------------
# Main
# -----------------------------------------------------------------------------
if __name__ == "__main__":
server.start()