导出step文件合并为整体,方便后续修改
This commit is contained in:
@@ -6,6 +6,7 @@ AI 分模辅助模型接口示例
|
|||||||
"""
|
"""
|
||||||
from typing import Dict, Any, Optional
|
from typing import Dict, Any, Optional
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from OCC.Core.TopoDS import TopoDS_Shape, TopoDS_Face
|
||||||
|
|
||||||
|
|
||||||
class AIPartingSurfaceDetector:
|
class AIPartingSurfaceDetector:
|
||||||
@@ -40,7 +41,7 @@ class AIPartingSurfaceDetector:
|
|||||||
# self.model = torch.load(model_path)
|
# self.model = torch.load(model_path)
|
||||||
print(f"AI 模型加载:{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": [] # 倒扣区域
|
"undercut_regions": [] # 倒扣区域
|
||||||
}
|
}
|
||||||
|
|
||||||
def _preprocess_shape(self, shape: Any, analysis: Dict) -> Any:
|
def _preprocess_shape(self, shape: TopoDS_Shape, analysis: Dict) -> TopoDS_Shape:
|
||||||
"""
|
"""
|
||||||
预处理产品形状为 AI 模型输入
|
预处理产品形状为 AI 模型输入
|
||||||
|
|
||||||
@@ -110,7 +111,7 @@ class AIDraftAnalyzer:
|
|||||||
"""加载训练好的 AI 模型"""
|
"""加载训练好的 AI 模型"""
|
||||||
print(f"AI 拔模分析模型加载:{model_path}")
|
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]:
|
base_draft_angle: float) -> Optional[Dict]:
|
||||||
"""
|
"""
|
||||||
分析拔模需求
|
分析拔模需求
|
||||||
@@ -156,7 +157,7 @@ class AICavityLayoutOptimizer:
|
|||||||
if model_path:
|
if model_path:
|
||||||
self._load_model(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]:
|
mold_base_size: Dict) -> Optional[Dict]:
|
||||||
"""
|
"""
|
||||||
优化型腔布局
|
优化型腔布局
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ GNN 模型:
|
|||||||
|
|
||||||
from typing import Dict, List, Any, Optional, Tuple
|
from typing import Dict, List, Any, Optional, Tuple
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from OCC.Core.TopoDS import TopoDS_Shape
|
||||||
from utils.logger import get_logger
|
from utils.logger import get_logger
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
@@ -47,7 +48,7 @@ except ImportError:
|
|||||||
class ShapeGraphBuilder:
|
class ShapeGraphBuilder:
|
||||||
"""将 OCC 形状转换为图表示"""
|
"""将 OCC 形状转换为图表示"""
|
||||||
|
|
||||||
def build_graph(self, shape: Any) -> Optional[Dict]:
|
def build_graph(self, shape: TopoDS_Shape) -> Optional[Dict]:
|
||||||
"""
|
"""
|
||||||
从 OCC 形状构建图数据
|
从 OCC 形状构建图数据
|
||||||
|
|
||||||
@@ -383,7 +384,7 @@ class AIPartingSurfaceDetectorV2:
|
|||||||
logger.error(f"GNN 模型加载失败: {e}")
|
logger.error(f"GNN 模型加载失败: {e}")
|
||||||
self.model = None
|
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)
|
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 模型检测分型面"""
|
"""使用 GNN 模型检测分型面"""
|
||||||
if not _TORCH_GEOMETRIC_AVAILABLE:
|
if not _TORCH_GEOMETRIC_AVAILABLE:
|
||||||
return None
|
return None
|
||||||
@@ -457,7 +458,7 @@ class AIPartingSurfaceDetectorV2:
|
|||||||
logger.warning(f"GNN 检测失败,回退到几何方法: {e}")
|
logger.warning(f"GNN 检测失败,回退到几何方法: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _detect_with_geometry(self, shape: Any, analysis: Dict) -> Dict:
|
def _detect_with_geometry(self, shape: TopoDS_Shape, analysis: Dict) -> Dict:
|
||||||
"""几何方法回退:基于法向量统计的分型面检测"""
|
"""几何方法回退:基于法向量统计的分型面检测"""
|
||||||
try:
|
try:
|
||||||
graph_data = self.graph_builder.build_graph(shape)
|
graph_data = self.graph_builder.build_graph(shape)
|
||||||
@@ -504,7 +505,7 @@ class AIPartingSurfaceDetectorV2:
|
|||||||
"method": "fallback",
|
"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_normal: List[float],
|
||||||
ground_truth_origin: List[float]) -> Optional[Dict]:
|
ground_truth_origin: List[float]) -> Optional[Dict]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import numpy as np
|
|||||||
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeFace
|
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeFace
|
||||||
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox
|
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox
|
||||||
from OCC.Core.gp import gp_Pln, gp_Dir, gp_Pnt
|
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.BRepAdaptor import BRepAdaptor_Surface
|
||||||
from OCC.Core.TopExp import TopExp_Explorer
|
from OCC.Core.TopExp import TopExp_Explorer
|
||||||
from OCC.Core.TopAbs import TopAbs_FACE
|
from OCC.Core.TopAbs import TopAbs_FACE
|
||||||
@@ -128,7 +128,7 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
|||||||
else:
|
else:
|
||||||
logger.warning(f"未知材料 {material}")
|
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模型生成型腔和型芯
|
从产品的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 = super()._analyze_product_geometry(shape)
|
||||||
result["normal_statistics"] = self._analyze_parting_direction(shape)
|
result["normal_statistics"] = self._analyze_parting_direction(shape)
|
||||||
return result
|
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}
|
stats = {"X": 0.0, "Y": 0.0, "Z": 0.0}
|
||||||
explorer = TopExp_Explorer(shape, TopAbs_FACE)
|
explorer = TopExp_Explorer(shape, TopAbs_FACE)
|
||||||
@@ -328,11 +328,11 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
|||||||
for axis, value in stats.items()
|
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)
|
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:
|
except Exception:
|
||||||
return 50.0
|
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板结构)"""
|
"""生成完整的模具块(包含A/B板结构)"""
|
||||||
try:
|
try:
|
||||||
bbox = analysis["bounding_box"]
|
bbox = analysis["bounding_box"]
|
||||||
@@ -493,7 +493,7 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
|||||||
logger.error(f"模具块生成失败: {e}")
|
logger.error(f"模具块生成失败: {e}")
|
||||||
return cavity
|
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)
|
metadata = self._extract_plane_metadata(surface)
|
||||||
return {
|
return {
|
||||||
@@ -504,7 +504,7 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def _create_parting_surface_from_ai(self, ai_result: Dict, analysis: Dict,
|
def _create_parting_surface_from_ai(self, ai_result: Dict, analysis: Dict,
|
||||||
shape: Any = None) -> Dict:
|
shape: Optional[TopoDS_Shape] = None) -> Dict:
|
||||||
"""从 AI 结果创建分型面"""
|
"""从 AI 结果创建分型面"""
|
||||||
origin = ai_result.get("origin", [0, 0, 0])
|
origin = ai_result.get("origin", [0, 0, 0])
|
||||||
normal = ai_result.get("normal", [0, 0, 1])
|
normal = ai_result.get("normal", [0, 0, 1])
|
||||||
|
|||||||
@@ -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 math
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from OCC.Core.BRepOffsetAPI import BRepOffsetAPI_DraftAngle
|
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.BRepBuilderAPI import BRepBuilderAPI_MakeFace, BRepBuilderAPI_Transform
|
||||||
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakeHalfSpace
|
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.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.BRep import BRep_Tool, BRep_Builder
|
||||||
from OCC.Core.BRepMesh import BRepMesh_IncrementalMesh
|
from OCC.Core.BRepMesh import BRepMesh_IncrementalMesh
|
||||||
from OCC.Core.GProp import GProp_GProps
|
from OCC.Core.GProp import GProp_GProps
|
||||||
@@ -41,7 +41,7 @@ class BaseMoldGenerator:
|
|||||||
self.ai_draft_analyzer = draft_analyzer
|
self.ai_draft_analyzer = draft_analyzer
|
||||||
logger.info("AI 模型接口已设置")
|
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
|
scale_factor = 1.0 + self.shrinkage_rate
|
||||||
trsf = gp_Trsf()
|
trsf = gp_Trsf()
|
||||||
trsf.SetScale(gp_Pnt(0, 0, 0), scale_factor)
|
trsf.SetScale(gp_Pnt(0, 0, 0), scale_factor)
|
||||||
@@ -53,7 +53,7 @@ class BaseMoldGenerator:
|
|||||||
logger.warning(f"收缩率补偿失败: {e}")
|
logger.warning(f"收缩率补偿失败: {e}")
|
||||||
return shape
|
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:
|
try:
|
||||||
draft_direction = self._get_draft_direction(parting_surface)
|
draft_direction = self._get_draft_direction(parting_surface)
|
||||||
if draft_direction is None:
|
if draft_direction is None:
|
||||||
@@ -76,7 +76,7 @@ class BaseMoldGenerator:
|
|||||||
logger.warning(f"拔模角处理失败,返回原始形状: {e}")
|
logger.warning(f"拔模角处理失败,返回原始形状: {e}")
|
||||||
return shape
|
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:
|
try:
|
||||||
surface = BRepAdaptor_Surface(parting_surface)
|
surface = BRepAdaptor_Surface(parting_surface)
|
||||||
if surface.GetType() == 0:
|
if surface.GetType() == 0:
|
||||||
@@ -85,7 +85,7 @@ class BaseMoldGenerator:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return gp_Dir(0, 0, 1)
|
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 = []
|
draftable = []
|
||||||
explorer = TopExp_Explorer(shape, TopAbs_FACE)
|
explorer = TopExp_Explorer(shape, TopAbs_FACE)
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ class BaseMoldGenerator:
|
|||||||
|
|
||||||
return draftable
|
return draftable
|
||||||
|
|
||||||
def _get_face_normal(self, face: Any) -> Optional[gp_Dir]:
|
def _get_face_normal(self, face: TopoDS_Face) -> Optional[gp_Dir]:
|
||||||
try:
|
try:
|
||||||
surface = BRepAdaptor_Surface(face)
|
surface = BRepAdaptor_Surface(face)
|
||||||
u = (surface.FirstUParameter() + surface.LastUParameter()) / 2
|
u = (surface.FirstUParameter() + surface.LastUParameter()) / 2
|
||||||
@@ -122,8 +122,8 @@ class BaseMoldGenerator:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _execute_draft(self, shape: Any, faces: List[Any],
|
def _execute_draft(self, shape: TopoDS_Shape, faces: List[TopoDS_Face],
|
||||||
draft_direction: gp_Dir, draft_angle_rad: float) -> Any:
|
draft_direction: gp_Dir, draft_angle_rad: float) -> TopoDS_Shape:
|
||||||
try:
|
try:
|
||||||
draft = BRepOffsetAPI_DraftAngle(shape)
|
draft = BRepOffsetAPI_DraftAngle(shape)
|
||||||
|
|
||||||
@@ -156,8 +156,8 @@ class BaseMoldGenerator:
|
|||||||
logger.warning(f"拔模执行失败: {e}")
|
logger.warning(f"拔模执行失败: {e}")
|
||||||
return shape
|
return shape
|
||||||
|
|
||||||
def _draft_faces_sequentially(self, shape: Any, faces: List[Any],
|
def _draft_faces_sequentially(self, shape: TopoDS_Shape, faces: List[TopoDS_Face],
|
||||||
draft_direction: gp_Dir, draft_angle_rad: float) -> Any:
|
draft_direction: gp_Dir, draft_angle_rad: float) -> TopoDS_Shape:
|
||||||
current_shape = shape
|
current_shape = shape
|
||||||
success_count = 0
|
success_count = 0
|
||||||
|
|
||||||
@@ -190,7 +190,7 @@ class BaseMoldGenerator:
|
|||||||
|
|
||||||
return current_shape
|
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:
|
try:
|
||||||
props = GProp_GProps()
|
props = GProp_GProps()
|
||||||
brepgprop.VolumeProperties(shape, props)
|
brepgprop.VolumeProperties(shape, props)
|
||||||
@@ -224,7 +224,7 @@ class BaseMoldGenerator:
|
|||||||
logger.error(f"产品几何分析失败: {e}")
|
logger.error(f"产品几何分析失败: {e}")
|
||||||
raise
|
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)
|
return self._split_cavity_core_fallback(shape, None)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _extract_parting_normal(parting_surface: Any) -> List[float]:
|
def _extract_parting_normal(parting_surface: TopoDS_Face) -> List[float]:
|
||||||
"""从分型面提取法向量"""
|
"""从分型面提取法向量"""
|
||||||
try:
|
try:
|
||||||
surface = BRepAdaptor_Surface(parting_surface)
|
surface = BRepAdaptor_Surface(parting_surface)
|
||||||
@@ -288,14 +288,14 @@ class BaseMoldGenerator:
|
|||||||
|
|
||||||
def _build_core_with_base(
|
def _build_core_with_base(
|
||||||
self,
|
self,
|
||||||
shape: Any,
|
shape: TopoDS_Shape,
|
||||||
mold_block: Any,
|
mold_block: TopoDS_Shape,
|
||||||
parting_plane: gp_Pln,
|
parting_plane: gp_Pln,
|
||||||
mold_xmin: float, mold_ymin: float, mold_zmin: float,
|
mold_xmin: float, mold_ymin: float, mold_zmin: float,
|
||||||
mold_xmax: float, mold_ymax: float, mold_zmax: float,
|
mold_xmax: float, mold_ymax: float, mold_zmax: float,
|
||||||
xmin: float, ymin: float, zmin: float,
|
xmin: float, ymin: float, zmin: float,
|
||||||
xmax: float, ymax: float, zmax: float,
|
xmax: float, ymax: float, zmax: float,
|
||||||
) -> Any:
|
) -> TopoDS_Shape:
|
||||||
"""
|
"""
|
||||||
构建带底座的型芯。
|
构建带底座的型芯。
|
||||||
|
|
||||||
@@ -353,7 +353,7 @@ class BaseMoldGenerator:
|
|||||||
return self._build_core_compound(base_plate, shape)
|
return self._build_core_compound(base_plate, shape)
|
||||||
|
|
||||||
@staticmethod
|
@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 包含底座平板 + 产品。
|
兜底方案:构建 TopoDS_Compound 包含底座平板 + 产品。
|
||||||
即使布尔融合失败,底座也绝不会丢失。
|
即使布尔融合失败,底座也绝不会丢失。
|
||||||
@@ -366,7 +366,7 @@ class BaseMoldGenerator:
|
|||||||
logger.info("型芯 Compound 兜底构建 (底座+产品)")
|
logger.info("型芯 Compound 兜底构建 (底座+产品)")
|
||||||
return 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:
|
try:
|
||||||
surface = BRepAdaptor_Surface(parting_surface)
|
surface = BRepAdaptor_Surface(parting_surface)
|
||||||
@@ -383,8 +383,8 @@ class BaseMoldGenerator:
|
|||||||
logger.warning(f"分型面平面提取失败: {e}")
|
logger.warning(f"分型面平面提取失败: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _split_mold_block_by_plane(self, mold_block: Any,
|
def _split_mold_block_by_plane(self, mold_block: TopoDS_Shape,
|
||||||
parting_plane: gp_Pln) -> Tuple[Any, Any]:
|
parting_plane: gp_Pln) -> Tuple[TopoDS_Shape, TopoDS_Shape]:
|
||||||
"""
|
"""
|
||||||
用分型面将模具块切分为A板(上模)和B板(下模)
|
用分型面将模具块切分为A板(上模)和B板(下模)
|
||||||
|
|
||||||
@@ -439,8 +439,8 @@ class BaseMoldGenerator:
|
|||||||
logger.error(f"A/B板分离失败: {e}")
|
logger.error(f"A/B板分离失败: {e}")
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
def _subtract_product_from_plate(self, plate: Any, product: Any,
|
def _subtract_product_from_plate(self, plate: TopoDS_Shape, product: TopoDS_Shape,
|
||||||
plate_name: str) -> Any:
|
plate_name: str) -> TopoDS_Shape:
|
||||||
"""从模板中减去产品形状,生成型腔或型芯"""
|
"""从模板中减去产品形状,生成型腔或型芯"""
|
||||||
try:
|
try:
|
||||||
cut_op = BRepAlgoAPI_Cut(plate, product)
|
cut_op = BRepAlgoAPI_Cut(plate, product)
|
||||||
@@ -455,8 +455,8 @@ class BaseMoldGenerator:
|
|||||||
logger.warning(f"{plate_name}减产品失败: {e}")
|
logger.warning(f"{plate_name}减产品失败: {e}")
|
||||||
return plate
|
return plate
|
||||||
|
|
||||||
def _split_cavity_core_fallback(self, shape: Any,
|
def _split_cavity_core_fallback(self, shape: TopoDS_Shape,
|
||||||
mold_block: Optional[Any] = None) -> Tuple[Any, Any]:
|
mold_block: Optional[TopoDS_Shape] = None) -> Tuple[TopoDS_Shape, TopoDS_Shape]:
|
||||||
"""
|
"""
|
||||||
分模回退方案:完全嵌入 + 突出贴合,用 Z 中心面做分型基准。
|
分模回退方案:完全嵌入 + 突出贴合,用 Z 中心面做分型基准。
|
||||||
"""
|
"""
|
||||||
@@ -507,7 +507,7 @@ class BaseMoldGenerator:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return shape, shape
|
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,
|
depth_threshold: float = 30.0,
|
||||||
aspect_threshold: float = 3.0) -> List[Dict[str, Any]]:
|
aspect_threshold: float = 3.0) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
@@ -618,7 +618,7 @@ class BaseMoldGenerator:
|
|||||||
|
|
||||||
return inserts
|
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:
|
try:
|
||||||
mesh = BRepMesh_IncrementalMesh(shape, 0.1)
|
mesh = BRepMesh_IncrementalMesh(shape, 0.1)
|
||||||
mesh.Perform()
|
mesh.Perform()
|
||||||
@@ -678,7 +678,7 @@ class BaseMoldGenerator:
|
|||||||
"face_count": 0,
|
"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 = {
|
metadata = {
|
||||||
"normal": [0.0, 0.0, 1.0],
|
"normal": [0.0, 0.0, 1.0],
|
||||||
@@ -743,7 +743,7 @@ class BaseMoldGenerator:
|
|||||||
|
|
||||||
return total_length
|
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:
|
try:
|
||||||
section = BRepAlgoAPI_Section(shape, parting_surface)
|
section = BRepAlgoAPI_Section(shape, parting_surface)
|
||||||
section.Build()
|
section.Build()
|
||||||
@@ -783,7 +783,7 @@ class BaseMoldGenerator:
|
|||||||
logger.error(f"分型线计算失败: {e}")
|
logger.error(f"分型线计算失败: {e}")
|
||||||
return self._simple_parting_line(shape)
|
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:
|
try:
|
||||||
bbox = Bnd_Box()
|
bbox = Bnd_Box()
|
||||||
brepbndlib.Add(shape, bbox)
|
brepbndlib.Add(shape, bbox)
|
||||||
@@ -800,8 +800,8 @@ class BaseMoldGenerator:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return [[-50, -50, 0], [50, -50, 0], [50, 50, 0], [-50, 50, 0], [-50, -50, 0]]
|
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,
|
def extend_parting_surface(self, parting_surface: TopoDS_Face, shape: TopoDS_Shape,
|
||||||
extension: float = 30.0) -> Any:
|
extension: float = 30.0) -> TopoDS_Face:
|
||||||
"""
|
"""
|
||||||
将分型面延伸到模具块边界
|
将分型面延伸到模具块边界
|
||||||
|
|
||||||
|
|||||||
+34
-22
@@ -29,6 +29,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
from typing import Dict, List, Any, Optional, Tuple
|
from typing import Dict, List, Any, Optional, Tuple
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from OCC.Core.TopoDS import TopoDS_Shape
|
||||||
from utils.logger import get_logger
|
from utils.logger import get_logger
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
@@ -70,7 +71,7 @@ class CADExporter:
|
|||||||
relative = Path(os.path.basename(filepath))
|
relative = Path(os.path.basename(filepath))
|
||||||
return relative.as_posix()
|
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:
|
schema: str = "AP214") -> bool:
|
||||||
"""
|
"""
|
||||||
导出 STEP 文件
|
导出 STEP 文件
|
||||||
@@ -118,7 +119,7 @@ class CADExporter:
|
|||||||
logger.error(f"STEP 导出失败: {e}")
|
logger.error(f"STEP 导出失败: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def export_iges(self, shape: Any, filepath: str) -> bool:
|
def export_iges(self, shape: TopoDS_Shape, filepath: str) -> bool:
|
||||||
"""
|
"""
|
||||||
导出 IGES 文件
|
导出 IGES 文件
|
||||||
|
|
||||||
@@ -156,7 +157,7 @@ class CADExporter:
|
|||||||
logger.error(f"IGES 导出失败: {e}")
|
logger.error(f"IGES 导出失败: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def export_stl(self, shape: Any, filepath: str,
|
def export_stl(self, shape: TopoDS_Shape, filepath: str,
|
||||||
ascii_mode: bool = True,
|
ascii_mode: bool = True,
|
||||||
deflection: float = 0.1) -> bool:
|
deflection: float = 0.1) -> bool:
|
||||||
"""
|
"""
|
||||||
@@ -201,7 +202,7 @@ class CADExporter:
|
|||||||
logger.error(f"STL 导出失败: {e}")
|
logger.error(f"STL 导出失败: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def export_brep(self, shape: Any, filepath: str) -> bool:
|
def export_brep(self, shape: TopoDS_Shape, filepath: str) -> bool:
|
||||||
"""
|
"""
|
||||||
导出 BRep 文件(OpenCASCADE 原生格式)
|
导出 BRep 文件(OpenCASCADE 原生格式)
|
||||||
|
|
||||||
@@ -240,18 +241,6 @@ class CADExporter:
|
|||||||
components: List[str] = None,
|
components: List[str] = None,
|
||||||
task_id: Optional[str] = None,
|
task_id: Optional[str] = None,
|
||||||
scheme_id: Optional[str] = None) -> Dict[str, Any]:
|
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:
|
if formats is None:
|
||||||
formats = ["step", "stl"]
|
formats = ["step", "stl"]
|
||||||
if components is None:
|
if components is None:
|
||||||
@@ -279,7 +268,8 @@ class CADExporter:
|
|||||||
"parting_surface": ("parting_surface", "分型面"),
|
"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:
|
for comp in components:
|
||||||
if comp == "all":
|
if comp == "all":
|
||||||
@@ -287,23 +277,45 @@ class CADExporter:
|
|||||||
shape = cavity_data.get(data_key)
|
shape = cavity_data.get(data_key)
|
||||||
if shape is not None:
|
if shape is not None:
|
||||||
shapes_to_export.append((key, label, shape))
|
shapes_to_export.append((key, label, shape))
|
||||||
|
assembly_shapes.append((shape, label))
|
||||||
break
|
break
|
||||||
elif comp in shape_map:
|
elif comp in shape_map:
|
||||||
data_key, label = shape_map[comp]
|
data_key, label = shape_map[comp]
|
||||||
shape = cavity_data.get(data_key)
|
shape = cavity_data.get(data_key)
|
||||||
if shape is not None:
|
if shape is not None:
|
||||||
shapes_to_export.append((comp, label, shape))
|
shapes_to_export.append((comp, label, shape))
|
||||||
|
assembly_shapes.append((shape, label))
|
||||||
else:
|
else:
|
||||||
results["errors"].append(f"{label}形状不可用")
|
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 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}")
|
filepath = os.path.join(export_dir, f"{base_filename}_{comp_name}.{fmt}")
|
||||||
|
|
||||||
success = False
|
success = False
|
||||||
if fmt == "step":
|
if fmt == "iges":
|
||||||
success = self.export_step(shape, filepath)
|
|
||||||
elif fmt == "iges":
|
|
||||||
success = self.export_iges(shape, filepath)
|
success = self.export_iges(shape, filepath)
|
||||||
elif fmt == "stl":
|
elif fmt == "stl":
|
||||||
success = self.export_stl(shape, filepath)
|
success = self.export_stl(shape, filepath)
|
||||||
@@ -337,7 +349,7 @@ class CADExporter:
|
|||||||
|
|
||||||
return results
|
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,
|
filepath: str,
|
||||||
schema: str = "AP214") -> bool:
|
schema: str = "AP214") -> bool:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from typing import Dict, List, Any, Optional
|
from typing import Dict, List, Any, Optional
|
||||||
import math
|
import math
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from OCC.Core.TopoDS import TopoDS_Shape
|
||||||
from models.schemas import (
|
from models.schemas import (
|
||||||
create_mold_feature,
|
create_mold_feature,
|
||||||
create_design_recommendation,
|
create_design_recommendation,
|
||||||
@@ -38,7 +39,7 @@ class GeometryAnalyzer:
|
|||||||
def analyze_mold_design(self, geometry_data: Dict[str, Any],
|
def analyze_mold_design(self, geometry_data: Dict[str, Any],
|
||||||
product_material: str = "ABS",
|
product_material: str = "ABS",
|
||||||
mold_material: str = "Aluminum",
|
mold_material: str = "Aluminum",
|
||||||
shape: Any = None
|
shape: Optional[TopoDS_Shape] = None
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""分析模具设计
|
"""分析模具设计
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@ class GeometryAnalyzer:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _detect_features(self, geometry_data: Dict[str, Any],
|
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 = []
|
features = []
|
||||||
|
|
||||||
@@ -99,7 +100,7 @@ class GeometryAnalyzer:
|
|||||||
return features
|
return features
|
||||||
|
|
||||||
def _detect_wall_features(self, geometry_data: Dict[str, Any],
|
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 = []
|
features = []
|
||||||
|
|
||||||
@@ -230,7 +231,7 @@ class GeometryAnalyzer:
|
|||||||
|
|
||||||
return features
|
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 精确计算壁厚"""
|
"""使用 BRepExtrema_DistShapeShape 精确计算壁厚"""
|
||||||
try:
|
try:
|
||||||
from OCC.Core.TopExp import TopExp_Explorer
|
from OCC.Core.TopExp import TopExp_Explorer
|
||||||
@@ -319,7 +320,7 @@ class GeometryAnalyzer:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def _detect_rib_features(self, geometry_data: Dict[str, Any],
|
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 = []
|
features = []
|
||||||
topology = geometry_data.get("topology", {})
|
topology = geometry_data.get("topology", {})
|
||||||
@@ -350,7 +351,7 @@ class GeometryAnalyzer:
|
|||||||
return features
|
return features
|
||||||
|
|
||||||
def _detect_boss_features(self, geometry_data: Dict[str, Any],
|
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柱特征"""
|
"""检测BOSS柱特征"""
|
||||||
features = []
|
features = []
|
||||||
volume = geometry_data.get("volume", 0)
|
volume = geometry_data.get("volume", 0)
|
||||||
@@ -382,7 +383,7 @@ class GeometryAnalyzer:
|
|||||||
return features
|
return features
|
||||||
|
|
||||||
def _analyze_draft_angles(self, geometry_data: Dict[str, Any],
|
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 = []
|
features = []
|
||||||
|
|
||||||
@@ -450,7 +451,7 @@ class GeometryAnalyzer:
|
|||||||
|
|
||||||
return features
|
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:
|
try:
|
||||||
from OCC.Core.TopExp import TopExp_Explorer
|
from OCC.Core.TopExp import TopExp_Explorer
|
||||||
@@ -516,7 +517,7 @@ class GeometryAnalyzer:
|
|||||||
logger.warning(f"拔模角度计算失败: {e}")
|
logger.warning(f"拔模角度计算失败: {e}")
|
||||||
return None
|
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 = []
|
features = []
|
||||||
try:
|
try:
|
||||||
@@ -604,7 +605,7 @@ class GeometryAnalyzer:
|
|||||||
|
|
||||||
return features
|
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 = []
|
features = []
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from OCC.Core.BRepMesh import BRepMesh_IncrementalMesh
|
|||||||
from OCC.Core.TopExp import TopExp_Explorer
|
from OCC.Core.TopExp import TopExp_Explorer
|
||||||
from OCC.Core.TopAbs import TopAbs_FACE
|
from OCC.Core.TopAbs import TopAbs_FACE
|
||||||
from OCC.Core.BRep import BRep_Tool
|
from OCC.Core.BRep import BRep_Tool
|
||||||
|
from OCC.Core.TopoDS import TopoDS_Shape
|
||||||
from OCC.Core.TopLoc import TopLoc_Location
|
from OCC.Core.TopLoc import TopLoc_Location
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -24,7 +25,7 @@ class MeshGenerator:
|
|||||||
}
|
}
|
||||||
self.quality = self.quality_settings.get(quality, 0.3)
|
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形状生成点云数据"""
|
"""从PythonOCC形状生成点云数据"""
|
||||||
try:
|
try:
|
||||||
mesh = BRepMesh_IncrementalMesh(shape, self.quality, False, 0.5, True)
|
mesh = BRepMesh_IncrementalMesh(shape, self.quality, False, 0.5, True)
|
||||||
@@ -121,7 +122,7 @@ class MeshGenerator:
|
|||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
return self._create_sample_pointcloud()
|
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简化,避免重复计算
|
"""生成多级LOD网格 - 一次OCC剖分,trimesh简化,避免重复计算
|
||||||
|
|
||||||
返回结构:
|
返回结构:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from typing import Dict, List, Any, Tuple, Optional
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeFace
|
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeFace
|
||||||
from OCC.Core.gp import gp_Pln, gp_Dir, gp_Pnt
|
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.BRepAdaptor import BRepAdaptor_Surface
|
||||||
from OCC.Core.TopExp import TopExp_Explorer
|
from OCC.Core.TopExp import TopExp_Explorer
|
||||||
from OCC.Core.TopAbs import TopAbs_FACE
|
from OCC.Core.TopAbs import TopAbs_FACE
|
||||||
@@ -47,7 +47,7 @@ class MoldCavityGenerator(BaseMoldGenerator):
|
|||||||
else:
|
else:
|
||||||
logger.warning(f"未知材料 {material}, 使用默认密度 {self.material_density} g/cm³")
|
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模型生成型腔和型芯
|
从产品的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("使用简化方法检测分型面")
|
logger.info("使用简化方法检测分型面")
|
||||||
return self._simple_parting_surface(shape, analysis)
|
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优先 → 几何法向量 → 简化回退)"""
|
"""检测主分型面(AI优先 → 几何法向量 → 简化回退)"""
|
||||||
if self.ai_parting_detector is not None:
|
if self.ai_parting_detector is not None:
|
||||||
try:
|
try:
|
||||||
@@ -283,7 +283,7 @@ class MoldCavityGenerator(BaseMoldGenerator):
|
|||||||
logger.info(f"转换得到 {len(regions)} 个兼容倒扣区域")
|
logger.info(f"转换得到 {len(regions)} 个兼容倒扣区域")
|
||||||
return 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:
|
else:
|
||||||
return gp_Dir(0, 0, 1)
|
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:
|
direction: gp_Dir) -> gp_Pln:
|
||||||
"""
|
"""
|
||||||
创建最优分型面
|
创建最优分型面
|
||||||
@@ -352,7 +352,7 @@ class MoldCavityGenerator(BaseMoldGenerator):
|
|||||||
|
|
||||||
return parting_plane
|
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"]
|
bbox = analysis["bounding_box"]
|
||||||
center_z = bbox["center"][2]
|
center_z = bbox["center"][2]
|
||||||
@@ -372,7 +372,7 @@ class MoldCavityGenerator(BaseMoldGenerator):
|
|||||||
return parting_surface, parting_line
|
return parting_surface, parting_line
|
||||||
|
|
||||||
def _create_parting_surface_from_ai(self, ai_result: Dict,
|
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 模型结果创建分型面(预留接口)
|
从 AI 模型结果创建分型面(预留接口)
|
||||||
|
|
||||||
@@ -405,7 +405,7 @@ class MoldCavityGenerator(BaseMoldGenerator):
|
|||||||
logger.info(f"从 AI 结果创建分型面:原点={origin}, 法向量={normal}")
|
logger.info(f"从 AI 结果创建分型面:原点={origin}, 法向量={normal}")
|
||||||
return parting_surface, parting_line
|
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)
|
metadata = self._extract_plane_metadata(surface)
|
||||||
|
|
||||||
|
|||||||
@@ -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.gp import gp_Dir, gp_Pln, gp_Pnt
|
||||||
from OCC.Core.TopAbs import TopAbs_FACE
|
from OCC.Core.TopAbs import TopAbs_FACE
|
||||||
from OCC.Core.TopExp import TopExp_Explorer
|
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.mold_generator import MoldCavityGenerator
|
||||||
from core.aluminum_foam_mold import AluminumFoamMoldGenerator
|
from core.aluminum_foam_mold import AluminumFoamMoldGenerator
|
||||||
@@ -31,7 +31,7 @@ class MultiSchemeMoldPlanner:
|
|||||||
|
|
||||||
def generate_plan(
|
def generate_plan(
|
||||||
self,
|
self,
|
||||||
shape: Any,
|
shape: TopoDS_Shape,
|
||||||
material: Dict[str, Any],
|
material: Dict[str, Any],
|
||||||
is_foam_material: bool = False,
|
is_foam_material: bool = False,
|
||||||
max_schemes: int = 3,
|
max_schemes: int = 3,
|
||||||
@@ -92,7 +92,7 @@ class MultiSchemeMoldPlanner:
|
|||||||
def _build_scheme(
|
def _build_scheme(
|
||||||
self,
|
self,
|
||||||
generator: Any,
|
generator: Any,
|
||||||
shape: Any,
|
shape: TopoDS_Shape,
|
||||||
analysis: Dict[str, Any],
|
analysis: Dict[str, Any],
|
||||||
candidate: Dict[str, Any],
|
candidate: Dict[str, Any],
|
||||||
is_foam_material: bool,
|
is_foam_material: bool,
|
||||||
@@ -209,10 +209,10 @@ class MultiSchemeMoldPlanner:
|
|||||||
generator: Any,
|
generator: Any,
|
||||||
analysis: Dict[str, Any],
|
analysis: Dict[str, Any],
|
||||||
direction_vector: List[float],
|
direction_vector: List[float],
|
||||||
shape: Any,
|
shape: TopoDS_Shape,
|
||||||
offset_ratio: float = 0.0,
|
offset_ratio: float = 0.0,
|
||||||
opening_span_mm: Optional[float] = None,
|
opening_span_mm: Optional[float] = None,
|
||||||
) -> Any:
|
) -> TopoDS_Face:
|
||||||
center = analysis.get("bounding_box", {}).get("center", [0, 0, 0])
|
center = analysis.get("bounding_box", {}).get("center", [0, 0, 0])
|
||||||
dims = analysis.get("bounding_box", {}).get("dimensions", [100, 100, 100])
|
dims = analysis.get("bounding_box", {}).get("dimensions", [100, 100, 100])
|
||||||
span = max(dims) * 1.5 + 30
|
span = max(dims) * 1.5 + 30
|
||||||
@@ -272,7 +272,7 @@ class MultiSchemeMoldPlanner:
|
|||||||
|
|
||||||
return variants
|
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}
|
stats = {"X": 0.0, "Y": 0.0, "Z": 0.0}
|
||||||
explorer = TopExp_Explorer(shape, TopAbs_FACE)
|
explorer = TopExp_Explorer(shape, TopAbs_FACE)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
from typing import Dict, List, Any, Optional, Tuple
|
from typing import Dict, List, Any, Optional, Tuple
|
||||||
import math
|
import math
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from OCC.Core.TopoDS import TopoDS_Shape, TopoDS_Face
|
||||||
from utils.logger import get_logger
|
from utils.logger import get_logger
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
@@ -29,8 +30,8 @@ logger = get_logger(__name__)
|
|||||||
class UndercutDetector:
|
class UndercutDetector:
|
||||||
"""倒扣区域检测器"""
|
"""倒扣区域检测器"""
|
||||||
|
|
||||||
def detect_undercuts(self, shape: Any, parting_direction: List[float],
|
def detect_undercuts(self, shape: TopoDS_Shape, parting_direction: List[float],
|
||||||
parting_surface: Any = None) -> Dict[str, Any]:
|
parting_surface: Optional[TopoDS_Face] = None) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
检测产品中的倒扣区域
|
检测产品中的倒扣区域
|
||||||
|
|
||||||
@@ -443,8 +444,8 @@ class SideActionDesigner:
|
|||||||
self.slider_designer = SliderMechanismDesigner()
|
self.slider_designer = SliderMechanismDesigner()
|
||||||
self.lifter_designer = LifterMechanismDesigner()
|
self.lifter_designer = LifterMechanismDesigner()
|
||||||
|
|
||||||
def analyze_and_design(self, shape: Any, parting_direction: List[float],
|
def analyze_and_design(self, shape: TopoDS_Shape, parting_direction: List[float],
|
||||||
mold_size: Dict, parting_surface: Any = None) -> Dict[str, Any]:
|
mold_size: Dict, parting_surface: Optional[TopoDS_Face] = None) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
综合分析倒扣并设计侧向分型机构
|
综合分析倒扣并设计侧向分型机构
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import json
|
|||||||
from utils.logger import get_logger
|
from utils.logger import get_logger
|
||||||
from OCC.Core.GProp import GProp_GProps
|
from OCC.Core.GProp import GProp_GProps
|
||||||
from OCC.Core.BRepGProp import brepgprop
|
from OCC.Core.BRepGProp import brepgprop
|
||||||
|
from OCC.Core.TopoDS import TopoDS_Shape
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
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文件"""
|
"""加载STP文件"""
|
||||||
try:
|
try:
|
||||||
from OCC.Core.STEPControl import STEPControl_Reader
|
from OCC.Core.STEPControl import STEPControl_Reader
|
||||||
@@ -51,7 +52,7 @@ class STPParser:
|
|||||||
logger.error(f"STP解析失败: {e}")
|
logger.error(f"STP解析失败: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def analyze_geometry(self, shape) -> Dict[str, Any]:
|
def analyze_geometry(self, shape: TopoDS_Shape) -> Dict[str, Any]:
|
||||||
"""分析几何属性"""
|
"""分析几何属性"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -97,7 +98,7 @@ class STPParser:
|
|||||||
logger.error(f"几何分析失败: {e}")
|
logger.error(f"几何分析失败: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def _compute_bounding_box(self, shape) -> Dict[str, Any]:
|
def _compute_bounding_box(self, shape: TopoDS_Shape) -> Dict[str, Any]:
|
||||||
"""计算边界框"""
|
"""计算边界框"""
|
||||||
try:
|
try:
|
||||||
from OCC.Core.Bnd import Bnd_Box
|
from OCC.Core.Bnd import Bnd_Box
|
||||||
@@ -125,7 +126,7 @@ class STPParser:
|
|||||||
logger.error(f"边界框计算失败: {e}")
|
logger.error(f"边界框计算失败: {e}")
|
||||||
return self._default_bounding_box()
|
return self._default_bounding_box()
|
||||||
|
|
||||||
def _compute_volume(self, shape) -> float:
|
def _compute_volume(self, shape: TopoDS_Shape) -> float:
|
||||||
"""计算体积"""
|
"""计算体积"""
|
||||||
try:
|
try:
|
||||||
from OCC.Core.GProp import GProp_GProps
|
from OCC.Core.GProp import GProp_GProps
|
||||||
@@ -141,7 +142,7 @@ class STPParser:
|
|||||||
logger.error(f"体积计算失败: {e}")
|
logger.error(f"体积计算失败: {e}")
|
||||||
raise RuntimeError(f"体积计算失败: {e}") from e
|
raise RuntimeError(f"体积计算失败: {e}") from e
|
||||||
|
|
||||||
def _compute_surface_area(self, shape) -> float:
|
def _compute_surface_area(self, shape: TopoDS_Shape) -> float:
|
||||||
"""计算表面积"""
|
"""计算表面积"""
|
||||||
try:
|
try:
|
||||||
from OCC.Core.GProp import GProp_GProps
|
from OCC.Core.GProp import GProp_GProps
|
||||||
@@ -175,7 +176,7 @@ class STPParser:
|
|||||||
logger.error(f"表面积计算失败: {e}")
|
logger.error(f"表面积计算失败: {e}")
|
||||||
raise RuntimeError(f"表面积计算失败: {e}") from 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:
|
try:
|
||||||
from OCC.Core.GProp import GProp_GProps
|
from OCC.Core.GProp import GProp_GProps
|
||||||
@@ -194,7 +195,7 @@ class STPParser:
|
|||||||
except Exception:
|
except Exception:
|
||||||
raise RuntimeError(f"质心计算失败且边界框回退也失败: {e}") from e
|
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:
|
try:
|
||||||
from OCC.Core.GProp import GProp_GProps
|
from OCC.Core.GProp import GProp_GProps
|
||||||
@@ -216,7 +217,7 @@ class STPParser:
|
|||||||
logger.error(f"惯性属性计算失败: {e}")
|
logger.error(f"惯性属性计算失败: {e}")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def _analyze_topology(self, shape) -> Dict[str, int]:
|
def _analyze_topology(self, shape: TopoDS_Shape) -> Dict[str, int]:
|
||||||
"""分析拓扑"""
|
"""分析拓扑"""
|
||||||
try:
|
try:
|
||||||
from OCC.Core.TopExp import TopExp_Explorer
|
from OCC.Core.TopExp import TopExp_Explorer
|
||||||
|
|||||||
Reference in New Issue
Block a user