Skip to content

Commit

Permalink
Merge pull request #7 from Kitware/fix-incremental-state
Browse files Browse the repository at this point in the history
fix(LocalView): Properly handle add/remove actor
  • Loading branch information
jourdain committed Nov 5, 2022
2 parents 6b5da52 + 2ee50c5 commit 6c370c6
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 10 deletions.
147 changes: 147 additions & 0 deletions examples/validation/AddRemoveActors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
from trame.app import get_server
from trame.widgets import vuetify, vtk as vtk_widgets
from trame.ui.vuetify import SinglePageLayout

from vtkmodules.vtkFiltersModeling import vtkOutlineFilter
from vtkmodules.vtkCommonDataModel import vtkPolyData
from vtkmodules.vtkFiltersSources import vtkConeSource, vtkSphereSource
from vtkmodules.vtkRenderingCore import (
vtkRenderer,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkPolyDataMapper,
vtkActor,
)
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleSwitch # noqa

# -----------------------------------------------------------------------------
# Trame initialization
# -----------------------------------------------------------------------------

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

state.trame__title = "VTK Remote View - Local Rendering"

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

DEFAULT_RESOLUTION = 6

renderer = vtkRenderer()
renderWindow = vtkRenderWindow()
renderWindow.AddRenderer(renderer)

renderWindowInteractor = vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderWindowInteractor.GetInteractorStyle().SetCurrentStyleToTrackballCamera()


def create_pipeline(source):
mapper = vtkPolyDataMapper()
actor = vtkActor()
if hasattr(source, "GetOutputPort"):
mapper.SetInputConnection(source.GetOutputPort())
else:
mapper.SetInputData(source)
actor.SetMapper(mapper)
return actor


cone_source = vtkConeSource()
cone_actor = create_pipeline(cone_source)
renderer.AddActor(cone_actor)

sphere_source = vtkSphereSource()
sphere_actor = create_pipeline(sphere_source)
renderer.AddActor(sphere_actor)

# Dummy actor
filter = vtkOutlineFilter()
filter.SetInputConnection(cone_source.GetOutputPort())
renderer.AddActor(create_pipeline(filter))

renderer.ResetCamera()
renderWindow.Render()


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


@state.change("resolution")
def update_cone(resolution=DEFAULT_RESOLUTION, **kwargs):
cone_source.SetResolution(resolution)
ctrl.view_update()


def update_reset_resolution():
state.resolution = DEFAULT_RESOLUTION


@state.change("show_cone")
def update_cone(show_cone, **kwargs):
if show_cone:
renderer.AddActor(cone_actor)
else:
renderer.RemoveActor(cone_actor)
ctrl.view_update()


@state.change("show_sphere")
def update_cone(show_sphere, **kwargs):
if show_sphere:
renderer.AddActor(sphere_actor)
else:
renderer.RemoveActor(sphere_actor)
ctrl.view_update()


# -----------------------------------------------------------------------------
# GUI
# -----------------------------------------------------------------------------

with SinglePageLayout(server) as layout:
layout.icon.click = ctrl.view_reset_camera
layout.title.set_text("Cone Application")

with layout.toolbar:
vuetify.VSpacer()
vuetify.VSlider(
v_model=("resolution", DEFAULT_RESOLUTION),
min=3,
max=60,
step=1,
hide_details=True,
dense=True,
style="max-width: 300px",
)
vuetify.VDivider(vertical=True, classes="mx-2")
with vuetify.VBtn(icon=True, click=update_reset_resolution):
vuetify.VIcon("mdi-undo-variant")

vuetify.VCheckbox(
v_model=("show_cone", True), label="Cone", dense=True, hide_details=True
)
vuetify.VCheckbox(
v_model=("show_sphere", True), label="Sphere", dense=True, hide_details=True
)

with layout.content:
with vuetify.VContainer(
fluid=True,
classes="pa-0 fill-height",
):
view = vtk_widgets.VtkLocalView(renderWindow, ref="view")
ctrl.view_update = view.update
ctrl.view_reset_camera = view.reset_camera


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

if __name__ == "__main__":
server.start()
8 changes: 4 additions & 4 deletions trame_vtk/modules/paraview/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def mesh(self, proxy, field_to_keep=None, point_arrays=None, cell_arrays=None):
cell_arrays=cell_arrays,
)

def scene(self, view_proxy):
def scene(self, view_proxy, new_state=False):
# flush data without requiring a render/picture
tmp = view_proxy.SuppressRendering
view_proxy.SuppressRendering = 1
Expand All @@ -63,7 +63,7 @@ def scene(self, view_proxy):
view_proxy.SuppressRendering = tmp

return self._app.protocol_call(
"viewport.geometry.view.get.state", self.id(view_proxy), True
"viewport.geometry.view.get.state", self.id(view_proxy), new_state
)

def push_image(self, view_proxy, reset_camera=False):
Expand Down Expand Up @@ -201,8 +201,8 @@ def mesh(dataset, field_to_keep=None, point_arrays=None, cell_arrays=None):
return HELPER.mesh(dataset, field_to_keep, point_arrays, cell_arrays)


def scene(render_window, reset_camera=False):
scene_state = HELPER.scene(render_window)
def scene(render_window, reset_camera=False, new_state=True):
scene_state = HELPER.scene(render_window, new_state)
if reset_camera:
scene_state.setdefault("extra", {})["resetCamera"] = 1
return scene_state
Expand Down
8 changes: 4 additions & 4 deletions trame_vtk/modules/vtk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ def mesh(self, dataset, field_to_keep=None, point_arrays=None, cell_arrays=None)
cell_arrays=cell_arrays,
)

def scene(self, render_window):
def scene(self, render_window, new_state=False):
return self._app.protocol_call(
"viewport.geometry.view.get.state", self.id(render_window), True
"viewport.geometry.view.get.state", self.id(render_window), new_state
)

def push_image(self, render_window, reset_camera=False):
Expand Down Expand Up @@ -205,8 +205,8 @@ def mesh(dataset, field_to_keep=None, point_arrays=None, cell_arrays=None):
return HELPER.mesh(dataset, field_to_keep, point_arrays, cell_arrays)


def scene(render_window, reset_camera=False):
scene_state = HELPER.scene(render_window)
def scene(render_window, reset_camera=False, new_state=True):
scene_state = HELPER.scene(render_window, new_state)
if reset_camera:
scene_state.setdefault("extra", {})["resetCamera"] = 1
return scene_state
Expand Down
17 changes: 15 additions & 2 deletions trame_vtk/widgets/vtk/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@ def __init__(self, view, ref="view", **kwargs):

MODULE.has_capabilities("web")

self._progressive_state = False
self.__scene_id = f"scene_{ref}"
self.__view = view
self.__ref = ref
Expand Down Expand Up @@ -693,13 +694,25 @@ def __init__(self, view, ref="view", **kwargs):
"EndInteraction",
]
self.update()
self._server.controller.on_server_ready.add(self.update)
self._server.controller.on_server_ready.add(self._ready)

def _ready(self, **kwargs):
self.progressive_state(False)
self.progressive_state(True)

def update(self, **kwargs):
"""
Force geometry to be pushed
"""
self.server.state[self.__scene_id] = MODULE.scene(self.__view)
self.server.state[self.__scene_id] = MODULE.scene(
self.__view,
new_state=not self._progressive_state,
)

def progressive_state(self, value=True):
self._progressive_state = value
if not value:
self.update()

def reset_camera(self, **kwargs):
"""
Expand Down

0 comments on commit 6c370c6

Please sign in to comment.