Skip to content

Commit f2a89c9

Browse files
committed
fix(api): update listeners structure
1 parent 784675e commit f2a89c9

File tree

3 files changed

+113
-81
lines changed

3 files changed

+113
-81
lines changed

examples/vtk/widgets_plane.py

Lines changed: 46 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@
3232

3333
def create_vtk_pipeline(file_to_load):
3434
colors = vtkNamedColors()
35-
sphere_source = vtkSphereSource()
36-
sphere_source.SetRadius(10.0)
37-
sphere_source.Update()
38-
input_bounds = sphere_source.GetOutput().GetBounds()
3935

4036
fp = None
4137
if file_to_load:
@@ -46,59 +42,49 @@ def create_vtk_pipeline(file_to_load):
4642
return
4743

4844
# Setup a visualization pipeline.
49-
plane = vtkPlane()
50-
clipper = vtkClipPolyData()
51-
clipper.SetClipFunction(plane)
52-
clipper.InsideOutOn()
53-
if file_to_load:
54-
reader = vtkXMLPolyDataReader()
55-
reader.SetFileName(fp)
56-
reader.Update()
45+
source = (
46+
vtkXMLPolyDataReader(file_name=fp)
47+
if file_to_load
48+
else vtkSphereSource(radius=10.0)
49+
)
50+
source.Update()
51+
52+
input_bounds = source.output.bounds
53+
plane = vtkPlane(
54+
origin=(
55+
0.5 * (input_bounds[0] + input_bounds[1]),
56+
0.5 * (input_bounds[2] + input_bounds[3]),
57+
0.5 * (input_bounds[4] + input_bounds[5]),
58+
)
59+
)
5760

58-
input_bounds = reader.GetOutput().GetBounds()
59-
clipper.SetInputConnection(reader.GetOutputPort())
60-
else:
61-
clipper.SetInputConnection(sphere_source.GetOutputPort())
61+
clipper = vtkClipPolyData(
62+
clip_function=plane, inside_out=1, input_connection=source.output_port
63+
)
6264

6365
# Create a mapper and actor.
64-
mapper = vtkPolyDataMapper()
65-
mapper.SetInputConnection(clipper.GetOutputPort())
66-
actor = vtkActor()
67-
actor.SetMapper(mapper)
68-
69-
back_faces = vtkProperty()
70-
back_faces.SetDiffuseColor(colors.GetColor3d("Gold"))
71-
72-
actor.SetBackfaceProperty(back_faces)
66+
mapper = vtkPolyDataMapper(input_connection=clipper.output_port)
67+
back_faces = vtkProperty(diffuse_color=colors.GetColor3d("Gold"))
68+
actor = vtkActor(mapper=mapper, backface_property=back_faces)
7369

7470
# A renderer and render window
75-
renderer = vtkRenderer()
71+
renderer = vtkRenderer(background=colors.GetColor3d("SlateGray"))
72+
renderer.AddActor(actor)
7673
ren_win = vtkRenderWindow()
7774
ren_win.AddRenderer(renderer)
78-
ren_win.SetWindowName("ImplicitPlaneWidget2")
79-
80-
renderer.AddActor(actor)
81-
renderer.SetBackground(colors.GetColor3d("SlateGray"))
8275

8376
# An interactor
84-
iren = vtkRenderWindowInteractor()
77+
iren = vtkRenderWindowInteractor(render_window=ren_win)
8578
iren.GetInteractorStyle().SetCurrentStyleToTrackballCamera()
86-
iren.SetRenderWindow(ren_win)
8779

88-
rep = vtkImplicitPlaneRepresentation()
89-
rep.SetPlaceFactor(1.25) # This must be set prior to placing the widget
90-
rep.PlaceWidget(input_bounds)
91-
plane.SetOrigin(
92-
0.5 * (input_bounds[0] + input_bounds[1]),
93-
0.5 * (input_bounds[2] + input_bounds[3]),
94-
0.5 * (input_bounds[4] + input_bounds[5]),
80+
rep = vtkImplicitPlaneRepresentation(
81+
place_factor=1.25,
9582
)
96-
rep.SetNormal(plane.GetNormal())
97-
rep.SetOrigin(plane.GetOrigin())
83+
rep.PlaceWidget(input_bounds)
84+
rep.normal = plane.normal
85+
rep.origin = plane.origin
9886

99-
plane_widget = vtkImplicitPlaneWidget2()
100-
plane_widget.SetInteractor(iren)
101-
plane_widget.SetRepresentation(rep)
87+
plane_widget = vtkImplicitPlaneWidget2(interactor=iren, representation=rep)
10288

10389
renderer.ResetCamera(input_bounds)
10490
ren_win.Render()
@@ -142,8 +128,8 @@ def _on_widget_update(self, plane_widget, **_):
142128
return
143129

144130
# update cutting plane
145-
self.plane.SetNormal(plane_widget.get("normal"))
146-
self.plane.SetOrigin(plane_widget.get("origin"))
131+
self.plane.normal = plane_widget.get("normal")
132+
self.plane.origin = plane_widget.get("origin")
147133

148134
# prevent requesting geometry too often
149135
self.html_view.render_throttle()
@@ -152,30 +138,31 @@ def toggle_listeners(self):
152138
if self.state.wasm_listeners is not None and len(self.state.wasm_listeners):
153139
self.state.wasm_listeners = {}
154140
else:
155-
widget_id = self.html_view.get_wasm_id(self.widget)
156-
rep_id = self.html_view.get_wasm_id(self.widget.representation)
157141
self.state.wasm_listeners = {
158-
widget_id: {
142+
self.widget_id: {
159143
"InteractionEvent": {
160144
"plane_widget": {
161-
rep_id: {
162-
"Normal": "normal",
163-
"Origin": "origin",
164-
}
145+
"normal": (
146+
self.widget_id,
147+
"WidgetRepresentation",
148+
"Normal",
149+
),
150+
"origin": (
151+
self.widget_id,
152+
"WidgetRepresentation",
153+
"Origin",
154+
),
165155
}
166156
}
167157
}
168158
}
169159

170160
def one_time_update(self):
171-
rep_id = self.html_view.get_wasm_id(self.widget.representation)
172161
self.html_view.eval(
173162
{
174163
"plane_widget": {
175-
rep_id: {
176-
"Normal": "normal",
177-
"Origin": "origin",
178-
}
164+
"origin": (self.widget_id, "WidgetRepresentation", "Origin"),
165+
"normal": (self.widget_id, "WidgetRepresentation", "Normal"),
179166
}
180167
}
181168
)
@@ -201,7 +188,7 @@ def _ui(self):
201188
throttle_rate=20,
202189
listeners=("wasm_listeners", {}),
203190
)
204-
self.html_view.register_widget(self.widget)
191+
self.widget_id = self.html_view.register_widget(self.widget)
205192

206193
return layout
207194

trame_vtklocal/widgets/vtklocal.py

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,34 @@ def get_version():
4545

4646

4747
class LocalView(HtmlElement):
48+
"""
49+
LocalView allow to mirror a server side vtkRenderWindow on the client side using VTK.wasm.
50+
51+
Parameters
52+
53+
:param render_window: Specify the VTK window to mirror
54+
:type vtkRenderWindow:
55+
:param throttle_rate: Number of update per second the render_throttle() method will actually perform.
56+
:type number:
57+
58+
Properties
59+
60+
:param cache_size: Size of client side cache for geometry and arrays in Bytes.
61+
:type number:
62+
:param eager_sync: If enabled, the server will push states rather than waiting for the client to request them. Usually improve fast update behavior.
63+
:type bool:
64+
:param listeners: Dynamic structure describing what to observe and how to map internal WASM state to trame state variable.
65+
:type dict:
66+
67+
Events
68+
69+
:param updated: Emitted after each completed client side update.
70+
:param memory_vtk: Event which provides the current memory used by vtk object structures.
71+
:param memory_arrays: Event which provides the current memory used by vtk arrays.
72+
:param camera: Event emitted when any camera is changed. The actual state of the camera is passed as arg.
73+
74+
"""
75+
4876
_next_id = 0
4977

5078
def __init__(self, render_window, throttle_rate=10, **kwargs):
@@ -75,9 +103,9 @@ def __init__(self, render_window, throttle_rate=10, **kwargs):
75103
]
76104
self._event_names += [
77105
"updated",
106+
"camera",
78107
("memory_vtk", "memory-vtk"),
79108
("memory_arrays", "memory-arrays"),
80-
("camera", "camera"),
81109
]
82110

83111
# Generate throttle update function
@@ -99,14 +127,9 @@ def eval(self, state_mapping):
99127
100128
state_mapping = {
101129
trame_state_name: {
102-
wasm_id1: {
103-
wasm_state_prop_name: js_name_in_trame_state_name_obj1
104-
wasm_state_prop_name2: js_name2_in_trame_state_name_obj1
105-
},
106-
wasm_id2: {
107-
wasm_state_prop_name: js_name_in_trame_state_name_obj2
108-
wasm_state_prop_name2: js_name2_in_trame_state_name_obj2
109-
},
130+
prop_name1: (wasm_id, "PropName"),
131+
origin: (wasm_id, "WidgetRepresentation", "origin"),
132+
widget_state: widget_id,
110133
}
111134
}
112135
"""
@@ -118,12 +141,14 @@ def update(self, push_camera=False):
118141
self.server.js_call(self.__ref, "update")
119142

120143
def register_widget(self, w):
121-
"""Register external element (i.e. widget) into the scene so it can be managed"""
144+
"""Register external element (i.e. widget) into the scene so it can be managed and return its wasm_id"""
122145
if w not in self.__registered_obj:
123146
self.api.register_widget(self._render_window, w)
124147
self.__registered_obj.append(w)
125148
self.api.update()
126149

150+
return self.get_wasm_id(w)
151+
127152
def uregister_widgets(self):
128153
"""Unregister external element (i.e. widget) from the scene so it can removed from tracking"""
129154
for w in self.__registered_obj:

vue-components/src/components/VtkLocal.js

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,41 @@ function idToState(sceneManager, cid) {
1515
return sceneManager.getState(wasmId);
1616
}
1717

18+
function createStateHelper(sceneManager) {
19+
const cache = {};
20+
21+
return function getState(wasm_id) {
22+
if (!cache[wasm_id]) {
23+
cache[wasm_id] = idToState(sceneManager, wasm_id);
24+
}
25+
return cache[wasm_id];
26+
};
27+
}
28+
29+
function getStatePathToValue(getStateFn, statePath) {
30+
const expression = Array.isArray(statePath) ? statePath : [statePath];
31+
let value = null;
32+
for (let i = 0; i < expression.length; i++) {
33+
const token = expression[i];
34+
if (i === 0) {
35+
value = getStateFn(token);
36+
} else {
37+
value = value[token];
38+
if (value.Id) {
39+
value = getStateFn(value.Id);
40+
}
41+
}
42+
}
43+
return value;
44+
}
45+
1846
function createExtractCallback(trame, sceneManager, extractInfo) {
1947
return function () {
20-
for (const [name, objIds] of Object.entries(extractInfo)) {
48+
const getState = createStateHelper(sceneManager);
49+
for (const [name, props] of Object.entries(extractInfo)) {
2150
const value = {};
22-
for (const [objId, props] of Object.entries(objIds)) {
23-
const state = idToState(sceneManager, objId);
24-
if (typeof props === "string") {
25-
value[props] = state;
26-
} else {
27-
// extract and remap
28-
for (const [k, v] of Object.entries(props)) {
29-
value[v] = state[k];
30-
}
31-
}
51+
for (const [propName, statePath] of Object.entries(props)) {
52+
value[propName] = getStatePathToValue(getState, statePath);
3253
}
3354
trame.state.set(name, value);
3455
}
@@ -369,7 +390,6 @@ export default {
369390
// Public -----------------------------------------------------------------
370391

371392
function evalStateExtract(definition) {
372-
console.log("definition", definition);
373393
createExtractCallback(trame, sceneManager, definition)();
374394
}
375395

0 commit comments

Comments
 (0)