Skip to content

Commit d4c53e2

Browse files
author
Xing Han Lu
authored
Merge pull request #588 from plotly/add-vehicle-geometry
Add vehicle geometry app (#minor) Former-commit-id: 0227075
2 parents 23a4988 + 24bce6b commit d4c53e2

25 files changed

+268
-0
lines changed

apps/dash-vehicle-geometry/Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: gunicorn app:server

apps/dash-vehicle-geometry/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# plotly-vtk

apps/dash-vehicle-geometry/app.py

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
import os
2+
import glob
3+
import random
4+
5+
import dash
6+
import dash_bootstrap_components as dbc
7+
import dash_html_components as html
8+
import dash_core_components as dcc
9+
10+
from dash.dependencies import Input, Output, State
11+
12+
import dash_vtk
13+
from dash_vtk.utils import to_mesh_state, preset_as_options
14+
15+
import vtk
16+
17+
DATA_PATH = "data"
18+
19+
# -----------------------------------------------------------------------------
20+
# Helper functions
21+
# -----------------------------------------------------------------------------
22+
23+
24+
def _load_vtp(filepath, fieldname=None):
25+
reader = vtk.vtkXMLPolyDataReader()
26+
reader.SetFileName(filepath)
27+
reader.Update()
28+
if fieldname is None:
29+
return to_mesh_state(reader.GetOutput())
30+
else:
31+
return to_mesh_state(reader.GetOutput(), fieldname)
32+
33+
34+
# -----------------------------------------------------------------------------
35+
# GUI setup
36+
# -----------------------------------------------------------------------------
37+
38+
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
39+
server = app.server
40+
41+
# -----------------------------------------------------------------------------
42+
# Populate scene
43+
# -----------------------------------------------------------------------------
44+
45+
# vehicle geometry
46+
vehicle_vtk = []
47+
for filename in glob.glob(os.path.join(DATA_PATH, "vehicle") + "/*.vtp"):
48+
mesh = _load_vtp(filename)
49+
part_name = filename.split("/")[-1].replace(".vtp", "")
50+
child = dash_vtk.GeometryRepresentation(
51+
id=f"{part_name}-rep",
52+
colorMapPreset="erdc_rainbow_bright",
53+
colorDataRange=[0, 100],
54+
property={"opacity": 1},
55+
children=[dash_vtk.Mesh(id=f"{part_name}-mesh", state=mesh,)],
56+
)
57+
vehicle_vtk.append(child)
58+
59+
# isosurfaces
60+
isosurfs_vtk = []
61+
for filename in glob.glob(os.path.join(DATA_PATH, "isosurfaces") + "/*.vtp"):
62+
mesh = _load_vtp(filename)
63+
64+
surf_name = filename.split("/")[-1].replace(".vtp", "")
65+
child = dash_vtk.GeometryRepresentation(
66+
id=f"{surf_name}-rep",
67+
property={"opacity": 0, "color": [1, 0, 0]},
68+
children=[dash_vtk.Mesh(id=f"{surf_name}-mesh", state=mesh,)],
69+
)
70+
71+
isosurfs_vtk.append(child)
72+
73+
# -----------------------------------------------------------------------------
74+
# 3D Viz
75+
# -----------------------------------------------------------------------------
76+
77+
vtk_view = dash_vtk.View(id="vtk-view", children=vehicle_vtk + isosurfs_vtk)
78+
79+
# -----------------------------------------------------------------------------
80+
# Control UI
81+
# -----------------------------------------------------------------------------
82+
83+
controls = [
84+
dbc.Card(
85+
[
86+
dbc.CardHeader("Geometry"),
87+
dbc.CardBody(
88+
[
89+
dcc.Checklist(
90+
id="geometry",
91+
options=[
92+
{"label": " body", "value": "body"},
93+
{"label": " drivetrain", "value": "drive-train"},
94+
{"label": " front-wing", "value": "front-wing"},
95+
{"label": " rear-wing", "value": "rear-wing"},
96+
],
97+
labelStyle={"display": "block"},
98+
value=["body", "drive-train", "front-wing", "rear-wing"],
99+
),
100+
]
101+
),
102+
]
103+
),
104+
html.Br(),
105+
dbc.Card(
106+
[
107+
dbc.CardHeader("Surface Coloring"),
108+
dbc.CardBody(
109+
[
110+
dcc.Dropdown(
111+
id="surfcolor",
112+
options=[
113+
{"label": "solid", "value": "solid"},
114+
{"label": "U", "value": "U"},
115+
],
116+
value="solid",
117+
),
118+
]
119+
),
120+
]
121+
),
122+
html.Br(),
123+
dbc.Card(
124+
[
125+
dbc.CardHeader("Isosurfaces"),
126+
dbc.CardBody(
127+
[
128+
dcc.Checklist(
129+
id="isosurfaces",
130+
options=[{"label": " Cp", "value": "cp"}],
131+
labelStyle={"display": "block"},
132+
value=[],
133+
),
134+
]
135+
),
136+
]
137+
),
138+
]
139+
140+
# -----------------------------------------------------------------------------
141+
# App UI
142+
# -----------------------------------------------------------------------------
143+
144+
app.layout = dbc.Container(
145+
fluid=True,
146+
children=[
147+
html.H2("Vehicle Geometry with OpenFOAM"),
148+
html.Hr(),
149+
dbc.Row(
150+
[
151+
dbc.Col(width=4, children=controls),
152+
dbc.Col(
153+
width=8,
154+
children=[
155+
html.Div(vtk_view, style={"height": "100%", "width": "100%"})
156+
],
157+
),
158+
],
159+
style={"margin-top": "15px", "height": "calc(100vh - 230px)"},
160+
),
161+
],
162+
)
163+
164+
# -----------------------------------------------------------------------------
165+
# Handle controls
166+
# -----------------------------------------------------------------------------
167+
168+
169+
@app.callback(
170+
[Output("vtk-view", "triggerRender")]
171+
+ [Output(item.id.replace("rep", "mesh"), "state") for item in vehicle_vtk]
172+
+ [Output(item.id, "property") for item in vehicle_vtk]
173+
+ [Output("cp-rep", "property")],
174+
[
175+
Input("geometry", "value"),
176+
Input("isosurfaces", "value"),
177+
Input("surfcolor", "value"),
178+
],
179+
)
180+
def update_scene(geometry, isosurfaces, surfcolor):
181+
triggered = dash.callback_context.triggered
182+
183+
# update geometry visibility
184+
geo_viz, iso_viz = [], []
185+
if triggered and "geometry" in triggered[0]["prop_id"]:
186+
geo_viz = [
187+
{"opacity": 1}
188+
if part.id.replace("-rep", "").split("_")[0] in triggered[0]["value"]
189+
else {"opacity": 0}
190+
for part in vehicle_vtk
191+
]
192+
else:
193+
geo_viz = [dash.no_update for item in vehicle_vtk]
194+
195+
# update isosurface visibility
196+
if triggered and "isosurfaces" in triggered[0]["prop_id"]:
197+
if "cp" in triggered[0]["value"]:
198+
iso_viz = {"opacity": 1}
199+
else:
200+
iso_viz = {"opacity": 0}
201+
else:
202+
iso_viz = dash.no_update
203+
204+
# update surface coloring
205+
if triggered and "surfcolor" in triggered[0]["prop_id"]:
206+
surf_state = []
207+
208+
for filename in glob.glob(os.path.join(DATA_PATH, "vehicle") + "/*.vtp"):
209+
if triggered[0]["value"] == "solid":
210+
mesh = _load_vtp(filename)
211+
else:
212+
mesh = _load_vtp(filename, triggered[0]["value"])
213+
surf_state.append(mesh)
214+
else:
215+
surf_state = [dash.no_update for item in vehicle_vtk]
216+
217+
return [random.random()] + surf_state + geo_viz + [iso_viz]
218+
219+
220+
# -----------------------------------------------------------------------------
221+
222+
if __name__ == "__main__":
223+
app.run_server(debug=True)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
libgl1-mesa-glx

apps/dash-vehicle-geometry/assets/placeholder.txt

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
82b0e7fd328e5ab6d25251545f1d1f9bc97e0521
Binary file not shown.
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
b15faf32340dd4eb1368972865a74ce92e9ce5d5
Binary file not shown.

0 commit comments

Comments
 (0)