From 44d431f4af7876574b5b24a692522807e595ed44 Mon Sep 17 00:00:00 2001 From: cjw <792430652@qq.com> Date: Mon, 16 Feb 2026 19:06:41 +0800 Subject: [PATCH] deving --- src/api/routes.py | 66 ++++++++++++++++--- src/models/database.py | 36 +++++++++++ src/services/storage_integration_rustfs.py | 73 +++++++++++++++++++++- src/storage/rustfs_storage.py | 3 +- 4 files changed, 168 insertions(+), 10 deletions(-) diff --git a/src/api/routes.py b/src/api/routes.py index 946c3cc..625cd50 100644 --- a/src/api/routes.py +++ b/src/api/routes.py @@ -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, "模具型腔生成完成" diff --git a/src/models/database.py b/src/models/database.py index 5eaceac..5a2c8a4 100644 --- a/src/models/database.py +++ b/src/models/database.py @@ -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"" + +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"" + class HTMLFile(Base): """网页文件元数据表""" __tablename__ = "html_files" diff --git a/src/services/storage_integration_rustfs.py b/src/services/storage_integration_rustfs.py index e327735..c5456ea 100644 --- a/src/services/storage_integration_rustfs.py +++ b/src/services/storage_integration_rustfs.py @@ -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) diff --git a/src/storage/rustfs_storage.py b/src/storage/rustfs_storage.py index 88a4a9c..12ce446 100644 --- a/src/storage/rustfs_storage.py +++ b/src/storage/rustfs_storage.py @@ -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'