This commit is contained in:
cjw
2026-02-16 19:06:41 +08:00
parent 1525f6fc0b
commit 44d431f4af
4 changed files with 168 additions and 10 deletions
+58 -8
View File
@@ -15,6 +15,7 @@ from database.database import get_db_session
from utils.logger import get_logger
from sqlalchemy.ext.asyncio import AsyncSession
from core.mold_generator import MoldCavityGenerator
from core.mesh_generator import MeshGenerator
logger = get_logger(__name__)
@@ -27,6 +28,7 @@ file_handler = FileHandler()
html_generator = HTMLGenerator()
# 初始化模具生成器(可配置不同材料的收缩率)
mold_generator = MoldCavityGenerator(shrinkage_rate=0.005) # ABS材料
mesh_generator = MeshGenerator(quality="medium")
# 内存中的任务存储
tasks = {}
@@ -359,7 +361,55 @@ async def process_file_core(
shape = stp_parser.load_step_file(Path(file_path))
geometry_data = stp_parser.analyze_geometry(shape)
# 2. 生成模具型腔(模拟数据)
# 2. 生成网格数据并持久化(详细 JSON 存 RustFS,摘要写 PostgreSQL)
await storage_service.update_task_status(
db_session, task_id, "processing", 30, "生成网格数据"
)
mesh_result = None
mesh_json = None
try:
mesh_result = mesh_generator.generate_mesh_from_shape(shape)
tri_mesh = mesh_result.get("trimesh_mesh")
pointcloud = mesh_result.get("pointcloud") or {}
if tri_mesh is not None:
# 顶点和面转为 JSON 可序列化
vertices = tri_mesh.vertices.tolist()
faces = tri_mesh.faces.tolist()
# 使用已计算的几何边界框,避免重复计算
bbox = geometry_data.get("bounding_box", {})
mesh_json = {
"metadata": {
"file_name": Path(file_path).name,
"generated_at": datetime.now().isoformat(),
"quality": "medium",
"vertex_count": len(vertices),
"face_count": len(faces),
"point_count": pointcloud.get("count"),
},
"mesh": {
"vertices": vertices,
"faces": faces,
},
"pointcloud": pointcloud,
"bounding_box": bbox,
}
await storage_service.save_mesh_data(
db_session,
stp_file_id=stp_file_id,
mesh_json=mesh_json,
quality="medium",
)
except Exception as mesh_err:
# 网格失败不影响整体流程,只记录日志
logger.warning(f"网格生成或保存失败,不影响主流程: {mesh_err}")
# 3. 生成模具型腔(模拟数据)
await storage_service.update_task_status(
db_session, task_id, "processing", 40, "生成模具型腔(模拟)"
)
@@ -371,7 +421,7 @@ async def process_file_core(
"gating_type": "edge_gate"
}
# 3. 生成详细JSON数据(使用计算值)
# 4. 生成详细JSON数据(使用计算值)
await storage_service.update_task_status(
db_session, task_id, "processing", 60, "生成型腔详细数据"
)
@@ -472,10 +522,10 @@ async def process_file_core(
}
}
# 4. 生成关键信息(模拟)
# 5. 生成关键信息(模拟)
cavity_key_info = detailed_cavity_json["mold_cavities"]["cavity_key_info"]
# 5. 保存几何数据到数据库
# 6. 保存几何数据到数据库
await storage_service.update_task_status(
db_session, task_id, "processing", 70, "保存几何数据"
)
@@ -487,14 +537,14 @@ async def process_file_core(
geometry_data.get("analysis_method", "mold_cavity")
)
# 6. 保存模具型腔数据
# 7. 保存模具型腔数据
await storage_service.save_mold_cavity_data(
db_session,
stp_file_id,
detailed_cavity_json
)
# 7. 生成HTML可视化(包含型腔信息)
# 8. 生成HTML可视化(包含型腔信息)
await storage_service.update_task_status(
db_session, task_id, "processing", 85, "生成可视化报告"
)
@@ -513,10 +563,10 @@ async def process_file_core(
html_file_path
)
# 8. 分析模具设计
# 9. 分析模具设计
analysis_result = geometry_analyzer.analyze_mold_design(geometry_data)
# 9. 完成处理
# 10. 完成处理
await storage_service.update_stp_file_status(db_session, stp_file_id, "completed")
await storage_service.update_task_status(
db_session, task_id, "completed", 100, "模具型腔生成完成"
+36
View File
@@ -61,6 +61,8 @@ class STPFile(Base):
# 关联关系
user = relationship("User", back_populates="stp_files")
geometry_data = relationship("GeometryData", back_populates="stp_file", uselist=False)
# 网格数据:一条 STP 记录对应一条网格摘要记录(详细 JSON 在 RustFS)
mesh_data = relationship("MeshData", back_populates="stp_file", uselist=False)
mold_cavity_data = relationship("MoldCavityData", back_populates="stp_file", uselist=False)
html_file = relationship("HTMLFile", back_populates="stp_file", uselist=False)
@@ -103,6 +105,40 @@ class GeometryData(Base):
def __repr__(self):
return f"<GeometryData(id={self.id}, stp_file_id={self.stp_file_id})>"
class MeshData(Base):
"""网格数据JSON元数据表(详细网格存 RustFS,PostgreSQL 存摘要)"""
__tablename__ = "mesh_data"
id = Column(Integer, primary_key=True, index=True)
stp_file_id = Column(Integer, ForeignKey("stp_files.id"), nullable=False, index=True)
# 对象存储信息
object_key = Column(String(500), nullable=False)
storage_bucket = Column(String(100), nullable=False)
object_url = Column(String(1000), nullable=True)
# 生成设置
quality = Column(String(20), default="medium") # low / medium / high
# 网格规模信息
vertex_count = Column(Integer, nullable=True)
face_count = Column(Integer, nullable=True)
point_count = Column(Integer, nullable=True) # 采样点云数量
# 网格边界框(便于快速查询)
bounding_box_min = Column(JSON, nullable=True)
bounding_box_max = Column(JSON, nullable=True)
# 时间戳
created_time = Column(DateTime, default=func.now())
# 关联关系
stp_file = relationship("STPFile", back_populates="mesh_data")
def __repr__(self):
return f"<MeshData(id={self.id}, stp_file_id={self.stp_file_id}, quality='{self.quality}')>"
class HTMLFile(Base):
"""网页文件元数据表"""
__tablename__ = "html_files"
+72 -1
View File
@@ -8,7 +8,7 @@ import json
from datetime import datetime
from models.database import (
STPFile, GeometryData, MoldCavityData,
STPFile, GeometryData, MeshData, MoldCavityData,
HTMLFile, ProcessingTask, User,
FeatureDetection, DesignRecommendation,
UserActivity, SystemLog
@@ -200,6 +200,62 @@ class StorageIntegrationService:
logger.info(f"几何数据保存成功 RustFS: {geometry_data.id}")
return geometry_data
async def save_mesh_data(
self,
session: AsyncSession,
stp_file_id: int,
mesh_json: Dict[str, Any],
quality: str = "medium"
) -> MeshData:
"""保存网格数据到 PostgreSQL 元数据 + RustFS 对象存储
mesh_json 为完整网格 JSON(顶点、面、点云等),
PostgreSQL 只存 object_key 和一些摘要字段,详细数据放在 RustFS。
"""
# 1. 获取文件哈希
stp_file = await session.get(STPFile, stp_file_id)
file_hash = stp_file.file_hash
# 2. 上传网格 JSON 到 RustFS
upload_result = await rustfs_manager.upload_json_data(
file_type='mesh_data',
json_data=mesh_json,
file_hash=file_hash
)
# 3. 提取摘要信息
mesh_section = mesh_json.get('mesh', {})
pointcloud_section = mesh_json.get('pointcloud', {})
bbox = mesh_json.get('bounding_box', {})
vertices = mesh_section.get('vertices') or []
faces = mesh_section.get('faces') or []
vertex_count = len(vertices)
face_count = len(faces)
point_count = pointcloud_section.get('count')
# 4. 创建 PostgreSQL 记录
mesh_data = MeshData(
stp_file_id=stp_file_id,
object_key=upload_result['object_key'],
storage_bucket=upload_result['bucket'],
quality=quality,
vertex_count=vertex_count,
face_count=face_count,
point_count=point_count,
bounding_box_min=bbox.get('min'),
bounding_box_max=bbox.get('max')
)
session.add(mesh_data)
await session.commit()
await session.refresh(mesh_data)
logger.info(f"网格数据保存成功 RustFS: {mesh_data.id}")
return mesh_data
async def save_mold_cavity_data(self, session: AsyncSession,
stp_file_id: int,
cavity_json: Dict[str, Any]) -> MoldCavityData:
@@ -388,6 +444,7 @@ class StorageIntegrationService:
'user_id': stp_file.user_id
},
'geometry_data': None,
'mesh_data': None,
'mold_cavity_data': None,
'html_content': None,
'features': [],
@@ -412,6 +469,14 @@ class StorageIntegrationService:
)
result['mold_cavity_data'] = json.loads(cavity_data_bytes.decode('utf-8'))
# 网格数据
if stp_file.mesh_data:
mesh_bytes = await rustfs_manager.download_file(
file_type='mesh_data',
object_key=stp_file.mesh_data.object_key
)
result['mesh_data'] = json.loads(mesh_bytes.decode('utf-8'))
# HTML文件
if stp_file.html_file:
html_bytes = await rustfs_manager.download_file(
@@ -481,6 +546,12 @@ class StorageIntegrationService:
except Exception as e:
logger.error(f"删除型腔数据失败: {e}")
try:
if stp_file.mesh_data:
await rustfs_manager.delete_file('mesh_data', stp_file.mesh_data.object_key)
except Exception as e:
logger.error(f"删除网格数据失败: {e}")
try:
if stp_file.html_file:
await rustfs_manager.delete_file('html_files', stp_file.html_file.object_key)
+2 -1
View File
@@ -27,7 +27,8 @@ class RustFSManager:
# 文件类型前缀(子目录结构)
self.file_types = {
'stp_files': 'stp-files',
'geometry_data': 'geometry',
'geometry_data': 'geometry',
'mesh_data': 'mesh',
'mold_cavities': 'mold-cavities',
'html_files': 'html',
'user_files': 'user-files'