You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何修复Surface Nets网格生成算法产生的非流形边问题?

修复Surface Nets(PyVista contour_labels生成)网格中的非流形边问题

通过PyVista的contour_labels方法调用VTK实现的Surface Nets算法,偶尔会生成带有非流形边的网格——这类边会被4个面共享(正常网格边仅连接2个面),且多出现于对角线表面体素上。这类问题不影响体积计算,但会导致Laplacian平滑等操作产生尖刺,还会被Trimesh判定为非水密网格。

以下是三类可行的修复方案:

1. 基于VTK内置工具快速修复

直接利用VTK的vtkCleanPolyData过滤工具,自动处理非流形边、重合点等问题,适合大多数简单场景:

import pyvista as pv
from vtkmodules.vtkFiltersCore import vtkCleanPolyData

# 假设你的非流形网格对象为mesh
clean_filter = vtkCleanPolyData()
clean_filter.SetInputData(mesh)
clean_filter.SetTolerance(1e-6)  # 根据网格精度调整阈值
clean_filter.PointMergingOn()  # 开启重合点合并
clean_filter.Update()

# 转换为PyVista网格对象
fixed_mesh = pv.wrap(clean_filter.GetOutput())

2. 手动定位拆分非流形边

针对VTK工具无法处理的特殊情况,可手动识别4面共享的非流形边,通过插入中点拆分:

import trimesh
import numpy as np

# 加载目标网格
mesh = trimesh.load("your_mesh_file.stl")
# 获取所有非流形边
non_manifold_edges = mesh.non_manifold_edges()

for edge in non_manifold_edges:
    face_count = len(mesh.edges_faces[edge])
    if face_count != 4:
        continue  # 只处理4面共享的非流形边
    
    # 计算边的中点
    v0, v1 = mesh.vertices[edge[0]], mesh.vertices[edge[1]]
    mid_point = (v0 + v1) / 2
    new_v_idx = len(mesh.vertices)
    mesh.vertices = np.vstack([mesh.vertices, mid_point])
    
    # 拆分关联的4个面
    faces = mesh.edges_faces[edge]
    # 前2个面连接原起点与中点,后2个面连接中点与原终点
    for i in range(2):
        face = mesh.faces[faces[i]]
        # 找到边在面中的位置并替换顶点
        idx = np.where((face == edge[0]) & (np.roll(face, -1) == edge[1]))[0]
        if len(idx) == 0:
            idx = np.where((face == edge[1]) & (np.roll(face, -1) == edge[0]))[0]
        face[idx] = new_v_idx
    for i in range(2, 4):
        face = mesh.faces[faces[i]]
        idx = np.where((face == edge[0]) & (np.roll(face, -1) == edge[1]))[0]
        if len(idx) == 0:
            idx = np.where((face == edge[1]) & (np.roll(face, -1) == edge[0]))[0]
        face[np.roll(idx, 1)] = new_v_idx

# 重新整理网格拓扑
mesh.process()

3. 局部区域重新三角化

对于复杂的非流形区域,可删除问题面后重新生成流形网格:

import pyvista as pv

# 假设目标网格为mesh
# 获取非流形边关联的所有面
non_manifold_faces = set()
for edge in mesh.non_manifold_edges():
    non_manifold_faces.update(mesh.edges_faces[edge])
non_manifold_faces = list(non_manifold_faces)

# 提取问题区域的局部网格与边界
local_mesh = mesh.extract_cells(non_manifold_faces)
boundary = local_mesh.extract_feature_edges(boundary_edges=True, non_manifold_edges=False)

# 删除原网格中的问题面
mesh = mesh.extract_cells([i for i in range(mesh.n_cells) if i not in non_manifold_faces])

# 对边界区域做Delaunay三角化,生成流形网格
delaunay_mesh = boundary.delaunay_2d()

# 合并修复后的局部网格与原网格
fixed_mesh = mesh.merge(delaunay_mesh)

内容的提问来源于stack exchange,提问作者Matthew Vine

火山引擎 最新活动