2026-02-11 22:40:35 +08:00
|
|
|
# src/core/mesh_generator.py
|
|
|
|
|
import logging
|
|
|
|
|
import numpy as np
|
2026-03-07 01:18:25 +08:00
|
|
|
from typing import Dict, List, Optional, Any
|
2026-02-11 22:40:35 +08:00
|
|
|
import trimesh
|
|
|
|
|
from OCC.Core.BRepMesh import BRepMesh_IncrementalMesh
|
2026-03-07 01:18:25 +08:00
|
|
|
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
|
2026-02-11 22:40:35 +08:00
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MeshGenerator:
|
2026-03-07 01:18:25 +08:00
|
|
|
"""网格生成器 - 从PythonOCC形状生成点云"""
|
2026-02-11 22:40:35 +08:00
|
|
|
|
|
|
|
|
def __init__(self, quality: str = "medium"):
|
|
|
|
|
self.quality_settings = {
|
2026-03-07 01:18:25 +08:00
|
|
|
"low": 1.0,
|
|
|
|
|
"medium": 0.5,
|
|
|
|
|
"high": 0.1
|
2026-02-11 22:40:35 +08:00
|
|
|
}
|
2026-03-07 01:18:25 +08:00
|
|
|
self.quality = self.quality_settings.get(quality, 0.5)
|
2026-02-11 22:40:35 +08:00
|
|
|
|
2026-03-07 01:18:25 +08:00
|
|
|
def generate_mesh_from_shape(self, shape, num_points: int = 50000) -> Dict:
|
|
|
|
|
"""从PythonOCC形状生成点云数据"""
|
2026-02-11 22:40:35 +08:00
|
|
|
try:
|
2026-03-07 01:18:25 +08:00
|
|
|
# 生成网格
|
|
|
|
|
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)} 个点云点")
|
|
|
|
|
|
2026-02-11 22:40:35 +08:00
|
|
|
return {
|
2026-03-07 01:18:25 +08:00
|
|
|
"vertices": vertices.tolist(),
|
|
|
|
|
"faces": faces.tolist(),
|
2026-02-11 22:40:35 +08:00
|
|
|
"points": points.tolist(),
|
|
|
|
|
"normals": normals.tolist(),
|
2026-03-07 01:18:25 +08:00
|
|
|
"point_count": len(points),
|
|
|
|
|
"vertex_count": len(vertices),
|
|
|
|
|
"face_count": len(faces)
|
2026-02-11 22:40:35 +08:00
|
|
|
}
|
2026-03-07 01:18:25 +08:00
|
|
|
|
2026-02-11 22:40:35 +08:00
|
|
|
except Exception as e:
|
2026-03-07 01:18:25 +08:00
|
|
|
logger.error(f"网格生成失败: {e}")
|
|
|
|
|
import traceback
|
|
|
|
|
logger.error(traceback.format_exc())
|
|
|
|
|
# 返回示例数据
|
|
|
|
|
return self._create_sample_pointcloud()
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
}
|