Skip to content

Commit 1b2159d

Browse files
committed
fix(vtk): use vtk for rendering
1 parent d55b3e2 commit 1b2159d

File tree

2 files changed

+53
-35
lines changed

2 files changed

+53
-35
lines changed

src/e3sm_quickview/pipeline.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ def __init__(self, projection="Mollweide"):
143143
Translate=0,
144144
)
145145
self.geometry = simple.ExtractSurface(Input=self.proj)
146+
self.vtk_geometry = self.geometry.GetClientSideObject()
146147

147148
# Add observer to
148149
vtk_obj = self.reader.GetClientSideObject()

src/e3sm_quickview/view_manager.py

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
from trame.app import TrameComponent
55
from trame.decorators import controller
66
from trame.ui.html import DivLayout
7-
from trame.widgets import client, html
8-
from trame.widgets import paraview as pvw
7+
from trame.widgets import client, html, rca
98
from trame.widgets import vuetify3 as v3
109
from trame_dataclass.core import StateDataModel
10+
from vtkmodules.vtkRenderingCore import vtkActor, vtkPolyDataMapper
1111

1212
from e3sm_quickview.components import view as tview
1313
from e3sm_quickview.presets import COLOR_BLIND_SAFE
@@ -72,38 +72,45 @@ class ViewConfiguration(StateDataModel):
7272
class VariableView(TrameComponent):
7373
def __init__(self, server, source, variable_name, variable_type):
7474
super().__init__(server)
75-
self.config = ViewConfiguration(server, variable=variable_name)
7675
self.source = source
7776
self.variable_name = variable_name
7877
self.variable_type = variable_type
78+
self.disable_render = False
7979
self.name = f"view_{self.variable_name}"
80+
self.config = ViewConfiguration(server, variable=variable_name)
81+
82+
# ParaView
8083
self.view = simple.CreateRenderView()
81-
self.view.GetRenderWindow().SetOffScreenRendering(True)
8284
self.view.InteractionMode = "2D"
8385
self.view.OrientationAxesVisibility = 0
8486
self.view.UseColorPaletteForBackground = 0
8587
self.view.BackgroundColorMode = "Gradient"
8688
self.view.CameraParallelProjection = 1
87-
self.view.Size = 0 # make the interactive widget non responsive
88-
self.representation = simple.Show(
89-
proxy=source.views["atmosphere_data"],
90-
view=self.view,
91-
)
89+
90+
# VTK
91+
self._camera = self.view.GetActiveCamera()
92+
self.renderer = self.view.GetRenderer()
93+
self.render_window = self.view.GetRenderWindow()
94+
self.render_window.SetOffScreenRendering(True)
95+
96+
input = source.data_reader.vtk_geometry
97+
self.mapper = vtkPolyDataMapper(input_connection=input.output_port)
98+
self.actor = vtkActor(mapper=self.mapper)
99+
self.renderer.AddActor(self.actor)
92100

93101
# Lookup table color management
94-
simple.ColorBy(self.representation, ("CELLS", variable_name))
95102
self.lut = simple.GetColorTransferFunction(variable_name)
96103
self.lut.NanOpacity = 0.0
97104

98-
self.view.ResetActiveCameraToNegativeZ()
99-
self.view.ResetCamera(True, 0.9)
100-
self.disable_render = False
105+
# Color mapping
106+
self.mapper.SetScalarVisibility(1)
107+
self.mapper.SetScalarModeToUseCellFieldData()
108+
self.mapper.SelectColorArray(variable_name)
109+
self.mapper.SetLookupTable(self.lut.GetClientSideObject())
101110

102-
# Add annotation to the view
103-
# - continents
104-
self.view.GetRenderer().AddActor(source.continent.actor)
105-
# - gridlines
106-
self.view.GetRenderer().AddActor(source.grid_lines.actor)
111+
# Add annotation to the view (continents, gridlines)
112+
self.renderer.AddActor(source.continent.actor)
113+
self.renderer.AddActor(source.grid_lines.actor)
107114

108115
# Reactive behavior
109116
self.config.watch(
@@ -119,9 +126,15 @@ def __init__(self, server, source, variable_name, variable_type):
119126
eager=True,
120127
)
121128

129+
# Initial flush
130+
simple.Render(self.view)
131+
122132
# GUI
123133
self._build_ui()
124134

135+
# Need to be after RCA initialization (gui build)
136+
self.reset_camera()
137+
125138
def render(self):
126139
if self.disable_render or not self.ctx.has(self.name):
127140
return
@@ -132,13 +145,11 @@ def set_camera_modified(self, fn):
132145

133146
@property
134147
def camera(self):
135-
return self.view.GetActiveCamera()
148+
return self._camera
136149

137150
def reset_camera(self):
138-
self.view.InteractionMode = "2D"
139-
self.view.ResetActiveCameraToNegativeZ()
140151
self.view.ResetCamera(True, 0.9)
141-
self.ctx[self.name].update()
152+
self.render()
142153

143154
def update_color_preset(self, name, invert, log_scale, n_colors=255):
144155
self.config.preset = name
@@ -174,6 +185,12 @@ def color_range_str_to_float(self, color_value_min, color_value_max):
174185
if self.config.color_value_min_valid and self.config.color_value_max_valid:
175186
self.config.color_range = [min_value, max_value]
176187

188+
@property
189+
def data_array(self):
190+
self.source.data_reader.vtk_geometry.Update()
191+
ds = self.source.data_reader.vtk_geometry.GetOutput()
192+
return ds.GetCellData().GetArray(self.variable_name)
193+
177194
def update_color_range(self, *_):
178195
if self.config.override_range:
179196
skip_update = False
@@ -190,12 +207,7 @@ def update_color_range(self, *_):
190207

191208
self.lut.RescaleTransferFunction(*self.config.color_range)
192209
else:
193-
self.representation.RescaleTransferFunctionToDataRange(False, True)
194-
data_array = (
195-
self.source.views["atmosphere_data"]
196-
.GetCellDataInformation()
197-
.GetArray(self.variable_name)
198-
)
210+
data_array = self.data_array
199211
if data_array:
200212
data_range = data_array.GetRange()
201213
self.config.color_range = data_range
@@ -286,9 +298,16 @@ def _build_ui(self):
286298
""",
287299
),
288300
):
289-
pvw.VtkRemoteView(
290-
self.view, interactive_ratio=1, ctx_name=self.name
301+
display = rca.RemoteControlledArea(display="image")
302+
handler = display.create_view_handler(
303+
self.view.GetRenderWindow(),
304+
encoder="turbo-jpeg",
291305
)
306+
self.ctx[self.name] = handler
307+
308+
# pvw.VtkRemoteView(
309+
# self.view, interactive_ratio=1, ctx_name=self.name
310+
# )
292311

293312
tview.create_bottom_bar(self.config, self.update_color_preset)
294313

@@ -302,7 +321,7 @@ def __init__(self, server, source):
302321
self._last_vars = {}
303322
self._active_configs = {}
304323

305-
pvw.initialize(self.server)
324+
rca.initialize(self.server)
306325

307326
self.state.luts_normal = [
308327
{"name": k, "url": v["normal"], "safe": k in COLOR_BLIND_SAFE}
@@ -343,10 +362,8 @@ def update_color_range(self):
343362
def get_view(self, variable_name, variable_type):
344363
view = self._var2view.get(variable_name)
345364
if view is None:
346-
view = self._var2view.setdefault(
347-
variable_name,
348-
VariableView(self.server, self.source, variable_name, variable_type),
349-
)
365+
view = VariableView(self.server, self.source, variable_name, variable_type)
366+
self._var2view[variable_name] = view
350367
view.set_camera_modified(self.sync_camera)
351368

352369
return view

0 commit comments

Comments
 (0)