1
- import os
2
1
from trame .app import get_server
3
2
from trame .ui .html import DivLayout
4
- from trame .widgets import html , client , vtk as vtk_widgets
3
+ from trame .widgets import html , client
5
4
from trame_vtklocal .widgets import vtklocal
5
+ from trame .decorators import TrameApp , change
6
6
7
7
# Required for vtk factory
8
8
import vtkmodules .vtkRenderingOpenGL2 # noqa
9
9
from vtkmodules .vtkInteractionStyle import vtkInteractorStyleSwitch # noqa
10
10
11
11
from vtkmodules .vtkCommonColor import vtkNamedColors
12
12
from vtkmodules .vtkFiltersSources import vtkConeSource
13
- from vtkmodules .vtkInteractionWidgets import vtkBoxWidget2
14
- from vtkmodules .vtkCommonTransforms import vtkTransform
13
+ from vtkmodules .vtkInteractionWidgets import vtkBoxWidget2 , vtkBoxRepresentation
15
14
from vtkmodules .vtkRenderingCore import (
16
15
vtkActor ,
17
16
vtkPolyDataMapper ,
20
19
vtkRenderer ,
21
20
)
22
21
23
- WASM = "USE_WASM" in os .environ
24
-
25
-
26
- def box_callback (obj , event ):
27
- t = vtkTransform ()
28
- obj .representation .GetTransform (t )
29
- box_callback .actor .user_transform = t
30
-
31
22
32
23
def create_vtk_pipeline ():
33
24
colors = vtkNamedColors ()
@@ -40,7 +31,9 @@ def create_vtk_pipeline():
40
31
coneActor = vtkActor ()
41
32
coneActor .SetMapper (coneMapper )
42
33
coneActor .GetProperty ().SetColor (colors .GetColor3d ("BurlyWood" ))
43
- coneMapper .Update ()
34
+
35
+ cone .Update ()
36
+ input_bounds = cone .output .bounds
44
37
45
38
# A renderer and render window
46
39
renderer = vtkRenderer ()
@@ -49,58 +42,113 @@ def create_vtk_pipeline():
49
42
50
43
renwin = vtkRenderWindow ()
51
44
renwin .AddRenderer (renderer )
52
- renwin .SetWindowName ("BoxWidget" )
53
45
54
46
# An interactor
55
47
interactor = vtkRenderWindowInteractor ()
56
48
interactor .SetRenderWindow (renwin )
57
49
interactor .GetInteractorStyle ().SetCurrentStyleToTrackballCamera ()
58
50
59
51
# A Box widget
60
- boxWidget = vtkBoxWidget2 ()
61
- boxWidget .SetInteractor (interactor )
62
- boxWidget .representation .SetPlaceFactor (1.0 )
63
- boxWidget .representation .PlaceWidget (coneActor .bounds )
52
+ rep = vtkBoxRepresentation (place_factor = 2 )
53
+ rep .PlaceWidget (input_bounds )
64
54
65
- boxWidget . On ( )
55
+ boxWidget = vtkBoxWidget2 ( interactor = interactor , representation = rep )
66
56
67
- # Connect the event to a function
68
- if not WASM :
69
- box_callback .actor = coneActor
70
- boxWidget .AddObserver ("InteractionEvent" , box_callback )
57
+ renderer .ResetCamera ()
58
+ renwin .Render ()
71
59
72
- return renwin , boxWidget
60
+ boxWidget .On ()
61
+
62
+ return renwin , boxWidget , coneActor
73
63
74
64
75
65
# -----------------------------------------------------------------------------
76
66
# GUI
77
67
# -----------------------------------------------------------------------------
78
68
79
69
70
+ @TrameApp ()
80
71
class App :
81
72
def __init__ (self , server = None ):
82
73
self .server = get_server (server , client_type = "vue3" )
83
74
84
75
# enable shared array buffer
85
76
self .server .http_headers .shared_array_buffer = True
86
77
87
- self .render_window , self .widget = create_vtk_pipeline ()
78
+ # Allocation state variable for widget state
79
+ self .state .widget_state = None
80
+
81
+ self .render_window , self .widget , self .actor = create_vtk_pipeline ()
88
82
self .html_view = None
89
83
self .ui = self ._ui ()
90
84
85
+ @property
86
+ def state (self ):
87
+ return self .server .state
88
+
89
+ @change ("widget_state" )
90
+ def _on_widget_update (self , widget_state , ** _ ):
91
+ if widget_state is None :
92
+ return
93
+
94
+ print (f"{ widget_state = } " )
95
+
96
+ self .actor .user_transform .SetMatrix (widget_state .get ("transform" ))
97
+ self .html_view .render_throttle ()
98
+
99
+ def toggle_listeners (self ):
100
+ if self .state .wasm_listeners is not None and len (self .state .wasm_listeners ):
101
+ self .state .wasm_listeners = {}
102
+ else :
103
+ self .state .wasm_listeners = {
104
+ self .widget_id : {
105
+ "InteractionEvent" : {
106
+ "widget_state" : {
107
+ "transform" : (
108
+ self .widget_id ,
109
+ "WidgetRepresentation" ,
110
+ "Transform" ,
111
+ ),
112
+ }
113
+ }
114
+ }
115
+ }
116
+
117
+ def one_time_update (self ):
118
+ self .html_view .eval (
119
+ {
120
+ "widget_state" : {
121
+ "transform" : (
122
+ self .widget_id ,
123
+ "WidgetRepresentation" ,
124
+ "Transform" ,
125
+ ),
126
+ }
127
+ }
128
+ )
129
+
91
130
def _ui (self ):
92
131
with DivLayout (self .server ) as layout :
93
132
client .Style ("body { margin: 0; }" )
133
+ html .Button (
134
+ "Toggle listeners" ,
135
+ click = self .toggle_listeners ,
136
+ style = "position: absolute; left: 1rem; top: 1rem; z-index: 10;" ,
137
+ )
138
+ html .Button (
139
+ "Update cut" ,
140
+ click = self .one_time_update ,
141
+ style = "position: absolute; right: 1rem; top: 1rem; z-index: 10;" ,
142
+ )
94
143
with html .Div (
95
144
style = "position: absolute; left: 0; top: 0; width: 100vw; height: 100vh;"
96
145
):
97
- if WASM :
98
- self .html_view = vtklocal .LocalView (self .render_window )
99
- self .html_view .register_widget (self .widget )
100
- else :
101
- self .html_view = vtk_widgets .VtkRemoteView (
102
- self .render_window , interactive_ratio = 1
103
- )
146
+ self .html_view = vtklocal .LocalView (
147
+ self .render_window ,
148
+ throttle_rate = 20 ,
149
+ listeners = ("wasm_listeners" , {}),
150
+ )
151
+ self .widget_id = self .html_view .register_widget (self .widget )
104
152
105
153
return layout
106
154
0 commit comments