Skip to content

Commit 8ad8b43

Browse files
committed
refactoring of the reference mesh (shape mesher without pyvista)
1 parent df10732 commit 8ad8b43

File tree

11 files changed

+93
-103
lines changed

11 files changed

+93
-103
lines changed

docs/scripts/generate_example.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ def run_image(folder_example):
3939
data_viewer["domain"]["data_options"]["plot_theme"]["background_color"] = "white"
4040
data_viewer["domain"]["data_options"]["plot_theme"]["axis_add"] = False
4141
data_viewer["domain"]["data_options"]["plot_view"]["grid_plot"] = False
42-
data_viewer["domain"]["data_options"]["plot_view"]["geom_plot"] = False
42+
data_viewer["domain"]["data_options"]["plot_view"]["voxel_plot"] = False
4343
data_viewer["domain"]["data_options"]["plot_view"]["point_plot"] = False
4444
data_viewer["domain"]["data_plot"]["title"] = None
4545

4646
# run the mesher
4747
data_voxel = pypeec.run_mesher_data(data_geometry)
4848

4949
# run the viewer
50-
pypeec.run_viewer_data(data_voxel, data_viewer, tag_plot=["domain"])
50+
pypeec.run_viewer_data(data_voxel, data_viewer, tag_plot=["domain"], plot_mode="qt")
5151

5252

5353
if __name__ == "__main__":

examples/config/cfg_data_pyvista.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@
2828
"grid_thickness": 1.0 # line thickness for the complete voxel geometry
2929
"grid_color": "black" # line opacity for the complete voxel geometry
3030
"grid_opacity": 0.1 # line color for the complete voxel geometry
31-
"geom_plot": true # plot (or not) the non-empty voxels as wireframe
32-
"geom_thickness": 1.0 # line thickness for the non-empty voxels
33-
"geom_color": "black" # line color for the non-empty voxels
34-
"geom_opacity": 0.1 # line opacity for the non-empty voxels
31+
"voxel_plot": true # plot (or not) the non-empty voxels as wireframe
32+
"voxel_thickness": 1.0 # line thickness for the non-empty voxels
33+
"voxel_color": "black" # line color for the non-empty voxels
34+
"voxel_opacity": 0.1 # line opacity for the non-empty voxels
3535
"point_plot": true # plot (or not) the provided point cloud as dots
3636
"point_color": "red" # color of the point cloud dots
3737
"point_size": 8.0 # size of the point cloud dots

pypeec/data/schema_plot_pyvista.yaml

+8-8
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@
6868
- "grid_thickness"
6969
- "grid_color"
7070
- "grid_opacity"
71-
- "geom_plot"
72-
- "geom_thickness"
73-
- "geom_color"
74-
- "geom_opacity"
71+
- "voxel_plot"
72+
- "voxel_thickness"
73+
- "voxel_color"
74+
- "voxel_opacity"
7575
- "point_plot"
7676
- "point_color"
7777
- "point_size"
@@ -92,15 +92,15 @@
9292
"type": "number"
9393
"minimum": 0
9494
"maximum": 1
95-
"geom_plot":
95+
"voxel_plot":
9696
"type": "boolean"
97-
"geom_thickness":
97+
"voxel_thickness":
9898
"type": "number"
9999
"minimum": 0
100-
"geom_color":
100+
"voxel_color":
101101
"type": "string"
102102
"minLength": 1
103-
"geom_opacity":
103+
"voxel_opacity":
104104
"type": "number"
105105
"minimum": 0
106106
"maximum": 1

pypeec/lib_mesher/mesher_png.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ def get_mesh(param, domain_color, layer_stack):
178178
size = param["size"]
179179

180180
# no reference geometry, direct voxelization
181-
reference = None
181+
geom_def = []
182182

183183
# get the image size
184184
(nx, ny) = size
@@ -211,4 +211,4 @@ def get_mesh(param, domain_color, layer_stack):
211211
# assemble
212212
n = [nx, ny, nz]
213213

214-
return n, d, c, domain_def, reference
214+
return n, d, c, domain_def, geom_def

pypeec/lib_mesher/mesher_shape.py

+29-38
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,13 @@
2121
__copyright__ = "Thomas Guillod - Dartmouth College"
2222
__license__ = "Mozilla Public License Version 2.0"
2323

24-
import vtk
2524
import warnings
2625
import scilogger
2726
import numpy as np
28-
import pyvista as pv
2927
import shapely as sha
3028
import rasterio.features as raf
3129
import rasterio.transform as rat
3230

33-
# prevent VTK to mess up the output
34-
vtk.vtkObject.GlobalWarningDisplayOff()
35-
3631
# prevent problematic linear transform to trigger warnings
3732
warnings.filterwarnings("ignore", module="shapely")
3833
warnings.filterwarnings("ignore", module="rasterio.features")
@@ -44,7 +39,7 @@
4439

4540
def _get_boundary_polygon(bnd, z_min):
4641
"""
47-
Convert a Shapely boundary into a PyVista polygon.
42+
Convert a Shapely boundary into a line mesh.
4843
"""
4944

5045
# check that the boundary is closed
@@ -58,24 +53,29 @@ def _get_boundary_polygon(bnd, z_min):
5853
# get the 3D boundary
5954
z = np.full(len(xy), z_min, dtype=np.float64)
6055
z = np.expand_dims(z, axis=1)
61-
xyz = np.hstack((xy, z))
56+
points = np.hstack((xy, z))
6257

6358
# remove the duplicated points
64-
xyz = xyz[:-1]
59+
points = points[:-1]
6560

66-
# get the face indices
67-
lines = np.arange(len(xyz))
68-
lines = np.concatenate(([len(xyz)+1], lines, [0]))
61+
# get the indices
62+
faces = np.empty(0, dtype=np.int64)
63+
lines = np.arange(len(points), dtype=np.int64)
64+
lines = np.concatenate(([len(points)+1], lines, [0]))
6965

7066
# create the polygon
71-
mesh = pv.PolyData(xyz, lines=lines)
67+
mesh = {
68+
"faces": np.array(faces, dtype=np.int64),
69+
"lines": np.array(lines, dtype=np.int64),
70+
"points": np.array(points, dtype=np.float64),
71+
}
7272

7373
return mesh
7474

7575

76-
def _get_shape_mesh(z_min, z_max, obj):
76+
def _get_shape_mesh(obj, z_min, z_max):
7777
"""
78-
Extrude a Shapely polygon into a PyVista mesh.
78+
Extrude a Shapely polygon into line meshes.
7979
"""
8080

8181
# ensure that the polygon has a positive orientation
@@ -85,19 +85,19 @@ def _get_shape_mesh(z_min, z_max, obj):
8585
bnd = obj.exterior
8686
holes = obj.interiors
8787

88-
# create an empty mesh
89-
mesh = pv.PolyData()
88+
# init mesh list
89+
geom_def = []
9090

9191
# polygon for the external boundaries
92-
mesh += _get_boundary_polygon(bnd, z_min)
93-
mesh += _get_boundary_polygon(bnd, z_max)
92+
geom_def.append(_get_boundary_polygon(bnd, z_min))
93+
geom_def.append(_get_boundary_polygon(bnd, z_max))
9494

9595
# polygon for the holes
9696
for bnd in holes:
97-
mesh += _get_boundary_polygon(bnd, z_min)
98-
mesh += _get_boundary_polygon(bnd, z_max)
97+
geom_def.append(_get_boundary_polygon(bnd, z_min))
98+
geom_def.append(_get_boundary_polygon(bnd, z_max))
9999

100-
return mesh
100+
return geom_def
101101

102102

103103
def _get_shape_single(tag, shape_type, shape_data):
@@ -426,13 +426,11 @@ def _get_voxel_size(dx, dy, dz, stack_pos, xy_max_obj, xy_min_obj, xy_max, xy_mi
426426
def _get_merge_shape(stack_pos, shape_obj):
427427
"""
428428
Transform all the 2D vector shapes into 3D meshes.
429-
Merge all the meshes into a single mesh.
430-
The resulting mesh represent the original geometry.
431-
This mesh can be used to assess the quality of the voxelization.
429+
The resulting meshes represent the original geometry.
432430
"""
433431

434-
# create an empty mesh
435-
reference = pv.PolyData()
432+
# init mesh list
433+
geom_def = []
436434

437435
# merge all the shapes
438436
for shape_obj_tmp in shape_obj:
@@ -446,14 +444,14 @@ def _get_merge_shape(stack_pos, shape_obj):
446444

447445
# transform the shapes into meshes
448446
if isinstance(obj, sha.Polygon):
449-
reference += _get_shape_mesh(z_min, z_max, obj)
447+
geom_def += _get_shape_mesh(obj, z_min, z_max)
450448
elif isinstance(obj, sha.MultiPolygon):
451449
for obj_tmp in obj.geoms:
452-
reference += _get_shape_mesh(z_min, z_max, obj_tmp)
450+
geom_def += _get_shape_mesh(obj_tmp, z_min, z_max)
453451
else:
454452
raise ValueError("invalid shape type")
455453

456-
return reference
454+
return geom_def
457455

458456

459457
def get_mesh(param, layer_stack, geometry_shape):
@@ -496,7 +494,7 @@ def get_mesh(param, layer_stack, geometry_shape):
496494

497495
# merge the shapes representing the original geometry
498496
LOGGER.debug("merge the shapes")
499-
reference = _get_merge_shape(stack_pos, shape_obj)
497+
geom_def = _get_merge_shape(stack_pos, shape_obj)
500498

501499
# voxelize the shapes
502500
LOGGER.debug("voxelize the shapes")
@@ -508,11 +506,4 @@ def get_mesh(param, layer_stack, geometry_shape):
508506
d = d.tolist()
509507
c = c.tolist()
510508

511-
# cast reference mesh
512-
reference = {
513-
"faces": np.array(reference.faces, dtype=np.int64),
514-
"lines": np.array(reference.lines, dtype=np.int64),
515-
"points": np.array(reference.points, dtype=np.float64),
516-
}
517-
518-
return n, d, c, domain_def, reference
509+
return n, d, c, domain_def, geom_def

pypeec/lib_mesher/mesher_stl.py

+13-16
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,11 @@ def _get_mesh_stl(domain_stl, check):
8484
Find the bounding box for all the meshes (minimum and maximum coordinates).
8585
"""
8686

87-
# init STL mesh list
87+
# init mesh list (for the voxelization)
8888
mesh_stl = []
89-
mesh_all = []
89+
90+
# init mesh list (for the reference meshes)
91+
geom_def = []
9092

9193
# init the coordinate (minimum and maximum coordinates)
9294
xyz_min = np.full(3, +np.inf, dtype=np.float64)
@@ -113,14 +115,16 @@ def _get_mesh_stl(domain_stl, check):
113115
xyz_max = np.maximum(xyz_max, tmp_max)
114116

115117
# assign the mesh
116-
mesh_all.append(mesh)
117118
mesh_stl.append({"tag": tag, "mesh": mesh})
118119

119-
# merge all the meshes
120-
reference = pv.MultiBlock(mesh_all)
121-
reference = reference.combine().extract_surface()
120+
# cast the surface mesh to a dict
121+
geom_def.append({
122+
"faces": np.array(mesh.faces, dtype=np.int64),
123+
"lines": np.array(mesh.lines, dtype=np.int64),
124+
"points": np.array(mesh.points, dtype=np.float64),
125+
})
122126

123-
return mesh_stl, reference, xyz_min, xyz_max
127+
return mesh_stl, geom_def, xyz_min, xyz_max
124128

125129

126130
def _get_voxel_size(d, xyz_max_stl, xyz_min_stl, xyz_max, xyz_min):
@@ -303,7 +307,7 @@ def get_mesh(param, domain_stl):
303307
with LOGGER.BlockIndent():
304308
# load the mesh and get the STL bounds
305309
LOGGER.debug("load STL files")
306-
(mesh_stl, reference, xyz_min_stl, xyz_max_stl) = _get_mesh_stl(domain_stl, check)
310+
(mesh_stl, geom_def, xyz_min_stl, xyz_max_stl) = _get_mesh_stl(domain_stl, check)
307311

308312
# geometry size
309313
LOGGER.debug("get the voxel size")
@@ -331,11 +335,4 @@ def get_mesh(param, domain_stl):
331335
d = d.tolist()
332336
c = c.tolist()
333337

334-
# cast reference mesh
335-
reference = {
336-
"faces": np.array(reference.faces, dtype=np.int64),
337-
"lines": np.array(reference.lines, dtype=np.int64),
338-
"points": np.array(reference.points, dtype=np.float64),
339-
}
340-
341-
return n, d, c, domain_def, reference
338+
return n, d, c, domain_def, geom_def

pypeec/lib_mesher/mesher_voxel.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def get_mesh(param, domain_index):
2929
nv = np.prod(n)
3030

3131
# no reference geometry, direct voxelization
32-
reference = None
32+
geom_def = []
3333

3434
# init new domain indices
3535
domain_def = {}
@@ -51,4 +51,4 @@ def get_mesh(param, domain_index):
5151
# add the new item
5252
domain_def[tag] = idx_tmp
5353

54-
return n, d, c, domain_def, reference
54+
return n, d, c, domain_def, geom_def

pypeec/lib_plot/manage_pyvista.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,13 @@ def _get_plot_view_theme(pl, grid, voxel, point, plot_view, plot_theme):
4848
)
4949

5050
# plot the non-empty voxels
51-
if plot_view["geom_plot"] and (voxel.n_cells > 0):
51+
if plot_view["voxel_plot"] and (voxel.n_cells > 0):
5252
pl.add_mesh(
5353
voxel,
5454
style="wireframe",
55-
color=plot_view["geom_color"],
56-
opacity=plot_view["geom_opacity"],
57-
line_width=plot_view["geom_thickness"],
55+
color=plot_view["voxel_color"],
56+
opacity=plot_view["voxel_opacity"],
57+
line_width=plot_view["voxel_thickness"],
5858
)
5959

6060
# plot the point cloud

pypeec/lib_plot/parse_voxel.py

+10-8
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,19 @@ def get_point(pts_cloud):
6464
return point
6565

6666

67-
def get_reference(reference):
67+
def get_reference(geom_def):
6868
"""
6969
Construct a PyVista object from the reference mesh.
7070
"""
7171

72-
if reference is None:
73-
reference = pv.PolyData()
74-
else:
75-
points = reference["points"]
76-
lines = reference["lines"]
77-
faces = reference["faces"]
78-
reference = pv.PolyData(points, lines=lines, faces=faces)
72+
# create an empty mesh
73+
reference = pv.PolyData()
74+
75+
# add the different reference mesh objects
76+
for geom_tmp in geom_def:
77+
points = geom_tmp["points"]
78+
lines = geom_tmp["lines"]
79+
faces = geom_tmp["faces"]
80+
reference += pv.PolyData(points, lines=lines, faces=faces)
7981

8082
return reference

0 commit comments

Comments
 (0)