From 9882d3becc212ea112ce4d33e9b4b79a1e7294cd Mon Sep 17 00:00:00 2001 From: chenjw28 <792430652@qq.com> Date: Wed, 27 May 2026 14:57:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=BC=E5=87=BAstep=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=90=88=E5=B9=B6=E4=B8=BA=E6=95=B4=E4=BD=93=EF=BC=8C=E6=96=B9?= =?UTF-8?q?=E4=BE=BF=E5=90=8E=E7=BB=AD=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/ai_mold_assistant.py | 9 +++-- src/core/ai_parting_detector.py | 11 +++--- src/core/aluminum_foam_mold.py | 18 ++++----- src/core/base_mold_generator.py | 64 ++++++++++++++++---------------- src/core/cad_exporter.py | 56 +++++++++++++++++----------- src/core/geometry_analyzer.py | 21 ++++++----- src/core/mesh_generator.py | 5 ++- src/core/mold_generator.py | 18 ++++----- src/core/multi_scheme_planner.py | 12 +++--- src/core/side_action_designer.py | 9 +++-- src/core/stp_parser.py | 17 +++++---- 11 files changed, 129 insertions(+), 111 deletions(-) diff --git a/src/core/ai_mold_assistant.py b/src/core/ai_mold_assistant.py index e67aa52..f6a62d8 100644 --- a/src/core/ai_mold_assistant.py +++ b/src/core/ai_mold_assistant.py @@ -6,6 +6,7 @@ AI 分模辅助模型接口示例 """ from typing import Dict, Any, Optional import numpy as np +from OCC.Core.TopoDS import TopoDS_Shape, TopoDS_Face class AIPartingSurfaceDetector: @@ -40,7 +41,7 @@ class AIPartingSurfaceDetector: # self.model = torch.load(model_path) print(f"AI 模型加载:{model_path}") - def detect(self, product_shape: Any, analysis: Dict) -> Optional[Dict]: + def detect(self, product_shape: TopoDS_Shape, analysis: Dict) -> Optional[Dict]: """ 检测最优分型面 @@ -76,7 +77,7 @@ class AIPartingSurfaceDetector: "undercut_regions": [] # 倒扣区域 } - def _preprocess_shape(self, shape: Any, analysis: Dict) -> Any: + def _preprocess_shape(self, shape: TopoDS_Shape, analysis: Dict) -> TopoDS_Shape: """ 预处理产品形状为 AI 模型输入 @@ -110,7 +111,7 @@ class AIDraftAnalyzer: """加载训练好的 AI 模型""" print(f"AI 拔模分析模型加载:{model_path}") - def analyze(self, product_shape: Any, parting_surface: Any, + def analyze(self, product_shape: TopoDS_Shape, parting_surface: TopoDS_Face, base_draft_angle: float) -> Optional[Dict]: """ 分析拔模需求 @@ -156,7 +157,7 @@ class AICavityLayoutOptimizer: if model_path: self._load_model(model_path) - def optimize(self, product_shape: Any, cavity_count: int, + def optimize(self, product_shape: TopoDS_Shape, cavity_count: int, mold_base_size: Dict) -> Optional[Dict]: """ 优化型腔布局 diff --git a/src/core/ai_parting_detector.py b/src/core/ai_parting_detector.py index 76854cb..92c3ecf 100644 --- a/src/core/ai_parting_detector.py +++ b/src/core/ai_parting_detector.py @@ -22,6 +22,7 @@ GNN 模型: from typing import Dict, List, Any, Optional, Tuple import numpy as np +from OCC.Core.TopoDS import TopoDS_Shape from utils.logger import get_logger logger = get_logger(__name__) @@ -47,7 +48,7 @@ except ImportError: class ShapeGraphBuilder: """将 OCC 形状转换为图表示""" - def build_graph(self, shape: Any) -> Optional[Dict]: + def build_graph(self, shape: TopoDS_Shape) -> Optional[Dict]: """ 从 OCC 形状构建图数据 @@ -383,7 +384,7 @@ class AIPartingSurfaceDetectorV2: logger.error(f"GNN 模型加载失败: {e}") self.model = None - def detect(self, product_shape: Any, analysis: Dict) -> Optional[Dict]: + def detect(self, product_shape: TopoDS_Shape, analysis: Dict) -> Optional[Dict]: """ 检测最优分型面 @@ -407,7 +408,7 @@ class AIPartingSurfaceDetectorV2: return self._detect_with_geometry(product_shape, analysis) - def _detect_with_gnn(self, shape: Any, analysis: Dict) -> Optional[Dict]: + def _detect_with_gnn(self, shape: TopoDS_Shape, analysis: Dict) -> Optional[Dict]: """使用 GNN 模型检测分型面""" if not _TORCH_GEOMETRIC_AVAILABLE: return None @@ -457,7 +458,7 @@ class AIPartingSurfaceDetectorV2: logger.warning(f"GNN 检测失败,回退到几何方法: {e}") return None - def _detect_with_geometry(self, shape: Any, analysis: Dict) -> Dict: + def _detect_with_geometry(self, shape: TopoDS_Shape, analysis: Dict) -> Dict: """几何方法回退:基于法向量统计的分型面检测""" try: graph_data = self.graph_builder.build_graph(shape) @@ -504,7 +505,7 @@ class AIPartingSurfaceDetectorV2: "method": "fallback", } - def collect_training_sample(self, shape: Any, analysis: Dict, + def collect_training_sample(self, shape: TopoDS_Shape, analysis: Dict, ground_truth_normal: List[float], ground_truth_origin: List[float]) -> Optional[Dict]: """ diff --git a/src/core/aluminum_foam_mold.py b/src/core/aluminum_foam_mold.py index 2604fcb..23fc9b8 100644 --- a/src/core/aluminum_foam_mold.py +++ b/src/core/aluminum_foam_mold.py @@ -16,7 +16,7 @@ import numpy as np from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeFace from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox from OCC.Core.gp import gp_Pln, gp_Dir, gp_Pnt -from OCC.Core.TopoDS import TopoDS_Face, topods +from OCC.Core.TopoDS import TopoDS_Face, TopoDS_Shape, topods from OCC.Core.BRepAdaptor import BRepAdaptor_Surface from OCC.Core.TopExp import TopExp_Explorer from OCC.Core.TopAbs import TopAbs_FACE @@ -128,7 +128,7 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator): else: logger.warning(f"未知材料 {material}") - def generate_mold_cavities(self, product_shape: Any) -> Dict[str, Any]: + def generate_mold_cavities(self, product_shape: TopoDS_Shape) -> Dict[str, Any]: """ 从产品的3D模型生成型腔和型芯 @@ -292,13 +292,13 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator): # ==================== 核心算法实现 ==================== - def _analyze_product_geometry(self, shape: Any) -> Dict[str, Any]: + def _analyze_product_geometry(self, shape: TopoDS_Shape) -> Dict[str, Any]: """分析产品几何属性(扩展基类版本,增加法向量统计)""" result = super()._analyze_product_geometry(shape) result["normal_statistics"] = self._analyze_parting_direction(shape) return result - def _analyze_parting_direction(self, shape: Any) -> Dict[str, float]: + def _analyze_parting_direction(self, shape: TopoDS_Shape) -> Dict[str, float]: """分析产品法向量分布,按面积加权统计各轴方向强度""" stats = {"X": 0.0, "Y": 0.0, "Z": 0.0} explorer = TopExp_Explorer(shape, TopAbs_FACE) @@ -328,11 +328,11 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator): for axis, value in stats.items() } - def _split_cavity_core(self, shape: Any, parting_surface: Any) -> Tuple[Any, Any]: + def _split_cavity_core(self, shape: TopoDS_Shape, parting_surface: TopoDS_Face) -> Tuple[TopoDS_Shape, TopoDS_Shape]: """分离型腔和型芯(铝泡沫使用更大余量)""" return super()._split_cavity_core(shape, parting_surface, margin=25) - def _detect_parting_surfaces(self, shape: Any, analysis: Dict) -> Dict[str, Any]: + def _detect_parting_surfaces(self, shape: TopoDS_Shape, analysis: Dict) -> Dict[str, Any]: """ 检测分型面(泡沫模具专用) @@ -470,7 +470,7 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator): except Exception: return 50.0 - def _generate_mold_block(self, cavity: Any, analysis: Dict) -> Any: + def _generate_mold_block(self, cavity: TopoDS_Shape, analysis: Dict) -> TopoDS_Shape: """生成完整的模具块(包含A/B板结构)""" try: bbox = analysis["bounding_box"] @@ -493,7 +493,7 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator): logger.error(f"模具块生成失败: {e}") return cavity - def _extract_parting_surface_geometry(self, surface: Any) -> Dict[str, Any]: + def _extract_parting_surface_geometry(self, surface: TopoDS_Face) -> Dict[str, Any]: """提取分型面几何数据""" metadata = self._extract_plane_metadata(surface) return { @@ -504,7 +504,7 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator): } def _create_parting_surface_from_ai(self, ai_result: Dict, analysis: Dict, - shape: Any = None) -> Dict: + shape: Optional[TopoDS_Shape] = None) -> Dict: """从 AI 结果创建分型面""" origin = ai_result.get("origin", [0, 0, 0]) normal = ai_result.get("normal", [0, 0, 1]) diff --git a/src/core/base_mold_generator.py b/src/core/base_mold_generator.py index 42a2ac1..22bcbd9 100644 --- a/src/core/base_mold_generator.py +++ b/src/core/base_mold_generator.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Any, Tuple, Optional +from typing import Dict, List, Any, Tuple, Optional, TYPE_CHECKING import math import numpy as np from OCC.Core.BRepOffsetAPI import BRepOffsetAPI_DraftAngle @@ -6,7 +6,7 @@ from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Cut, BRepAlgoAPI_Section, BRepAlgoA from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeFace, BRepBuilderAPI_Transform from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakeHalfSpace from OCC.Core.gp import gp_Pln, gp_Dir, gp_Pnt, gp_Trsf, gp_Ax2 -from OCC.Core.TopoDS import TopoDS_Face, TopoDS_Compound, topods +from OCC.Core.TopoDS import TopoDS_Shape, TopoDS_Face, TopoDS_Compound, topods from OCC.Core.BRep import BRep_Tool, BRep_Builder from OCC.Core.BRepMesh import BRepMesh_IncrementalMesh from OCC.Core.GProp import GProp_GProps @@ -41,7 +41,7 @@ class BaseMoldGenerator: self.ai_draft_analyzer = draft_analyzer logger.info("AI 模型接口已设置") - def _apply_shrinkage_compensation(self, shape: Any) -> Any: + def _apply_shrinkage_compensation(self, shape: TopoDS_Shape) -> TopoDS_Shape: scale_factor = 1.0 + self.shrinkage_rate trsf = gp_Trsf() trsf.SetScale(gp_Pnt(0, 0, 0), scale_factor) @@ -53,7 +53,7 @@ class BaseMoldGenerator: logger.warning(f"收缩率补偿失败: {e}") return shape - def _apply_draft_angles(self, shape: Any, parting_surface: Any) -> Any: + def _apply_draft_angles(self, shape: TopoDS_Shape, parting_surface: TopoDS_Face) -> TopoDS_Shape: try: draft_direction = self._get_draft_direction(parting_surface) if draft_direction is None: @@ -76,7 +76,7 @@ class BaseMoldGenerator: logger.warning(f"拔模角处理失败,返回原始形状: {e}") return shape - def _get_draft_direction(self, parting_surface: Any) -> Optional[gp_Dir]: + def _get_draft_direction(self, parting_surface: TopoDS_Face) -> Optional[gp_Dir]: try: surface = BRepAdaptor_Surface(parting_surface) if surface.GetType() == 0: @@ -85,7 +85,7 @@ class BaseMoldGenerator: except Exception: return gp_Dir(0, 0, 1) - def _find_draftable_faces(self, shape: Any, draft_direction: gp_Dir) -> List[Any]: + def _find_draftable_faces(self, shape: TopoDS_Shape, draft_direction: gp_Dir) -> List[TopoDS_Face]: draftable = [] explorer = TopExp_Explorer(shape, TopAbs_FACE) @@ -103,7 +103,7 @@ class BaseMoldGenerator: return draftable - def _get_face_normal(self, face: Any) -> Optional[gp_Dir]: + def _get_face_normal(self, face: TopoDS_Face) -> Optional[gp_Dir]: try: surface = BRepAdaptor_Surface(face) u = (surface.FirstUParameter() + surface.LastUParameter()) / 2 @@ -122,8 +122,8 @@ class BaseMoldGenerator: except Exception: return None - def _execute_draft(self, shape: Any, faces: List[Any], - draft_direction: gp_Dir, draft_angle_rad: float) -> Any: + def _execute_draft(self, shape: TopoDS_Shape, faces: List[TopoDS_Face], + draft_direction: gp_Dir, draft_angle_rad: float) -> TopoDS_Shape: try: draft = BRepOffsetAPI_DraftAngle(shape) @@ -156,8 +156,8 @@ class BaseMoldGenerator: logger.warning(f"拔模执行失败: {e}") return shape - def _draft_faces_sequentially(self, shape: Any, faces: List[Any], - draft_direction: gp_Dir, draft_angle_rad: float) -> Any: + def _draft_faces_sequentially(self, shape: TopoDS_Shape, faces: List[TopoDS_Face], + draft_direction: gp_Dir, draft_angle_rad: float) -> TopoDS_Shape: current_shape = shape success_count = 0 @@ -190,7 +190,7 @@ class BaseMoldGenerator: return current_shape - def _analyze_product_geometry(self, shape: Any) -> Dict[str, Any]: + def _analyze_product_geometry(self, shape: TopoDS_Shape) -> Dict[str, Any]: try: props = GProp_GProps() brepgprop.VolumeProperties(shape, props) @@ -224,7 +224,7 @@ class BaseMoldGenerator: logger.error(f"产品几何分析失败: {e}") raise - def _split_cavity_core(self, shape: Any, parting_surface: Any, margin: int = 20) -> Tuple[Any, Any]: + def _split_cavity_core(self, shape: TopoDS_Shape, parting_surface: TopoDS_Face, margin: int = 20) -> Tuple[TopoDS_Shape, TopoDS_Shape]: """ 分离型腔和型芯 — 完全嵌入 + 突出贴合方式。 @@ -274,7 +274,7 @@ class BaseMoldGenerator: return self._split_cavity_core_fallback(shape, None) @staticmethod - def _extract_parting_normal(parting_surface: Any) -> List[float]: + def _extract_parting_normal(parting_surface: TopoDS_Face) -> List[float]: """从分型面提取法向量""" try: surface = BRepAdaptor_Surface(parting_surface) @@ -288,14 +288,14 @@ class BaseMoldGenerator: def _build_core_with_base( self, - shape: Any, - mold_block: Any, + shape: TopoDS_Shape, + mold_block: TopoDS_Shape, parting_plane: gp_Pln, mold_xmin: float, mold_ymin: float, mold_zmin: float, mold_xmax: float, mold_ymax: float, mold_zmax: float, xmin: float, ymin: float, zmin: float, xmax: float, ymax: float, zmax: float, - ) -> Any: + ) -> TopoDS_Shape: """ 构建带底座的型芯。 @@ -353,7 +353,7 @@ class BaseMoldGenerator: return self._build_core_compound(base_plate, shape) @staticmethod - def _build_core_compound(base_plate: Any, shape: Any) -> Any: + def _build_core_compound(base_plate: TopoDS_Shape, shape: TopoDS_Shape) -> TopoDS_Shape: """ 兜底方案:构建 TopoDS_Compound 包含底座平板 + 产品。 即使布尔融合失败,底座也绝不会丢失。 @@ -366,7 +366,7 @@ class BaseMoldGenerator: logger.info("型芯 Compound 兜底构建 (底座+产品)") return compound - def _get_parting_plane(self, parting_surface: Any, shape: Any) -> Optional[gp_Pln]: + def _get_parting_plane(self, parting_surface: TopoDS_Face, shape: TopoDS_Shape) -> Optional[gp_Pln]: """从分型面提取平面方程""" try: surface = BRepAdaptor_Surface(parting_surface) @@ -383,8 +383,8 @@ class BaseMoldGenerator: logger.warning(f"分型面平面提取失败: {e}") return None - def _split_mold_block_by_plane(self, mold_block: Any, - parting_plane: gp_Pln) -> Tuple[Any, Any]: + def _split_mold_block_by_plane(self, mold_block: TopoDS_Shape, + parting_plane: gp_Pln) -> Tuple[TopoDS_Shape, TopoDS_Shape]: """ 用分型面将模具块切分为A板(上模)和B板(下模) @@ -439,8 +439,8 @@ class BaseMoldGenerator: logger.error(f"A/B板分离失败: {e}") return None, None - def _subtract_product_from_plate(self, plate: Any, product: Any, - plate_name: str) -> Any: + def _subtract_product_from_plate(self, plate: TopoDS_Shape, product: TopoDS_Shape, + plate_name: str) -> TopoDS_Shape: """从模板中减去产品形状,生成型腔或型芯""" try: cut_op = BRepAlgoAPI_Cut(plate, product) @@ -455,8 +455,8 @@ class BaseMoldGenerator: logger.warning(f"{plate_name}减产品失败: {e}") return plate - def _split_cavity_core_fallback(self, shape: Any, - mold_block: Optional[Any] = None) -> Tuple[Any, Any]: + def _split_cavity_core_fallback(self, shape: TopoDS_Shape, + mold_block: Optional[TopoDS_Shape] = None) -> Tuple[TopoDS_Shape, TopoDS_Shape]: """ 分模回退方案:完全嵌入 + 突出贴合,用 Z 中心面做分型基准。 """ @@ -507,7 +507,7 @@ class BaseMoldGenerator: except Exception: return shape, shape - def detect_insert_regions(self, shape: Any, analysis: Dict, + def detect_insert_regions(self, shape: TopoDS_Shape, analysis: Dict, depth_threshold: float = 30.0, aspect_threshold: float = 3.0) -> List[Dict[str, Any]]: """ @@ -618,7 +618,7 @@ class BaseMoldGenerator: return inserts - def _extract_shape_geometry(self, shape: Any, shape_type: str) -> Dict[str, Any]: + def _extract_shape_geometry(self, shape: TopoDS_Shape, shape_type: str) -> Dict[str, Any]: try: mesh = BRepMesh_IncrementalMesh(shape, 0.1) mesh.Perform() @@ -678,7 +678,7 @@ class BaseMoldGenerator: "face_count": 0, } - def _extract_plane_metadata(self, surface: Any) -> Dict[str, Any]: + def _extract_plane_metadata(self, surface: TopoDS_Shape) -> Dict[str, Any]: """从分型面提取平面元数据(法向量、原点、边界)""" metadata = { "normal": [0.0, 0.0, 1.0], @@ -743,7 +743,7 @@ class BaseMoldGenerator: return total_length - def _calculate_parting_line(self, shape: Any, parting_surface: Any) -> List[List[float]]: + def _calculate_parting_line(self, shape: TopoDS_Shape, parting_surface: TopoDS_Face) -> List[List[float]]: try: section = BRepAlgoAPI_Section(shape, parting_surface) section.Build() @@ -783,7 +783,7 @@ class BaseMoldGenerator: logger.error(f"分型线计算失败: {e}") return self._simple_parting_line(shape) - def _simple_parting_line(self, shape: Any) -> List[List[float]]: + def _simple_parting_line(self, shape: TopoDS_Shape) -> List[List[float]]: try: bbox = Bnd_Box() brepbndlib.Add(shape, bbox) @@ -800,8 +800,8 @@ class BaseMoldGenerator: except Exception: return [[-50, -50, 0], [50, -50, 0], [50, 50, 0], [-50, 50, 0], [-50, -50, 0]] - def extend_parting_surface(self, parting_surface: Any, shape: Any, - extension: float = 30.0) -> Any: + def extend_parting_surface(self, parting_surface: TopoDS_Face, shape: TopoDS_Shape, + extension: float = 30.0) -> TopoDS_Face: """ 将分型面延伸到模具块边界 diff --git a/src/core/cad_exporter.py b/src/core/cad_exporter.py index 2fa1980..98127cc 100644 --- a/src/core/cad_exporter.py +++ b/src/core/cad_exporter.py @@ -29,6 +29,7 @@ import os import re from typing import Dict, List, Any, Optional, Tuple from pathlib import Path +from OCC.Core.TopoDS import TopoDS_Shape from utils.logger import get_logger logger = get_logger(__name__) @@ -70,7 +71,7 @@ class CADExporter: relative = Path(os.path.basename(filepath)) return relative.as_posix() - def export_step(self, shape: Any, filepath: str, + def export_step(self, shape: TopoDS_Shape, filepath: str, schema: str = "AP214") -> bool: """ 导出 STEP 文件 @@ -118,7 +119,7 @@ class CADExporter: logger.error(f"STEP 导出失败: {e}") return False - def export_iges(self, shape: Any, filepath: str) -> bool: + def export_iges(self, shape: TopoDS_Shape, filepath: str) -> bool: """ 导出 IGES 文件 @@ -156,7 +157,7 @@ class CADExporter: logger.error(f"IGES 导出失败: {e}") return False - def export_stl(self, shape: Any, filepath: str, + def export_stl(self, shape: TopoDS_Shape, filepath: str, ascii_mode: bool = True, deflection: float = 0.1) -> bool: """ @@ -201,7 +202,7 @@ class CADExporter: logger.error(f"STL 导出失败: {e}") return False - def export_brep(self, shape: Any, filepath: str) -> bool: + def export_brep(self, shape: TopoDS_Shape, filepath: str) -> bool: """ 导出 BRep 文件(OpenCASCADE 原生格式) @@ -240,18 +241,6 @@ class CADExporter: components: List[str] = None, task_id: Optional[str] = None, scheme_id: Optional[str] = None) -> Dict[str, Any]: - """ - 批量导出模具设计结果 - - Args: - cavity_data: generate_mold_cavities() 的返回结果 - base_filename: 基础文件名(不含扩展名) - formats: 导出格式列表 ["step", "iges", "stl", "brep"] - components: 导出组件列表 ["cavity", "core", "parting_surface", "all"] - - Returns: - 导出结果摘要 - """ if formats is None: formats = ["step", "stl"] if components is None: @@ -279,7 +268,8 @@ class CADExporter: "parting_surface": ("parting_surface", "分型面"), } - shapes_to_export = [] + shapes_to_export: List[Tuple[str, str, TopoDS_Shape]] = [] + assembly_shapes: List[Tuple[TopoDS_Shape, str]] = [] for comp in components: if comp == "all": @@ -287,23 +277,45 @@ class CADExporter: shape = cavity_data.get(data_key) if shape is not None: shapes_to_export.append((key, label, shape)) + assembly_shapes.append((shape, label)) break elif comp in shape_map: data_key, label = shape_map[comp] shape = cavity_data.get(data_key) if shape is not None: shapes_to_export.append((comp, label, shape)) + assembly_shapes.append((shape, label)) else: results["errors"].append(f"{label}形状不可用") + # STEP: 所有组件合并为一个装配体文件 + if "step" in formats and assembly_shapes: + filepath = os.path.join(export_dir, f"{base_filename}_mold.step") + success = self.export_assembly_step(assembly_shapes, filepath) + if success: + file_size = os.path.getsize(filepath) + relative_path = self.get_relative_path(filepath) + results["files"].append({ + "component": "assembly", + "component_label": "模具装配体", + "format": "step", + "filepath": filepath, + "relative_path": relative_path, + "filename": os.path.basename(filepath), + "size_bytes": file_size, + "size_readable": self._format_file_size(file_size), + }) + else: + results["errors"].append("装配体 STEP 导出失败") + + # IGES / STL / BRep: 逐组件导出 + non_assembly_formats = [f for f in formats if f != "step"] for comp_name, label, shape in shapes_to_export: - for fmt in formats: + for fmt in non_assembly_formats: filepath = os.path.join(export_dir, f"{base_filename}_{comp_name}.{fmt}") success = False - if fmt == "step": - success = self.export_step(shape, filepath) - elif fmt == "iges": + if fmt == "iges": success = self.export_iges(shape, filepath) elif fmt == "stl": success = self.export_stl(shape, filepath) @@ -337,7 +349,7 @@ class CADExporter: return results - def export_assembly_step(self, shapes_with_names: List[Tuple[Any, str]], + def export_assembly_step(self, shapes_with_names: List[Tuple[TopoDS_Shape, str]], filepath: str, schema: str = "AP214") -> bool: """ diff --git a/src/core/geometry_analyzer.py b/src/core/geometry_analyzer.py index 36781f4..8fa2aed 100644 --- a/src/core/geometry_analyzer.py +++ b/src/core/geometry_analyzer.py @@ -1,6 +1,7 @@ from typing import Dict, List, Any, Optional import math import numpy as np +from OCC.Core.TopoDS import TopoDS_Shape from models.schemas import ( create_mold_feature, create_design_recommendation, @@ -38,7 +39,7 @@ class GeometryAnalyzer: def analyze_mold_design(self, geometry_data: Dict[str, Any], product_material: str = "ABS", mold_material: str = "Aluminum", - shape: Any = None + shape: Optional[TopoDS_Shape] = None ) -> Dict[str, Any]: """分析模具设计 @@ -72,7 +73,7 @@ class GeometryAnalyzer: ) def _detect_features(self, geometry_data: Dict[str, Any], - shape: Any = None) -> List[Dict[str, Any]]: + shape: Optional[TopoDS_Shape] = None) -> List[Dict[str, Any]]: """检测模具特征""" features = [] @@ -99,7 +100,7 @@ class GeometryAnalyzer: return features def _detect_wall_features(self, geometry_data: Dict[str, Any], - shape: Any = None) -> List[Dict[str, Any]]: + shape: Optional[TopoDS_Shape] = None) -> List[Dict[str, Any]]: """检测壁厚特征""" features = [] @@ -230,7 +231,7 @@ class GeometryAnalyzer: return features - def _compute_precise_wall_thickness(self, shape: Any) -> Optional[Dict[str, Any]]: + def _compute_precise_wall_thickness(self, shape: TopoDS_Shape) -> Optional[Dict[str, Any]]: """使用 BRepExtrema_DistShapeShape 精确计算壁厚""" try: from OCC.Core.TopExp import TopExp_Explorer @@ -319,7 +320,7 @@ class GeometryAnalyzer: return None def _detect_rib_features(self, geometry_data: Dict[str, Any], - shape: Any = None) -> List[Dict[str, Any]]: + shape: Optional[TopoDS_Shape] = None) -> List[Dict[str, Any]]: """检测加强筋特征""" features = [] topology = geometry_data.get("topology", {}) @@ -350,7 +351,7 @@ class GeometryAnalyzer: return features def _detect_boss_features(self, geometry_data: Dict[str, Any], - shape: Any = None) -> List[Dict[str, Any]]: + shape: Optional[TopoDS_Shape] = None) -> List[Dict[str, Any]]: """检测BOSS柱特征""" features = [] volume = geometry_data.get("volume", 0) @@ -382,7 +383,7 @@ class GeometryAnalyzer: return features def _analyze_draft_angles(self, geometry_data: Dict[str, Any], - shape: Any = None) -> List[Dict[str, Any]]: + shape: Optional[TopoDS_Shape] = None) -> List[Dict[str, Any]]: """分析拔模角度""" features = [] @@ -450,7 +451,7 @@ class GeometryAnalyzer: return features - def _compute_draft_angles_from_shape(self, shape: Any) -> Optional[Dict[str, Any]]: + def _compute_draft_angles_from_shape(self, shape: TopoDS_Shape) -> Optional[Dict[str, Any]]: """基于面法向量分析计算各面的拔模角度""" try: from OCC.Core.TopExp import TopExp_Explorer @@ -516,7 +517,7 @@ class GeometryAnalyzer: logger.warning(f"拔模角度计算失败: {e}") return None - def _detect_curvature_features(self, shape: Any) -> List[Dict[str, Any]]: + def _detect_curvature_features(self, shape: TopoDS_Shape) -> List[Dict[str, Any]]: """检测高曲率区域(可能导致应力集中)""" features = [] try: @@ -604,7 +605,7 @@ class GeometryAnalyzer: return features - def _detect_fillet_features(self, shape: Any) -> List[Dict[str, Any]]: + def _detect_fillet_features(self, shape: TopoDS_Shape) -> List[Dict[str, Any]]: """检测圆角/倒角特征""" features = [] try: diff --git a/src/core/mesh_generator.py b/src/core/mesh_generator.py index 817501a..7eb3013 100644 --- a/src/core/mesh_generator.py +++ b/src/core/mesh_generator.py @@ -8,6 +8,7 @@ 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.TopoDS import TopoDS_Shape from OCC.Core.TopLoc import TopLoc_Location logger = logging.getLogger(__name__) @@ -24,7 +25,7 @@ class MeshGenerator: } self.quality = self.quality_settings.get(quality, 0.3) - def generate_mesh_from_shape(self, shape, num_points: int = 20000) -> Dict: + def generate_mesh_from_shape(self, shape: TopoDS_Shape, num_points: int = 20000) -> Dict: """从PythonOCC形状生成点云数据""" try: mesh = BRepMesh_IncrementalMesh(shape, self.quality, False, 0.5, True) @@ -121,7 +122,7 @@ class MeshGenerator: logger.error(traceback.format_exc()) return self._create_sample_pointcloud() - def generate_multi_lod_mesh(self, shape) -> Dict: + def generate_multi_lod_mesh(self, shape: TopoDS_Shape) -> Dict: """生成多级LOD网格 - 一次OCC剖分,trimesh简化,避免重复计算 返回结构: diff --git a/src/core/mold_generator.py b/src/core/mold_generator.py index e13b93b..5e7a759 100644 --- a/src/core/mold_generator.py +++ b/src/core/mold_generator.py @@ -2,7 +2,7 @@ from typing import Dict, List, Any, Tuple, Optional import numpy as np from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeFace from OCC.Core.gp import gp_Pln, gp_Dir, gp_Pnt -from OCC.Core.TopoDS import TopoDS_Face, topods +from OCC.Core.TopoDS import TopoDS_Face, TopoDS_Shape, topods from OCC.Core.BRepAdaptor import BRepAdaptor_Surface from OCC.Core.TopExp import TopExp_Explorer from OCC.Core.TopAbs import TopAbs_FACE @@ -47,7 +47,7 @@ class MoldCavityGenerator(BaseMoldGenerator): else: logger.warning(f"未知材料 {material}, 使用默认密度 {self.material_density} g/cm³") - def generate_mold_cavities(self, product_shape: Any) -> Dict[str, Any]: + def generate_mold_cavities(self, product_shape: TopoDS_Shape) -> Dict[str, Any]: """ 从产品的3D模型生成型腔和型芯 @@ -196,7 +196,7 @@ class MoldCavityGenerator(BaseMoldGenerator): # ==================== 内部方法 ==================== - def _detect_parting_surface(self, shape: Any, analysis: Dict) -> Tuple[Any, List]: + def _detect_parting_surface(self, shape: TopoDS_Shape, analysis: Dict) -> Tuple[TopoDS_Face, List]: """ 检测分型面和分型线 @@ -219,7 +219,7 @@ class MoldCavityGenerator(BaseMoldGenerator): logger.info("使用简化方法检测分型面") return self._simple_parting_surface(shape, analysis) - def _detect_primary_parting(self, shape: Any, analysis: Dict) -> Dict[str, Any]: + def _detect_primary_parting(self, shape: TopoDS_Shape, analysis: Dict) -> Dict[str, Any]: """检测主分型面(AI优先 → 几何法向量 → 简化回退)""" if self.ai_parting_detector is not None: try: @@ -283,7 +283,7 @@ class MoldCavityGenerator(BaseMoldGenerator): logger.info(f"转换得到 {len(regions)} 个兼容倒扣区域") return regions - def _analyze_face_normals(self, shape: Any) -> gp_Dir: + def _analyze_face_normals(self, shape: TopoDS_Shape) -> gp_Dir: """ 分析产品表面的法向量分布,找出最优分型方向 @@ -326,7 +326,7 @@ class MoldCavityGenerator(BaseMoldGenerator): else: return gp_Dir(0, 0, 1) - def _create_optimal_parting_plane(self, shape: Any, analysis: Dict, + def _create_optimal_parting_plane(self, shape: TopoDS_Shape, analysis: Dict, direction: gp_Dir) -> gp_Pln: """ 创建最优分型面 @@ -352,7 +352,7 @@ class MoldCavityGenerator(BaseMoldGenerator): return parting_plane - def _simple_parting_surface(self, shape: Any, analysis: Dict) -> Tuple[Any, List]: + def _simple_parting_surface(self, shape: TopoDS_Shape, analysis: Dict) -> Tuple[TopoDS_Face, List]: """简化的分型面检测(回退方案)""" bbox = analysis["bounding_box"] center_z = bbox["center"][2] @@ -372,7 +372,7 @@ class MoldCavityGenerator(BaseMoldGenerator): return parting_surface, parting_line def _create_parting_surface_from_ai(self, ai_result: Dict, - analysis: Dict, shape: Any = None) -> Tuple[Any, List]: + analysis: Dict, shape: Optional[TopoDS_Shape] = None) -> Tuple[TopoDS_Face, List]: """ 从 AI 模型结果创建分型面(预留接口) @@ -405,7 +405,7 @@ class MoldCavityGenerator(BaseMoldGenerator): logger.info(f"从 AI 结果创建分型面:原点={origin}, 法向量={normal}") return parting_surface, parting_line - def _extract_parting_surface_geometry(self, surface: Any) -> Dict[str, Any]: + def _extract_parting_surface_geometry(self, surface: TopoDS_Face) -> Dict[str, Any]: """提取分型面几何数据""" metadata = self._extract_plane_metadata(surface) diff --git a/src/core/multi_scheme_planner.py b/src/core/multi_scheme_planner.py index 874b3be..885aaec 100644 --- a/src/core/multi_scheme_planner.py +++ b/src/core/multi_scheme_planner.py @@ -6,7 +6,7 @@ from OCC.Core.GProp import GProp_GProps from OCC.Core.gp import gp_Dir, gp_Pln, gp_Pnt from OCC.Core.TopAbs import TopAbs_FACE from OCC.Core.TopExp import TopExp_Explorer -from OCC.Core.TopoDS import TopoDS_Face, topods +from OCC.Core.TopoDS import TopoDS_Face, TopoDS_Shape, topods from core.mold_generator import MoldCavityGenerator from core.aluminum_foam_mold import AluminumFoamMoldGenerator @@ -31,7 +31,7 @@ class MultiSchemeMoldPlanner: def generate_plan( self, - shape: Any, + shape: TopoDS_Shape, material: Dict[str, Any], is_foam_material: bool = False, max_schemes: int = 3, @@ -92,7 +92,7 @@ class MultiSchemeMoldPlanner: def _build_scheme( self, generator: Any, - shape: Any, + shape: TopoDS_Shape, analysis: Dict[str, Any], candidate: Dict[str, Any], is_foam_material: bool, @@ -209,10 +209,10 @@ class MultiSchemeMoldPlanner: generator: Any, analysis: Dict[str, Any], direction_vector: List[float], - shape: Any, + shape: TopoDS_Shape, offset_ratio: float = 0.0, opening_span_mm: Optional[float] = None, - ) -> Any: + ) -> TopoDS_Face: center = analysis.get("bounding_box", {}).get("center", [0, 0, 0]) dims = analysis.get("bounding_box", {}).get("dimensions", [100, 100, 100]) span = max(dims) * 1.5 + 30 @@ -272,7 +272,7 @@ class MultiSchemeMoldPlanner: return variants - def _collect_axis_normal_stats(self, generator: Any, shape: Any) -> Dict[str, float]: + def _collect_axis_normal_stats(self, generator: Any, shape: TopoDS_Shape) -> Dict[str, float]: """按坐标轴统计面法向分布强度,用于候选方向排序。""" stats = {"X": 0.0, "Y": 0.0, "Z": 0.0} explorer = TopExp_Explorer(shape, TopAbs_FACE) diff --git a/src/core/side_action_designer.py b/src/core/side_action_designer.py index 88dac99..afeaa40 100644 --- a/src/core/side_action_designer.py +++ b/src/core/side_action_designer.py @@ -21,6 +21,7 @@ from typing import Dict, List, Any, Optional, Tuple import math import numpy as np +from OCC.Core.TopoDS import TopoDS_Shape, TopoDS_Face from utils.logger import get_logger logger = get_logger(__name__) @@ -29,8 +30,8 @@ logger = get_logger(__name__) class UndercutDetector: """倒扣区域检测器""" - def detect_undercuts(self, shape: Any, parting_direction: List[float], - parting_surface: Any = None) -> Dict[str, Any]: + def detect_undercuts(self, shape: TopoDS_Shape, parting_direction: List[float], + parting_surface: Optional[TopoDS_Face] = None) -> Dict[str, Any]: """ 检测产品中的倒扣区域 @@ -443,8 +444,8 @@ class SideActionDesigner: self.slider_designer = SliderMechanismDesigner() self.lifter_designer = LifterMechanismDesigner() - def analyze_and_design(self, shape: Any, parting_direction: List[float], - mold_size: Dict, parting_surface: Any = None) -> Dict[str, Any]: + def analyze_and_design(self, shape: TopoDS_Shape, parting_direction: List[float], + mold_size: Dict, parting_surface: Optional[TopoDS_Face] = None) -> Dict[str, Any]: """ 综合分析倒扣并设计侧向分型机构 diff --git a/src/core/stp_parser.py b/src/core/stp_parser.py index 5ff1d48..18a6f72 100644 --- a/src/core/stp_parser.py +++ b/src/core/stp_parser.py @@ -6,6 +6,7 @@ import json from utils.logger import get_logger from OCC.Core.GProp import GProp_GProps from OCC.Core.BRepGProp import brepgprop +from OCC.Core.TopoDS import TopoDS_Shape logger = get_logger(__name__) @@ -29,7 +30,7 @@ class STPParser: - def load_step_file(self, file_path: Path) -> Any: + def load_step_file(self, file_path: Path) -> TopoDS_Shape: """加载STP文件""" try: from OCC.Core.STEPControl import STEPControl_Reader @@ -51,7 +52,7 @@ class STPParser: logger.error(f"STP解析失败: {e}") raise - def analyze_geometry(self, shape) -> Dict[str, Any]: + def analyze_geometry(self, shape: TopoDS_Shape) -> Dict[str, Any]: """分析几何属性""" try: @@ -97,7 +98,7 @@ class STPParser: logger.error(f"几何分析失败: {e}") raise - def _compute_bounding_box(self, shape) -> Dict[str, Any]: + def _compute_bounding_box(self, shape: TopoDS_Shape) -> Dict[str, Any]: """计算边界框""" try: from OCC.Core.Bnd import Bnd_Box @@ -125,7 +126,7 @@ class STPParser: logger.error(f"边界框计算失败: {e}") return self._default_bounding_box() - def _compute_volume(self, shape) -> float: + def _compute_volume(self, shape: TopoDS_Shape) -> float: """计算体积""" try: from OCC.Core.GProp import GProp_GProps @@ -141,7 +142,7 @@ class STPParser: logger.error(f"体积计算失败: {e}") raise RuntimeError(f"体积计算失败: {e}") from e - def _compute_surface_area(self, shape) -> float: + def _compute_surface_area(self, shape: TopoDS_Shape) -> float: """计算表面积""" try: from OCC.Core.GProp import GProp_GProps @@ -175,7 +176,7 @@ class STPParser: logger.error(f"表面积计算失败: {e}") raise RuntimeError(f"表面积计算失败: {e}") from e - def _compute_center_of_mass(self, shape) -> List[float]: + def _compute_center_of_mass(self, shape: TopoDS_Shape) -> List[float]: """计算质心""" try: from OCC.Core.GProp import GProp_GProps @@ -194,7 +195,7 @@ class STPParser: except Exception: raise RuntimeError(f"质心计算失败且边界框回退也失败: {e}") from e - def _compute_inertia_properties(self, shape) -> Dict[str, Any]: + def _compute_inertia_properties(self, shape: TopoDS_Shape) -> Dict[str, Any]: """计算惯性属性""" try: from OCC.Core.GProp import GProp_GProps @@ -216,7 +217,7 @@ class STPParser: logger.error(f"惯性属性计算失败: {e}") return {} - def _analyze_topology(self, shape) -> Dict[str, int]: + def _analyze_topology(self, shape: TopoDS_Shape) -> Dict[str, int]: """分析拓扑""" try: from OCC.Core.TopExp import TopExp_Explorer