已知闭合曲面网格的单元边界点,如何提取子网格并计算单元面积?
基于边界点分割闭合心脏曲面网格并计算单元面积
核心思路
闭合曲面被闭合边界环分割为两个拓扑独立的区域,直接删除边界点会破坏网格拓扑导致面积计算失真,标准方案是通过边界环构建闭合切割体,利用布尔分割得到两个子网格,再提取目标单元。以下是Trimesh和Open3D的具体实现:
Trimesh 实现方案
import trimesh # 加载闭合心脏网格(支持stl/obj等格式) mesh = trimesh.load("heart_mesh.stl") # 已知的闭合边界点索引列表(需保证首尾点相连,无交叉) boundary_indices = [10, 25, 42, 67, 10] # 替换为实际索引 boundary_points = mesh.vertices[boundary_indices] # 生成闭合多边形路径 polygon = trimesh.load_path(boundary_points) # 拉伸多边形生成薄闭合切割体(厚度需足够穿透原网格) cutting_mesh = polygon.extrude(height=0.2, cap=True) # 预处理原网格,修复拓扑问题 mesh.remove_duplicate_faces() mesh.fill_holes() cutting_mesh.remove_duplicate_faces() # 执行网格分割 split_result = mesh.split(cutting_mesh) sub_meshes = list(split_result) # 提取目标单元(示例选面积较小的,可按需调整) target_mesh = min(sub_meshes, key=lambda m: m.area) # 计算单元面积 unit_area = target_mesh.area print(f"目标单元面积: {unit_area}")
注意事项
- 若边界点不共面,先通过
trimesh.projection.project_to_plane将点投影到主成分平面,再生成切割多边形 - 布尔分割失败时,用
mesh.is_watertight验证闭合性,mesh.remove_non_manifold_edges()修复非流形边
Open3D 实现方案
import open3d as o3d import numpy as np from scipy.spatial import Delaunay # 加载闭合心脏网格 mesh = o3d.io.read_triangle_mesh("heart_mesh.stl") # 已知闭合边界点索引 boundary_indices = [10, 25, 42, 67, 10] # 替换为实际索引 boundary_points = np.asarray(mesh.vertices)[boundary_indices] # 计算边界点所在平面的法向量与原点 plane_vec1 = boundary_points[1] - boundary_points[0] plane_vec2 = boundary_points[2] - boundary_points[0] plane_normal = np.cross(plane_vec1, plane_vec2) plane_normal /= np.linalg.norm(plane_normal) plane_origin = boundary_points[0] # 投影边界点到平面,保证共面 projected_points = [] for p in boundary_points: dist = np.dot(p - plane_origin, plane_normal) projected_points.append(p - dist * plane_normal) projected_points = np.array(projected_points) # 对投影点做Delaunay三角化,生成切割面网格 tri = Delaunay(projected_points) cutting_mesh = o3d.geometry.TriangleMesh() cutting_mesh.vertices = o3d.utility.Vector3dVector(projected_points) cutting_mesh.triangles = o3d.utility.Vector3iVector(tri.simplices) # 拉伸切割面为闭合体 cutting_mesh = cutting_mesh.extrude((0, 0, 0.2)) # 网格预处理,修复拓扑问题 mesh.remove_duplicated_vertices() mesh.remove_duplicated_triangles() mesh.remove_non_manifold_edges() cutting_mesh.remove_duplicated_vertices() cutting_mesh.remove_duplicated_triangles() cutting_mesh.remove_non_manifold_edges() # 执行布尔切割 split_result = mesh.boolean_cut(cutting_mesh) # 提取目标单元并计算面积 target_mesh = min(split_result, key=lambda m: m.get_surface_area()) unit_area = target_mesh.get_surface_area() print(f"目标单元面积: {unit_area}")
注意事项
- 若边界环复杂,用
o3d.geometry.LineSet可视化边界,验证闭合性与连续性 - 布尔运算依赖网格的watertight属性,
mesh.is_watertight()可检查,不满足则用mesh.fill_holes()修复
关键验证步骤
- 边界环验证:确保边界索引构成单一闭合环,无分支或交叉,可通过绘制边界线确认
- 网格质量验证:修复所有非流形拓扑、重复元素,保证网格是watertight的闭合曲面
- 分割结果验证:可视化两个子网格,确认目标单元与预期区域一致
内容的提问来源于stack exchange,提问作者Sulaimaan
相关产品推荐
相关产品推荐

