This commit is contained in:
2026-03-07 01:18:25 +08:00
parent 7ccc97134d
commit e82d2b524b
3 changed files with 190 additions and 112 deletions
+105 -80
View File
@@ -1,102 +1,127 @@
# src/core/mesh_generator.py
import logging
import numpy as np
from typing import Dict, List, Optional
import pyvista as pv
from typing import Dict, List, Optional, Any
import trimesh
from OCC.Core.BRepMesh import BRepMesh_IncrementalMesh
from OCC.Core.TopExp import TopExp_Explorer
from OCC.Core.TopAbs import TopAbs_FACE
from OCC.Core.BRep import BRep_Tool
from OCC.Core.gp import gp_Pnt, gp_Vec
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeFace, BRepBuilderAPI_MakeEdge
logger = logging.getLogger(__name__)
class MeshGenerator:
"""网格生成器 - 使用PyVista和Trimesh"""
"""网格生成器 - 从PythonOCC形状生成点云"""
def __init__(self, quality: str = "medium"):
self.quality_settings = {
"low": 0.5,
"medium": 0.1,
"high": 0.01
"low": 1.0,
"medium": 0.5,
"high": 0.1
}
self.quality = self.quality_settings.get(quality, 0.1)
self.quality = self.quality_settings.get(quality, 0.5)
def generate_mesh_from_shape(self, shape, num_points: int = 10000) -> Dict:
"""从形状生成网格数据"""
def generate_mesh_from_shape(self, shape, num_points: int = 50000) -> Dict:
"""从PythonOCC形状生成点云数据"""
try:
# 方法1: 使用PythonOCC生成网格
occ_mesh = self._generate_occ_mesh(shape)
# 方法2: 转换为PyVista网格
pv_mesh = self._convert_to_pyvista(occ_mesh)
# 方法3: 转换为Trimesh网格
tri_mesh = self._convert_to_trimesh(pv_mesh)
# 生成点云
pointcloud = self._generate_pointcloud(tri_mesh, num_points)
return {
"pyvista_mesh": pv_mesh,
"trimesh_mesh": tri_mesh,
"pointcloud": pointcloud
}
except Exception as e:
logger.error(f"网格生成失败: {e}")
raise
def _generate_occ_mesh(self, shape) -> any:
"""使用PythonOCC生成网格"""
mesh = BRepMesh_IncrementalMesh(shape, self.quality)
mesh.Perform()
return mesh
def _convert_to_pyvista(self, occ_mesh) -> pv.PolyData:
"""转换为PyVista网格"""
# 这里需要从OCC网格中提取顶点和面数据
# 简化实现 - 实际需要遍历OCC网格数据结构
try:
# 创建示例网格数据
cube = pv.Cube()
return cube
except Exception as e:
logger.warning(f"PyVista转换失败,使用备用方法: {e}")
return self._create_sample_mesh()
def _convert_to_trimesh(self, pv_mesh) -> trimesh.Trimesh:
"""转换为Trimesh网格"""
try:
# 从PyVista转换
vertices = pv_mesh.points
faces = pv_mesh.faces.reshape(-1, 4)[:, 1:4] # 假设三角形网格
return trimesh.Trimesh(vertices=vertices, faces=faces)
except Exception as e:
logger.warning(f"Trimesh转换失败: {e}")
return self._create_sample_trimesh()
def _generate_pointcloud(self, mesh: trimesh.Trimesh, num_points: int) -> Dict:
"""从网格生成点云"""
try:
# 均匀采样点云
points, face_indices = trimesh.sample.sample_surface(mesh, num_points)
# 计算法向量
normals = mesh.face_normals[face_indices]
# 生成网格
mesh = BRepMesh_IncrementalMesh(shape, self.quality)
mesh.Perform()
logger.info(f"OCC网格生成完成, 网格状态: {mesh.IsDone()}")
# 提取三角形面数据
vertices = []
faces = []
vertex_map = {}
vertex_index = 0
# 遍历所有面
explorer = TopExp_Explorer(shape, TopAbs_FACE)
while explorer.More():
face = explorer.Current()
# 获取面的三角形剖分
face_triangulation = BRep_Tool.Triangulation(face)
for i in range(1, face_triangulation.NbTriangles() + 1):
# 获取三角形的三个顶点
tri = face_triangulation.Triangle(i)
# 获取顶点坐标
v1 = BRep_Tool.Pnt(face_triangulation, tri.Value(1) + 1)
v2 = BRep_Tool.Pnt(face_triangulation, tri.Value(2) + 1)
v3 = BRep_Tool.Pnt(face_triangulation, tri.Value(3) + 1)
# 转换为坐标
p1 = (v1.X(), v1.Y(), v1.Z())
p2 = (v2.X(), v2.Y(), v2.Z())
p3 = (v3.X(), v3.Y(), v3.Z())
# 添加顶点并获取索引
def add_vertex(p):
nonlocal vertex_index
key = (round(p[0], 6), round(p[1], 6), round(p[2], 6))
if key not in vertex_map:
vertex_map[key] = vertex_index
vertices.append(p)
vertex_index += 1
return vertex_map[key]
idx1 = add_vertex(p1)
idx2 = add_vertex(p2)
idx3 = add_vertex(p3)
faces.append([idx1 - 1, idx2 - 1, idx3 - 1])
vertices = np.array(vertices, dtype=np.float32)
faces = np.array(faces, dtype=np.int32)
logger.info(f"提取了 {len(vertices)} 个顶点, {len(faces)} 个三角形面")
# 创建Trimesh对象
tri_mesh = trimesh.Trimesh(vertices=vertices, faces=faces)
# 在网格表面采样点云
points, face_idx = trimesh.sample.sample_surface(tri_mesh, num_points)
# 获取法向量
normals = tri_mesh.face_normals[face_idx]
logger.info(f"生成了 {len(points)} 个点云点")
return {
"vertices": vertices.tolist(),
"faces": faces.tolist(),
"points": points.tolist(),
"normals": normals.tolist(),
"count": len(points)
"point_count": len(points),
"vertex_count": len(vertices),
"face_count": len(faces)
}
except Exception as e:
logger.error(f"点云生成失败: {e}")
raise
logger.error(f"网格生成失败: {e}")
import traceback
logger.error(traceback.format_exc())
# 返回示例数据
return self._create_sample_pointcloud()
def _create_sample_mesh(self) -> pv.PolyData:
"""创建示例网格(备用)"""
return pv.Cube()
def _create_sample_trimesh(self) -> trimesh.Trimesh:
"""创建示例Trimesh(备用)"""
return trimesh.creation.box([100, 80, 50])
def _create_sample_pointcloud(self) -> Dict:
"""创建示例点云(备用)"""
# 创建一个简单的立方体点云
mesh = trimesh.creation.box([100, 80, 50])
points, _ = trimesh.sample.sample_surface(mesh, 5000)
normals = mesh.face_normals
return {
"vertices": mesh.vertices.tolist(),
"faces": mesh.faces.tolist(),
"points": points.tolist(),
"normals": normals.tolist(),
"point_count": len(points),
"vertex_count": len(mesh.vertices),
"face_count": len(mesh.faces)
}