PyVista 中的多体曲面到体积网格
Multibody Surface to Volumetric Mesh in PyVista
我有一个项目涉及将曲面网格导入 PyVista 并使用 tetgen 将它们转换为体积网格。这些表面网格中的一些包含多个主体,基本上沿表面分割。这些不能四面体化,因为它们是非流形的,但我想找到一种方法来修复它们,同时保留两个部分。下面是一个示例,显示了我正在处理的网格类型,以及使用 meshfix.repair 时如何丢失一个部分。 (为大数据集道歉,这个问题似乎不会发生在更简单的网格上)
给定这样的输入网格,我怎样才能得到两个部分的四面体化?
编辑:更多想法。
- 网格有两个不同的防水部分。所以也许可以有一种算法将表面网格分解成单独的防水部分。已尝试 DatasetFilters.Connectivity 但这要求各部分不接触。
- 墙元素在各部分之间共享,因此唯一的非流形边缘位于表面的外侧。这使得很难 select 分隔墙。
- 也许我们可以进行某种迭代测试,检查某个点是否在水密部分内,然后删除那些墙...
import pyvista as pv
import tetgen
import pymeshfix
import numpy as np
points = np.array([[ 76.84349 , 2.718057 , 2.718057 ],
[ 82.79519 , 1.491148 , 1.491148 ],
[ 0. , 0. , 0. ],
[ 70.97732 , 4.304215 , 4.304215 ],
[ 88.81041 , 0.6280057, 0.6280057],
[ 94.3964 , 0.1571253, 0.1571253],
[100. , 0. , 0. ],
[ 54.10642 , 11.15306 , 11.15306 ],
[ 59.58774 , 8.529518 , 8.529518 ],
[ 65.21831 , 6.243754 , 6.243754 ],
[ 38.75704 , 20.94748 , 20.94748 ],
[ 43.6718 , 17.37353 , 17.37353 ],
[ 48.79456 , 14.1047 , 14.1047 ],
[ 25.43809 , 33.36277 , 33.36277 ],
[ 29.62332 , 28.95689 , 28.95689 ],
[ 34.06845 , 24.81337 , 24.81337 ],
[ 14.59111 , 47.9873 , 47.9873 ],
[ 17.90807 , 42.89558 , 42.89558 ],
[ 21.52819 , 38.01472 , 38.01472 ],
[ 6.575722 , 64.33623 , 64.33623 ],
[ 8.914448 , 58.72746 , 58.72746 ],
[ 11.58954 , 53.2711 , 53.2711 ],
[ 1.657672 , 81.86754 , 81.86754 ],
[ 2.940621 , 75.92768 , 75.92768 ],
[ 4.581992 , 70.07671 , 70.07671 ],
[ 0. , 100. , 100. ],
[ 0.1846403, 93.92597 , 93.92597 ],
[ 0.7378794, 87.87437 , 87.87437 ],
[ 0. , 0. , 100. ],
[ 88.81041 , 0. , 0.6280057],
[ 76.84349 , 0. , 2.718057 ],
[ 65.21831 , 0. , 6.243754 ],
[ 54.10642 , 0. , 11.15306 ],
[ 43.6718 , 0. , 17.37353 ],
[ 34.06845 , 0. , 24.81337 ],
[ 25.43809 , 0. , 33.36277 ],
[ 17.90807 , 0. , 42.89558 ],
[ 11.58954 , 0. , 53.2711 ],
[ 6.575722 , 0. , 64.33623 ],
[ 2.940621 , 0. , 75.92768 ],
[ 0.7378794, 0. , 87.87437 ],
[ 87.87437 , 0.7378794, 0.7378794],
[ 93.92597 , 0.1846403, 0.1846403],
[ 81.86754 , 1.657672 , 1.657672 ],
[ 75.92768 , 2.940621 , 2.940621 ],
[ 70.07671 , 4.581992 , 4.581992 ],
[ 64.33623 , 6.575722 , 6.575722 ],
[ 58.72746 , 8.914448 , 8.914448 ],
[ 53.2711 , 11.58954 , 11.58954 ],
[ 47.9873 , 14.59111 , 14.59111 ],
[ 42.89558 , 17.90807 , 17.90807 ],
[ 38.01472 , 21.52819 , 21.52819 ],
[ 33.36277 , 25.43809 , 25.43809 ],
[ 28.95689 , 29.62332 , 29.62332 ],
[ 24.81337 , 34.06845 , 34.06845 ],
[ 20.94748 , 38.75704 , 38.75704 ],
[ 17.37353 , 43.6718 , 43.6718 ],
[ 14.1047 , 48.79456 , 48.79456 ],
[ 11.15306 , 54.10642 , 54.10642 ],
[ 8.529518 , 59.58774 , 59.58774 ],
[ 6.243754 , 65.21831 , 65.21831 ],
[ 4.304215 , 70.97732 , 70.97732 ],
[ 2.718057 , 76.84349 , 76.84349 ],
[ 1.491148 , 82.79519 , 82.79519 ],
[ 0.6280057, 88.81041 , 88.81041 ],
[ 0.1571253, 94.3964 , 94.3964 ],
[ 0. , 100. , 0. ],
[100. , 100. , 0. ],
[ 87.87437 , 100. , 0.7378794],
[ 75.92768 , 100. , 2.940621 ],
[ 64.33623 , 100. , 6.575722 ],
[ 53.2711 , 100. , 11.58954 ],
[ 42.89558 , 100. , 17.90807 ],
[ 33.36277 , 100. , 25.43809 ],
[ 24.81337 , 100. , 34.06845 ],
[ 17.37353 , 100. , 43.6718 ],
[ 11.15306 , 100. , 54.10642 ],
[ 6.243754 , 100. , 65.21831 ],
[ 2.718057 , 100. , 76.84349 ],
[ 0.6280057, 100. , 88.81041 ]], dtype=float)
faces = np.array([ 3, 0, 1, 2, 3, 0, 2, 3, 3, 1, 4, 2, 3, 2, 4, 5, 3,
2, 5, 6, 3, 7, 8, 2, 3, 2, 8, 9, 3, 2, 9, 3, 3, 10,
11, 2, 3, 2, 11, 12, 3, 2, 12, 7, 3, 13, 14, 2, 3, 2, 14,
15, 3, 2, 15, 10, 3, 16, 17, 2, 3, 2, 17, 18, 3, 2, 18, 13,
3, 19, 20, 2, 3, 2, 20, 21, 3, 2, 21, 16, 3, 22, 23, 2, 3,
2, 23, 24, 3, 2, 24, 19, 3, 25, 26, 2, 3, 2, 26, 27, 3, 2,
27, 22, 3, 25, 2, 28, 3, 2, 6, 29, 3, 29, 30, 2, 3, 2, 30,
31, 3, 2, 31, 32, 3, 32, 33, 2, 3, 2, 33, 34, 3, 2, 34, 35,
3, 35, 36, 2, 3, 2, 36, 37, 3, 2, 37, 38, 3, 38, 39, 2, 3,
2, 39, 40, 3, 2, 40, 28, 3, 40, 27, 28, 3, 28, 27, 26, 3, 28,
26, 25, 3, 39, 38, 19, 3, 19, 24, 39, 3, 39, 24, 23, 3, 39, 23,
40, 3, 40, 23, 22, 3, 40, 22, 27, 3, 37, 36, 17, 3, 17, 16, 37,
3, 37, 16, 21, 3, 37, 21, 38, 3, 38, 21, 20, 3, 38, 20, 19, 3,
35, 34, 15, 3, 15, 14, 35, 3, 35, 14, 13, 3, 35, 13, 36, 3, 36,
13, 18, 3, 36, 18, 17, 3, 33, 32, 7, 3, 7, 12, 33, 3, 33, 12,
11, 3, 33, 11, 34, 3, 34, 11, 10, 3, 34, 10, 15, 3, 31, 30, 0,
3, 0, 3, 31, 3, 31, 3, 9, 3, 31, 9, 32, 3, 32, 9, 8, 3,
32, 8, 7, 3, 6, 5, 29, 3, 29, 5, 4, 3, 29, 4, 30, 3, 30,
4, 1, 3, 30, 1, 0, 3, 41, 2, 42, 3, 42, 2, 6, 3, 41, 43,
2, 3, 2, 43, 44, 3, 2, 44, 45, 3, 45, 46, 2, 3, 2, 46, 47,
3, 2, 47, 48, 3, 48, 49, 2, 3, 2, 49, 50, 3, 2, 50, 51, 3,
51, 52, 2, 3, 2, 52, 53, 3, 2, 53, 54, 3, 54, 55, 2, 3, 2,
55, 56, 3, 2, 56, 57, 3, 57, 58, 2, 3, 2, 58, 59, 3, 2, 59,
60, 3, 60, 61, 2, 3, 2, 61, 62, 3, 2, 62, 63, 3, 63, 64, 2,
3, 2, 64, 65, 3, 2, 65, 25, 3, 25, 66, 2, 3, 6, 67, 42, 3,
42, 67, 68, 3, 42, 68, 41, 3, 41, 68, 43, 3, 43, 68, 69, 3, 43,
69, 44, 3, 44, 69, 45, 3, 45, 69, 70, 3, 45, 70, 46, 3, 46, 70,
47, 3, 47, 70, 71, 3, 47, 71, 48, 3, 48, 71, 49, 3, 49, 71, 72,
3, 49, 72, 50, 3, 73, 74, 54, 3, 54, 53, 73, 3, 73, 53, 52, 3,
73, 52, 72, 3, 72, 52, 51, 3, 72, 51, 50, 3, 75, 76, 58, 3, 58,
57, 75, 3, 75, 57, 56, 3, 75, 56, 74, 3, 74, 56, 55, 3, 74, 55,
54, 3, 77, 78, 62, 3, 62, 61, 77, 3, 77, 61, 60, 3, 77, 60, 76,
3, 76, 60, 59, 3, 76, 59, 58, 3, 25, 65, 79, 3, 79, 65, 64, 3,
79, 64, 78, 3, 78, 64, 63, 3, 78, 63, 62, 3, 66, 25, 79, 3, 79,
78, 66, 3, 66, 78, 77, 3, 66, 77, 76, 3, 76, 75, 66, 3, 66, 75,
74, 3, 66, 74, 73, 3, 73, 72, 66, 3, 66, 72, 71, 3, 66, 71, 70,
3, 70, 69, 66, 3, 66, 69, 68, 3, 66, 68, 67, 3, 2, 66, 6, 3,
6, 66, 67], dtype=int)
mesh = pv.PolyData(points, faces)
mesh.rotate_x(90, inplace=True)
mesh.rotate_z(90, inplace=True)
tet = tetgen.TetGen(mesh)
meshfix = pymeshfix.MeshFix(tet.v, tet.f)
holes = meshfix.extract_holes()
meshfix.repair()
tet.v, tet.f = meshfix.v, meshfix.f
assert(tet.tetrahedralize())
p = pv.Plotter()
p.add_mesh(mesh, style="wireframe", color="k", label="Original Surface")
p.add_mesh(holes, color='r', label="Holes")
p.add_mesh(meshfix.mesh, label="Repaired surface")
p.add_legend()
p.show()
我最终编写了一个库,可以提取网格的封闭表面,以及其他一些有用的东西。文档可在此处获得:https://acreegan.github.io/pyvista_tools/
下图显示了识别封闭区域前后的表面网格。
我有一个项目涉及将曲面网格导入 PyVista 并使用 tetgen 将它们转换为体积网格。这些表面网格中的一些包含多个主体,基本上沿表面分割。这些不能四面体化,因为它们是非流形的,但我想找到一种方法来修复它们,同时保留两个部分。下面是一个示例,显示了我正在处理的网格类型,以及使用 meshfix.repair 时如何丢失一个部分。 (为大数据集道歉,这个问题似乎不会发生在更简单的网格上)
给定这样的输入网格,我怎样才能得到两个部分的四面体化?
编辑:更多想法。
- 网格有两个不同的防水部分。所以也许可以有一种算法将表面网格分解成单独的防水部分。已尝试 DatasetFilters.Connectivity 但这要求各部分不接触。
- 墙元素在各部分之间共享,因此唯一的非流形边缘位于表面的外侧。这使得很难 select 分隔墙。
- 也许我们可以进行某种迭代测试,检查某个点是否在水密部分内,然后删除那些墙...
import pyvista as pv
import tetgen
import pymeshfix
import numpy as np
points = np.array([[ 76.84349 , 2.718057 , 2.718057 ],
[ 82.79519 , 1.491148 , 1.491148 ],
[ 0. , 0. , 0. ],
[ 70.97732 , 4.304215 , 4.304215 ],
[ 88.81041 , 0.6280057, 0.6280057],
[ 94.3964 , 0.1571253, 0.1571253],
[100. , 0. , 0. ],
[ 54.10642 , 11.15306 , 11.15306 ],
[ 59.58774 , 8.529518 , 8.529518 ],
[ 65.21831 , 6.243754 , 6.243754 ],
[ 38.75704 , 20.94748 , 20.94748 ],
[ 43.6718 , 17.37353 , 17.37353 ],
[ 48.79456 , 14.1047 , 14.1047 ],
[ 25.43809 , 33.36277 , 33.36277 ],
[ 29.62332 , 28.95689 , 28.95689 ],
[ 34.06845 , 24.81337 , 24.81337 ],
[ 14.59111 , 47.9873 , 47.9873 ],
[ 17.90807 , 42.89558 , 42.89558 ],
[ 21.52819 , 38.01472 , 38.01472 ],
[ 6.575722 , 64.33623 , 64.33623 ],
[ 8.914448 , 58.72746 , 58.72746 ],
[ 11.58954 , 53.2711 , 53.2711 ],
[ 1.657672 , 81.86754 , 81.86754 ],
[ 2.940621 , 75.92768 , 75.92768 ],
[ 4.581992 , 70.07671 , 70.07671 ],
[ 0. , 100. , 100. ],
[ 0.1846403, 93.92597 , 93.92597 ],
[ 0.7378794, 87.87437 , 87.87437 ],
[ 0. , 0. , 100. ],
[ 88.81041 , 0. , 0.6280057],
[ 76.84349 , 0. , 2.718057 ],
[ 65.21831 , 0. , 6.243754 ],
[ 54.10642 , 0. , 11.15306 ],
[ 43.6718 , 0. , 17.37353 ],
[ 34.06845 , 0. , 24.81337 ],
[ 25.43809 , 0. , 33.36277 ],
[ 17.90807 , 0. , 42.89558 ],
[ 11.58954 , 0. , 53.2711 ],
[ 6.575722 , 0. , 64.33623 ],
[ 2.940621 , 0. , 75.92768 ],
[ 0.7378794, 0. , 87.87437 ],
[ 87.87437 , 0.7378794, 0.7378794],
[ 93.92597 , 0.1846403, 0.1846403],
[ 81.86754 , 1.657672 , 1.657672 ],
[ 75.92768 , 2.940621 , 2.940621 ],
[ 70.07671 , 4.581992 , 4.581992 ],
[ 64.33623 , 6.575722 , 6.575722 ],
[ 58.72746 , 8.914448 , 8.914448 ],
[ 53.2711 , 11.58954 , 11.58954 ],
[ 47.9873 , 14.59111 , 14.59111 ],
[ 42.89558 , 17.90807 , 17.90807 ],
[ 38.01472 , 21.52819 , 21.52819 ],
[ 33.36277 , 25.43809 , 25.43809 ],
[ 28.95689 , 29.62332 , 29.62332 ],
[ 24.81337 , 34.06845 , 34.06845 ],
[ 20.94748 , 38.75704 , 38.75704 ],
[ 17.37353 , 43.6718 , 43.6718 ],
[ 14.1047 , 48.79456 , 48.79456 ],
[ 11.15306 , 54.10642 , 54.10642 ],
[ 8.529518 , 59.58774 , 59.58774 ],
[ 6.243754 , 65.21831 , 65.21831 ],
[ 4.304215 , 70.97732 , 70.97732 ],
[ 2.718057 , 76.84349 , 76.84349 ],
[ 1.491148 , 82.79519 , 82.79519 ],
[ 0.6280057, 88.81041 , 88.81041 ],
[ 0.1571253, 94.3964 , 94.3964 ],
[ 0. , 100. , 0. ],
[100. , 100. , 0. ],
[ 87.87437 , 100. , 0.7378794],
[ 75.92768 , 100. , 2.940621 ],
[ 64.33623 , 100. , 6.575722 ],
[ 53.2711 , 100. , 11.58954 ],
[ 42.89558 , 100. , 17.90807 ],
[ 33.36277 , 100. , 25.43809 ],
[ 24.81337 , 100. , 34.06845 ],
[ 17.37353 , 100. , 43.6718 ],
[ 11.15306 , 100. , 54.10642 ],
[ 6.243754 , 100. , 65.21831 ],
[ 2.718057 , 100. , 76.84349 ],
[ 0.6280057, 100. , 88.81041 ]], dtype=float)
faces = np.array([ 3, 0, 1, 2, 3, 0, 2, 3, 3, 1, 4, 2, 3, 2, 4, 5, 3,
2, 5, 6, 3, 7, 8, 2, 3, 2, 8, 9, 3, 2, 9, 3, 3, 10,
11, 2, 3, 2, 11, 12, 3, 2, 12, 7, 3, 13, 14, 2, 3, 2, 14,
15, 3, 2, 15, 10, 3, 16, 17, 2, 3, 2, 17, 18, 3, 2, 18, 13,
3, 19, 20, 2, 3, 2, 20, 21, 3, 2, 21, 16, 3, 22, 23, 2, 3,
2, 23, 24, 3, 2, 24, 19, 3, 25, 26, 2, 3, 2, 26, 27, 3, 2,
27, 22, 3, 25, 2, 28, 3, 2, 6, 29, 3, 29, 30, 2, 3, 2, 30,
31, 3, 2, 31, 32, 3, 32, 33, 2, 3, 2, 33, 34, 3, 2, 34, 35,
3, 35, 36, 2, 3, 2, 36, 37, 3, 2, 37, 38, 3, 38, 39, 2, 3,
2, 39, 40, 3, 2, 40, 28, 3, 40, 27, 28, 3, 28, 27, 26, 3, 28,
26, 25, 3, 39, 38, 19, 3, 19, 24, 39, 3, 39, 24, 23, 3, 39, 23,
40, 3, 40, 23, 22, 3, 40, 22, 27, 3, 37, 36, 17, 3, 17, 16, 37,
3, 37, 16, 21, 3, 37, 21, 38, 3, 38, 21, 20, 3, 38, 20, 19, 3,
35, 34, 15, 3, 15, 14, 35, 3, 35, 14, 13, 3, 35, 13, 36, 3, 36,
13, 18, 3, 36, 18, 17, 3, 33, 32, 7, 3, 7, 12, 33, 3, 33, 12,
11, 3, 33, 11, 34, 3, 34, 11, 10, 3, 34, 10, 15, 3, 31, 30, 0,
3, 0, 3, 31, 3, 31, 3, 9, 3, 31, 9, 32, 3, 32, 9, 8, 3,
32, 8, 7, 3, 6, 5, 29, 3, 29, 5, 4, 3, 29, 4, 30, 3, 30,
4, 1, 3, 30, 1, 0, 3, 41, 2, 42, 3, 42, 2, 6, 3, 41, 43,
2, 3, 2, 43, 44, 3, 2, 44, 45, 3, 45, 46, 2, 3, 2, 46, 47,
3, 2, 47, 48, 3, 48, 49, 2, 3, 2, 49, 50, 3, 2, 50, 51, 3,
51, 52, 2, 3, 2, 52, 53, 3, 2, 53, 54, 3, 54, 55, 2, 3, 2,
55, 56, 3, 2, 56, 57, 3, 57, 58, 2, 3, 2, 58, 59, 3, 2, 59,
60, 3, 60, 61, 2, 3, 2, 61, 62, 3, 2, 62, 63, 3, 63, 64, 2,
3, 2, 64, 65, 3, 2, 65, 25, 3, 25, 66, 2, 3, 6, 67, 42, 3,
42, 67, 68, 3, 42, 68, 41, 3, 41, 68, 43, 3, 43, 68, 69, 3, 43,
69, 44, 3, 44, 69, 45, 3, 45, 69, 70, 3, 45, 70, 46, 3, 46, 70,
47, 3, 47, 70, 71, 3, 47, 71, 48, 3, 48, 71, 49, 3, 49, 71, 72,
3, 49, 72, 50, 3, 73, 74, 54, 3, 54, 53, 73, 3, 73, 53, 52, 3,
73, 52, 72, 3, 72, 52, 51, 3, 72, 51, 50, 3, 75, 76, 58, 3, 58,
57, 75, 3, 75, 57, 56, 3, 75, 56, 74, 3, 74, 56, 55, 3, 74, 55,
54, 3, 77, 78, 62, 3, 62, 61, 77, 3, 77, 61, 60, 3, 77, 60, 76,
3, 76, 60, 59, 3, 76, 59, 58, 3, 25, 65, 79, 3, 79, 65, 64, 3,
79, 64, 78, 3, 78, 64, 63, 3, 78, 63, 62, 3, 66, 25, 79, 3, 79,
78, 66, 3, 66, 78, 77, 3, 66, 77, 76, 3, 76, 75, 66, 3, 66, 75,
74, 3, 66, 74, 73, 3, 73, 72, 66, 3, 66, 72, 71, 3, 66, 71, 70,
3, 70, 69, 66, 3, 66, 69, 68, 3, 66, 68, 67, 3, 2, 66, 6, 3,
6, 66, 67], dtype=int)
mesh = pv.PolyData(points, faces)
mesh.rotate_x(90, inplace=True)
mesh.rotate_z(90, inplace=True)
tet = tetgen.TetGen(mesh)
meshfix = pymeshfix.MeshFix(tet.v, tet.f)
holes = meshfix.extract_holes()
meshfix.repair()
tet.v, tet.f = meshfix.v, meshfix.f
assert(tet.tetrahedralize())
p = pv.Plotter()
p.add_mesh(mesh, style="wireframe", color="k", label="Original Surface")
p.add_mesh(holes, color='r', label="Holes")
p.add_mesh(meshfix.mesh, label="Repaired surface")
p.add_legend()
p.show()
我最终编写了一个库,可以提取网格的封闭表面,以及其他一些有用的东西。文档可在此处获得:https://acreegan.github.io/pyvista_tools/
下图显示了识别封闭区域前后的表面网格。