PyVista 中的多体曲面到体积网格

Multibody Surface to Volumetric Mesh in PyVista

我有一个项目涉及将曲面网格导入 PyVista 并使用 tetgen 将它们转换为体积网格。这些表面网格中的一些包含多个主体,基本上沿表面分割。这些不能四面体化,因为它们是非流形的,但我想找到一种方法来修复它们,同时保留两个部分。下面是一个示例,显示了我正在处理的网格类型,以及使用 meshfix.repair 时如何丢失一个部分。 (为大数据集道歉,这个问题似乎不会发生在更简单的网格上)

给定这样的输入网格,我怎样才能得到两个部分的四面体化?

编辑:更多想法。

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/

下图显示了识别封闭区域前后的表面网格。