unexpected behavior when selecting (and "highlighting") cells in trame

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)
1 Like