Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions examples/validation/stale_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import time

import vtkmodules.vtkInteractionStyle # noqa: F401
import vtkmodules.vtkRenderingOpenGL2 # noqa: F401

from vtkmodules.vtkCommonCore import vtkSMPTools
from vtkmodules.vtkFiltersCore import vtkFlyingEdges3D
from vtkmodules.vtkFiltersModeling import vtkOutlineFilter
from vtkmodules.vtkImagingCore import vtkRTAnalyticSource
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkPolyDataMapper,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkRenderer,
)

from trame.app import TrameApp
from trame.ui.html import DivLayout
from trame.widgets import html, client, vtklocal
from trame.decorators import change

# -----------------------------------------------------------------------------
# User settings
# -----------------------------------------------------------------------------
DIMENSION = 100 # Drive data size
HARD_UPDATE = False # toggle between force update or throttle [need to be true to trigger stale state]
THROTTLE_RATE = 20 # time per seconds
MAX_MEMORY_USAGE = (2_000_000_000,) # 2 GB
# -----------------------------------------------------------------------------
print(
"Volume size: "
f"{2 * DIMENSION} x {2 * DIMENSION} x {DIMENSION} = "
f"{2 * DIMENSION * 2 * DIMENSION * DIMENSION}"
)
# -----------------------------------------------------------------------------

# Enable threading in VTK
smp = vtkSMPTools()
smp.SetBackend("STDThread")


class ContourApp(TrameApp):
def __init__(self, server=None):
super().__init__(server)
self._setup_vtk()
self._build_ui()

def _setup_vtk(self):
renderer = vtkRenderer()
render_window = vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window.OffScreenRenderingOn()

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

source = vtkRTAnalyticSource(
whole_extent=(-DIMENSION, DIMENSION, -DIMENSION, DIMENSION, 0, DIMENSION),
)

iso = vtkFlyingEdges3D()
iso.SetValue(0, 150)
isoMapper = vtkPolyDataMapper()
isoMapper.SetInputConnection(iso.GetOutputPort())
isoMapper.ScalarVisibilityOff()
source >> iso >> isoMapper

outline = vtkOutlineFilter()
outlineMapper = vtkPolyDataMapper()
source >> outline >> outlineMapper

renderer.AddActor(vtkActor(mapper=outlineMapper))
renderer.AddActor(vtkActor(mapper=isoMapper))

self.render_window = render_window
self.contour = iso

def _build_ui(self):
self.state.mem_vtk = 0
self.state.mem_total = 0
with DivLayout(self.server) as self.ui:
client.Style("html,body{margin:0;padding:0}")
self.ui.root.style = "height:100vh"
vtklocal.LocalView(
self.render_window,
ctx_name="view",
throttle_rate=THROTTLE_RATE,
cache_size=MAX_MEMORY_USAGE,
emit_memory=True,
memory_vtk="mem_vtk = $event",
memory_arrays="mem_total = $event",
)

with html.Div(
style="position:absolute;top:1rem;left:1rem;right:1rem;z-index:100;"
):
html.Input(
type="range",
v_model_number=("contour", 150),
min="35",
max="260",
step="1",
style="width: 100%;",
)
html.Div(
"{{ utils.fmt.bytes(mem_vtk) }} / {{ utils.fmt.bytes(mem_total) }}",
style="color: white;",
)

@change("contour")
def _on_contour(self, contour, **_):
self.contour.SetValue(0, contour)
t0 = time.perf_counter()
self.contour.Update()
t1 = time.perf_counter()
print(f"Computed in {t1 - t0:.3f}s")

if HARD_UPDATE:
self.ctx.view.update()
else:
self.ctx.view.update_throttle()


def main():
app = ContourApp()
app.server.start()


if __name__ == "__main__":
main()
22 changes: 18 additions & 4 deletions src/trame_vtklocal/module/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,25 @@ def get_batch(self, state_ids, hash_keys):
chunk_threshold = int(os.environ.get("WSLINK_MAX_MSG_SIZE", "4194304"))
next_hashes = []
hashes = {}
states = [
json.loads(self.vtk_object_manager.GetState(obj_id)) for obj_id in state_ids
]
states = []

for obj_id in state_ids:
state = json.loads(self.vtk_object_manager.GetState(obj_id))
if state:
states.append(state)
else:
# Abort as the state is stale
return {
"states": [],
"hashes": {},
"next": False,
"skip": True,
}

for hash in hash_keys:
if blob_chunk_size < chunk_threshold:
blob = memoryview(self.vtk_object_manager.GetBlob(hash))
array = self.vtk_object_manager.GetBlob(hash)
blob = memoryview(array)
blob_chunk_size += blob.nbytes
hashes[hash] = blob
else:
Expand Down Expand Up @@ -238,6 +251,7 @@ def get_status(self, obj_id):
else:
force_push.append(cid)
cameras.append(cid)

return dict(
ids=ids_mtime,
hashes=hashes,
Expand Down
8 changes: 4 additions & 4 deletions vue-components/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vue-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"vue": "^2.7.0 || >=3.0.0"
},
"dependencies": {
"@kitware/vtk-wasm": "^3.0.1"
"@kitware/vtk-wasm": "^3.0.2"
},
"devDependencies": {
"@eslint/js": "^9.22.0",
Expand Down
Loading