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

Failing event binding with vtkRemoteView

cardinalgeo opened this issue · comments

Describe the bug
Under the following conditions, the error message JS Error => RangeError: Maximum call stack size exceeded is produced.
1.) Use of vtkRemoteView() (this error is not produced for vtkLocalView())
2.) an arbitrary function is bound to an event, such as LeftButtonDown
3.) the contents of the event are passed as an input to the function
4.) the event is triggered

To Reproduce

Steps to reproduce the behavior:

  1. Run the script below (an MRE using a two-segment polyline passed to a tube filter as an actor)
  2. Click anywhere in the display
  3. See error

Code

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,
    vtkRenderer,
    vtkRenderWindow,
    vtkRenderWindowInteractor, 
)
from vtkmodules.vtkFiltersCore import vtkTubeFilter
from vtkmodules.vtkInteractionStyle import (
    vtkInteractorStyleTrackballCamera) 

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

# -----------------------------------------------------------------------------
# Interactions
# -----------------------------------------------------------------------------

def foo(pickData): 
    print("hello")

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

tubes_filter = vtkTubeFilter()
tubes_filter.SetInputData(linesPolyData)
tubes_filter.SetRadius(2)
tubes_filter.SetNumberOfSides(3)
tubes_filter.Update()

mapper = vtkPolyDataMapper()
mapper.SetInputConnection(tubes_filter.GetOutputPort())
actor = vtkActor()
actor.SetMapper(mapper)

renderer = vtkRenderer()
renderer.SetBackground(1, 1, 1)
renderer.AddActor(actor)

render_window = vtkRenderWindow()
render_window.AddRenderer(renderer)

rw_interactor = vtkRenderWindowInteractor()
rw_interactor.SetRenderWindow(render_window)
rw_interactor.GetInteractorStyle().SetCurrentStyleToTrackballCamera()

renderer.ResetCamera()

# -----------------------------------------------------------------------------
# GUI layout
# -----------------------------------------------------------------------------

with SinglePageLayout(server) as layout:
    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=(foo, "[$event]")
                )
                view.update
                view.reset_camera

# -----------------------------------------------------------------------------
# Main
# -----------------------------------------------------------------------------

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

Expected behavior

I expect that, upon clicking anywhere in the display, "hello" will be printed.
Screenshots

If applicable, add screenshots to help explain your problem (drag and drop the image).

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

The reason why it is failing is that $event is not serializable which through an exception on the JS side. We provide a helper to extract a serializable version of that event.

To fix your example, just replace that line

LeftButtonPress=(foo, "[utils.vtk.event($event)]")

You can see the documentation about it:

The working code base can be found here

Stellar, it now works! This was (hopefully) the last piece of the puzzle for an mvp with vtkRemoteView. (There's a separate issue I'll open for vtkLocalView). Thanks @jourdain!

Did you figure out the remaining part of your cell picking? Or are you still missing some details?

Hi @jourdain, are you referring to #178? If so, that problem remains unresolved. In that case I was using vtkView, but I've since switched to vtkRemoteView, and the problem has not yet shown up!

Ok sounds good.