Kitware / trame

Trame lets you weave various components and technologies into a Web Application solely written in Python.

Home Page:https://kitware.github.io/trame/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Failure when picking cells

cardinalgeo opened this issue · comments

Describe the bug

Picking cells in a simple tube filter, applied to a two-line-segment polyline, sometimes fails inexplicably.
To Reproduce

Steps to reproduce the behavior:

  1. Run the script that follows
  2. Click on the actor to "pick" its cells
  3. Inspect the viewer and command line output; when pick is successful, a tooltip appears with the data value corresponding to the cell and the last output on the command line shows a value > -1. when the pick is unsuccessful, no tooltip appears and the last output on the command line shows a value = -1.

Code

from trame.app import get_server
from trame.ui.vuetify import SinglePageLayout
from trame.widgets import vuetify, html, trame, vtk as vtk_widgets
from vtkmodules.vtkFiltersCore import vtkTubeFilter
from vtk import reference, vtkGenericCell
import vtk.util.numpy_support as vtknumpy

import vtk

import numpy as np
# -----------------------------------------------------------------------------
# Trame
# -----------------------------------------------------------------------------

server = get_server()
state, ctrl = server.state, server.controller

# -----------------------------------------------------------------------------
# Constants
# -----------------------------------------------------------------------------

VIEW_INTERACT = [
    {"button": 1, "action": "Rotate"},
    {"button": 2, "action": "Pan"},
    {"button": 3, "action": "Zoom", "scrollEnabled": True},
    {"button": 1, "action": "Pan", "alt": True},
    {"button": 1, "action": "Zoom", "control": True},
    {"button": 1, "action": "Pan", "shift": True},
    {"button": 1, "action": "Roll", "alt": True, "shift": True},
]

# -----------------------------------------------------------------------------
# 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("data")
vtkfields.SetNumberOfComponents(1)

linesPolyData.GetCellData().AddArray(vtkfields)

# -----------------------------------------------------------------------------
# VTK pipeline
# -----------------------------------------------------------------------------

lines_tubes = vtkTubeFilter()
lines_tubes.SetInputData(linesPolyData)
radius = 2
lines_tubes.SetRadius(radius)
n_of_sides = 6
lines_tubes.SetNumberOfSides(n_of_sides)
lines_tubes.Update()
lines_polydata = lines_tubes.GetOutput()
state.lines = None

# Extract fieldParameters
fieldParameters = {"data": {"range": [0, 1]}}
cd = linesPolyData.GetCellData()
nb_arrays = cd.GetNumberOfArrays()

# -----------------------------------------------------------------------------
# Web App setup
# -----------------------------------------------------------------------------

state.update(
    {
        # Fields available
        "fieldParameters": fieldParameters,
        # picking controls
        "pickingMode": "click",
        "modes": [
            {"value": "click", "icon": "mdi-cursor-default-click-outline"},
        ],
        "field": "data",
        # Picking feedback
        "pickData": None,
        "tooltip": "",
        "pixel_ratio": 2,
        # Meshes
        "linesVisible": True,
        
    }
)

# -----------------------------------------------------------------------------
# Callbacks
# -----------------------------------------------------------------------------

@state.change("pickData")
def update_tooltip(pickData, pixel_ratio, **kwargs):
    state.tooltip = ""
    state.tooltipStyle = {"display": "none"}
    data = pickData
    if data and data["representationId"] == "lines":
        xyx = data["worldPosition"]
        
        gen_cell = vtkGenericCell()
        sub_id = reference(0)
        pc = [0, 0, 0]
        weights = [0,0,0,0,0,0,0,0,0,0,0,0]
        face_idx = lines_polydata.FindCell(xyx, gen_cell, -1, 1, sub_id, pc, weights)
        idx = int(np.floor(face_idx / n_of_sides))
        print(" ")
        print("New Click:")
        print(f"xyx={xyx}, gen_cell={gen_cell}, sub_id={sub_id}, pc={pc}, weights={weights}")
        print(f"index={idx}")
        if idx > -1:

            messages = []

            for i in range(nb_arrays):
                array = cd.GetAbstractArray(i)
                if array.IsNumeric(): 
                    name = array.GetName()
                    if name == state.field: 
                        value_str = f"{array.GetValue(idx):.2f}"
                        norm_str = ""

                        messages.append(f"{name}: {value_str} {norm_str}")

            if len(messages):
                x, y, z = data["displayPosition"]
                state.tooltip = "\n".join(messages)
                state.tooltipStyle = {
                    "position": "absolute",
                    "left": f"{(x / pixel_ratio )+ 10}px",
                    "bottom": f"{(y / pixel_ratio ) + 10}px",
                    "zIndex": 10,
                    "pointerEvents": "none",
                }

# -----------------------------------------------------------------------------
# UI
# -----------------------------------------------------------------------------

with SinglePageLayout(server) as layout:
    # Let the server know the browser pixel ratio
    trame.ClientTriggers(mounted="pixel_ratio = window.devicePixelRatio")

    with layout.content:
        with vuetify.VContainer(
            fluid=True, classes="pa-0 fill-height", style="position: relative;"
        ): 

            with vuetify.VCard(
                style=("tooltipStyle", {"display": "none"}), elevation=2, outlined=True
            ):
                with vuetify.VCardText():
                    html.Pre("{{ tooltip }}")

            with vtk_widgets.VtkView(
                ref="view",
                picking_modes=("[pickingMode]",),
                interactor_settings=("interactorSettings", VIEW_INTERACT),
                click="pickData = $event"
            ):

                with vtk_widgets.VtkGeometryRepresentation(
                    id="lines",
                    v_if="lines",
                    actor=("{ visibility: linesVisible }",),
                ):
                    vtk_widgets.VtkMesh("lines", dataset=lines_polydata, cell_arrays=["data"])

# -----------------------------------------------------------------------------
# Jupyter
# -----------------------------------------------------------------------------

def show(**kwargs):
    from trame.app import jupyter

    jupyter.show(server, **kwargs)

# -----------------------------------------------------------------------------
# CLI
# -----------------------------------------------------------------------------

if __name__ == "__main__":
    server.start(port=8080)

Expected behavior

I expect that, upon clicking the tube filter actor, a cell within the actor will be picked. Inexplicably, the cell that is clicked will occasionally not be registered as picked. Furthermore, this "bad behavior" gets worse as the number of clicks continues (i.e., initially the proportion of clicks that result in a failed pick is low, but that increases with the cumulative number of clicks). The behavior described is exhibited in the movie below:

Screenshots

MRE_pick_failure_vtk.mov

I realize that this might be an issue with something other than Trame, but I thought I'd start here!

Platform:

Trame:

  • Version 1.x
  • Version 2.x

Device:

  • Desktop
  • Mobile

OS:

  • Windows
  • MacOS
  • Linux
  • Android
  • iOS

Browsers Affected:

  • Chrome
  • Firefox
  • Microsoft Edge
  • Safari
  • Opera
  • Brave
  • IE 11

py-web-vue version:
vMAJOR.MINOR.PATCH

Closing for now as workaround found