diff --git a/docs/SPEC_ALUMINUM_FOAM_MOLD.md b/docs/SPEC_ALUMINUM_FOAM_MOLD.md new file mode 100644 index 0000000..2a9c395 --- /dev/null +++ b/docs/SPEC_ALUMINUM_FOAM_MOLD.md @@ -0,0 +1,598 @@ +# 铝制家电包装泡沫模具分模功能技术规格说明书 + +## 文档信息 + +| 项目 | 内容 | +|------|------| +| **文档名称** | 铝制家电包装泡沫模具分模功能技术规格说明书 | +| **版本** | 1.0 | +| **日期** | 2026-03-13 | +| **项目** | geMoldInsight 模具分模功能增强 | + +--- + +## 1. 项目背景与目标 + +### 1.1 项目背景 + +铝制家电包装泡沫是一种广泛应用于家电产品缓冲包装的特殊材料,其模具设计具有以下特点: + +- **材料特性**:铝泡沫密度低(0.4-0.8 g/cm³),发泡倍率高,需要特殊的成型工艺 +- **产品特性**:壁厚较大(通常 20-100mm),形状复杂,表面质量要求高 +- **模具特性**:需要耐腐蚀模具材料,加强排气系统,特殊的浇注系统 + +### 1.2 项目目标 + +开发一套专业的铝制家电包装泡沫模具分模系统,实现: + +1. **自动分模算法** - 针对铝泡沫产品结构特性的智能分模 +2. **参数自定义** - 分模角度、分型线精度、型腔匹配度等 +3. **三维可视化** - 实时显示分模效果,支持交互调整 +4. **质量检测** - 自动验证分模面质量、结构合理性、生产可行性 +5. **数据接口** - 兼容现有软件,标准数据导出 + +--- + +## 2. 功能需求规格 + +### 2.1 自动分模算法 + +#### 2.1.1 分型面自动检测 + +**功能描述**:自动分析产品几何特征,计算最优分型面位置和方向 + +**需求规格**: + +| 需求项 | 详细说明 | 优先级 | +|--------|----------|--------| +| 表面法向量分析 | 统计产品所有面的法向量分布 | P0 | +| 最优方向计算 | 基于法向量统计计算最优分型方向 | P0 | +| 多分型面支持 | 支持复杂产品的多个分型面 | P1 | +| 倒扣检测 | 自动识别产品倒扣区域 | P1 | +| 分型面优化 | 平滑处理分型面,减少毛刺 | P2 | + +**算法输入**: +- 产品 3D 模型 (STEP/IGES 格式) +- 产品材料类型 +- 产品尺寸参数 + +**算法输出**: +- 分型面方程 (平面参数) +- 分型面位置 (Z 坐标或自定义) +- 置信度评分 (0-100%) + +#### 2.1.2 铝泡沫特性适配 + +**功能描述**:针对铝泡沫材料的特殊参数设置 + +**需求规格**: + +| 参数 | 范围 | 默认值 | 说明 | +|------|------|--------|------| +| 发泡倍率 | 1.5-4.0 | 2.5 | 铝泡沫发泡倍率 | +| 目标密度 | 0.3-0.8 g/cm³ | 0.5 | 成型后泡沫密度 | +| 收缩率 | 0.5%-3.0% | 1.5% | 铝泡沫收缩率(较大) | +| 成型温度 | 300-450°C | 380°C | 发泡成型温度 | + +**材料数据库**: + +```python +foam_materials = { + "AlSi10Mg": { + "density": 0.45, + "expansion_ratio": 2.5, + "shrinkage_rate": 0.015, + "molding_temp": 380, + "description": "常用铝硅泡沫" + }, + "AlSi12": { + "density": 0.50, + "expansion_ratio": 2.2, + "shrinkage_rate": 0.012, + "molding_temp": 360, + "description": "高强度铝泡沫" + }, + "Pure Al Foam": { + "density": 0.35, + "expansion_ratio": 3.0, + "shrinkage_rate": 0.020, + "molding_temp": 400, + "description": "纯铝泡沫" + } +} +``` + +#### 2.1.3 拔模角优化 + +**功能描述**:针对铝泡沫产品的拔模角计算 + +**需求规格**: + +| 需求项 | 详细说明 | 优先级 | +|--------|----------|--------| +| 最小拔模角计算 | 基于产品高度和材料摩擦系数 | P0 | +| 拔模方向检测 | 自动确定脱模方向 | P0 | +| 拔模干涉检测 | 检测脱模过程中的干涉区域 | P1 | +| 拔模补偿 | 自动补偿拔模引起的尺寸变化 | P1 | + +**拔模角参数**: + +| 参数 | 范围 | 默认值 | 说明 | +|------|------|--------|------| +| 最小拔模角 | 1°-10° | 3° | 铝泡沫建议 3-5° | +| 拔模方向 | X/Y/Z/自定义 | 自动 | 脱模方向 | +| 摩擦系数 | 0.1-0.5 | 0.3 | 材料摩擦系数 | + +### 2.2 参数自定义设置 + +#### 2.2.1 分模参数配置 + +**功能描述**:用户可自定义分模过程的各项参数 + +**需求规格**: + +| 参数名称 | 参数类型 | 取值范围 | 默认值 | 说明 | +|----------|----------|----------|--------|------| +| 分模方式 | 枚举 | 单分型面/多分型面/自动 | 自动 | 分模策略 | +| 分型线精度 | 浮点数 | 0.01-1.0 mm | 0.1 mm | 分型线采样精度 | +| 分型面容差 | 浮点数 | 0.01-2.0 mm | 0.5 mm | 分型面拟合容差 | +| 型腔匹配度 | 浮点数 | 80%-100% | 95% | 型腔与产品匹配度 | +| 收缩补偿 | 布尔 | 是/否 | 是 | 是否应用收缩补偿 | +| 拔模处理 | 布尔 | 是/否 | 是 | 是否应用拔模角 | + +#### 2.2.2 高级参数设置 + +**功能描述**:专家级用户可调整的高级参数 + +**参数面板**: + +```python +advanced_params = { + "mold_parameters": { + "cavity_count": 1, # 型腔数量 + "mold_material": "P20", # 模具材料 + "surface_finish": "SPI A2", # 表面粗糙度 + "ejection_system": "pin", # 顶出系统 + }, + "processing_params": { + "injection_pressure": "80-120 MPa", + "molding_temp": "350-400 °C", + "cooling_time": "30-60 秒", + "ejection_temp": "60-80 °C", + }, + "quality_params": { + "warpage_tolerance": 0.5, # 翘曲容差 mm + "sink_mark_depth": 0.1, # 缩痕深度 mm + "weld_line_gap": 0.05, # 熔接缝间隙 mm + } +} +``` + +### 2.3 三维可视化界面 + +#### 2.3.1 分模过程可视化 + +**功能描述**:实时显示分模过程和结果 + +**需求规格**: + +| 功能 | 说明 | 优先级 | +|------|------|--------| +| 产品模型显示 | 加载并显示原始产品 3D 模型 | P0 | +| 分型面可视化 | 在产品上显示分型面位置 | P0 | +| 分型线可视化 | 显示计算得到的分型线路径 | P0 | +| 型腔/型芯显示 | 分别高亮显示型腔和型芯 | P0 | +| 模具块显示 | 显示完整的模具块结构 | P1 | +| 剖视图 | 沿分型面剖切显示内部结构 | P1 | + +#### 2.3.2 交互调整功能 + +**功能描述**:支持用户交互调整分模参数 + +**需求规格**: + +| 功能 | 说明 | 交互方式 | +|------|------|----------| +| 分型面拖拽 | 沿法线方向移动分型面 | 鼠标拖拽 | +| 分型角度调整 | 调整分型面角度 | 滑块控制 | +| 视图旋转 | 360° 查看模型 | 鼠标拖拽 | +| 缩放 | 放大/缩小视图 | 滚轮 | +| 剖面切换 | 切换不同剖面视图 | 按钮切换 | +| 透明度调整 | 调整模型透明度 | 滑块控制 | +| 测量工具 | 测量距离、角度 | 点击测量 | + +#### 2.3.3 可视化参数 + +| 参数 | 取值范围 | 默认值 | +|------|----------|--------| +| 分型面颜色 | #FF0000 (红色) | #00FF00 (绿色) | +| 分型线颜色 | #FFFF00 (黄色) | #FF00FF (品红) | +| 型腔颜色 | #0000FF (蓝色) | #00FFFF (青色) | +| 型芯颜色 | #FF8800 (橙色) | #8800FF (紫色) | +| 网格密度 | 1000-50000 点 | 10000 点 | + +### 2.4 质量检测模块 + +#### 2.4.1 分模面质量检测 + +**功能描述**:自动检测分模面的质量 + +**检测项目**: + +| 检测项 | 检测方法 | 质量标准 | 优先级 | +|--------|----------|----------|--------| +| 平滑度 | 曲率分析 | 无明显凹凸 | P0 | +| 连续性 | 边界检查 | 无间隙 | P0 | +| 几何精度 | 偏差测量 | < 0.1mm | P1 | +| 表面缺陷 | 三角网格检查 | 无破面 | P1 | + +**检测输出**: + +```python +quality_report = { + "surface_quality": { + "smoothness_score": 95, # 平滑度评分 0-100 + "continuity_score": 100, # 连续性评分 + "defects": [], # 发现的缺陷列表 + "overall_score": 97 # 综合评分 + }, + "geometry_check": { + "deviation": 0.05, # 偏差 mm + "tolerance_met": True # 是否符合容差 + } +} +``` + +#### 2.4.2 模具结构合理性检测 + +**功能描述**:检测模具结构的合理性 + +**检测项目**: + +| 检测项 | 说明 | 判定标准 | +|--------|------|----------| +| 模具尺寸 | 模具是否足够大 | 产品尺寸 + 余量 | +| 壁厚检测 | 模具壁厚是否足够 | > 10mm | +| 拔模检测 | 是否有倒扣无法脱模 | 无倒扣或已处理 | +| 干涉检测 | 运动件是否干涉 | 无干涉 | +| 冷却系统 | 冷却通道是否合理 | 分布均匀 | + +#### 2.4.3 生产可行性评估 + +**功能描述**:评估模具的生产可行性 + +**评估项目**: + +| 评估项 | 评估方法 | 输出 | +|--------|----------|------| +| 注塑压力 | 投影面积 × 压力系数 | 压力值 (MPa) | +| 锁模力 | 投影面积 × 材料压力 | 力值 (吨) | +| 成型周期 | 体积/冷却速度 | 时间 (秒) | +| 材料利用率 | 流道体积/产品体积 | 百分比 | +| 生产成本 | 材料+工艺+时间 | 估算成本 | + +### 2.5 数据接口 + +#### 2.5.1 导入接口 + +**支持的格式**: + +| 格式 | 说明 | 优先级 | +|------|------|--------| +| STEP | 标准 CAD 交换格式 | P0 | +| IGES | 另一种 CAD 交换格式 | P1 | +| BREP | OpenCASCADE 原生格式 | P1 | +| STL | 三角网格格式 | P2 | + +#### 2.5.2 导出接口 + +**导出格式**: + +| 格式 | 说明 | 用途 | +|------|------|------| +| STEP | 分模后模具模型 | CAD 软件 | +| IGES | 分模后模具模型 | CAM 软件 | +| STL | 3D 打印/快速成型 | 3D 打印 | +| JSON | 分模参数和结果 | 数据交换 | +| PDF | 质量检测报告 | 文档输出 | + +#### 2.5.3 API 接口 + +**内部 API**: + +```python +# 分模分析 API +POST /api/mold/analyze +{ + "product_file": "file", + "material": "AlSi10Mg", + "params": { + "draft_angle": 3.0, + "parting_tolerance": 0.1, + "cavity_match": 95 + } +} + +# 获取分模结果 +GET /api/mold/result/{task_id} + +# 导出分模结果 +GET /api/mold/export/{task_id}?format=step +``` + +--- + +## 3. 技术架构规格 + +### 3.1 系统架构 + +``` +┌─────────────────────────────────────────────────────────┐ +│ 表示层 (Presentation) │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ Web 界面 │ │ 3D 可视化 │ │ 参数面板 │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +└─────────────────────────────────────────────────────────┘ + │ +┌─────────────────────────────────────────────────────────┐ +│ 业务层 (Business Logic) │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ 分模算法 │ │ 质量检测 │ │ 参数优化 │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +└─────────────────────────────────────────────────────────┘ + │ +┌─────────────────────────────────────────────────────────┐ +│ 数据层 (Data Layer) │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ PythonOCC │ │ 数据库 │ │ 文件存储 │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +└─────────────────────────────────────────────────────────┘ +``` + +### 3.2 模块设计 + +#### 3.2.1 分模算法模块 + +**模块职责**:核心分模算法实现 + +**主要类**: + +```python +class AluminumFoamMoldGenerator: + """铝泡沫模具分模生成器""" + + def __init__(self, params: MoldParams): + self.params = params + self.material_db = FoamMaterialDatabase() + + def analyze_product(self, shape: TopoDS_Shape) -> ProductAnalysis: + """分析产品几何特征""" + pass + + def detect_parting_surface(self, shape, analysis) -> PartingSurface: + """检测分型面""" + pass + + def calculate_parting_line(self, shape, surface) -> PartingLine: + """计算分型线""" + pass + + def apply_draft_angles(self, shape, direction) -> Shape: + """应用拔模角""" + pass + + def split_cavity_core(self, shape, surface) -> Tuple[Shape, Shape]: + """分离型腔和型芯""" + pass + + def generate_mold_block(self, cavity, params) -> Shape: + """生成模具块""" + pass +``` + +#### 3.2.2 质量检测模块 + +**模块职责**:分模质量检测和评估 + +**主要类**: + +```python +class MoldQualityInspector: + """模具质量检测器""" + + def inspect_surface(self, surface) -> SurfaceQualityReport: + """检测分模面质量""" + pass + + def inspect_structure(self, mold) -> StructureQualityReport: + """检测模具结构""" + pass + + def assess_feasibility(self, mold, params) -> FeasibilityReport: + """评估生产可行性""" + pass + + def generate_report(self) -> QualityReport: + """生成质量报告""" + pass +``` + +#### 3.2.3 可视化模块 + +**模块职责**:3D 可视化渲染和交互 + +**主要类**: + +```python +class MoldVisualizationController: + """模具可视化控制器""" + + def load_model(self, shape): + """加载 3D 模型""" + pass + + def render_parting_surface(self, surface): + """渲染分型面""" + pass + + def render_parting_line(self, line): + """渲染分型线""" + pass + + def render_cavity_core(self, cavity, core): + """渲染型腔/型芯""" + pass + + def set_interaction_mode(self, mode): + """设置交互模式""" + pass + + def export_view(self, format): + """导出视图""" + pass +``` + +### 3.3 数据结构 + +#### 3.3.1 分模参数 + +```python +@dataclass +class MoldSplitParams: + """分模参数""" + # 分模参数 + split_mode: SplitMode = SplitMode.AUTO + parting_tolerance: float = 0.1 # mm + parting_line_precision: float = 0.1 # mm + cavity_match_rate: float = 95.0 # % + + # 铝泡沫参数 + foam_material: str = "AlSi10Mg" + target_density: float = 0.5 # g/cm³ + expansion_ratio: float = 2.5 + molding_temp: float = 380 # °C + + # 拔模参数 + min_draft_angle: float = 3.0 # ° + draft_direction: str = "auto" + friction_coefficient: float = 0.3 + + # 收缩补偿 + apply_shrinkage: bool = True + shrinkage_rate: float = 0.015 # 1.5% + + # 高级参数 + cavity_count: int = 1 + mold_material: str = "P20" + ejection_system: str = "pin" + + # 质量标准 + warpage_tolerance: float = 0.5 # mm + sink_mark_tolerance: float = 0.1 # mm +``` + +#### 3.3.2 分模结果 + +```python +@dataclass +class MoldSplitResult: + """分模结果""" + # 几何数据 + product_shape: TopoDS_Shape + cavity_shape: TopoDS_Shape + core_shape: TopoDS_Shape + parting_surface: TopoDS_Shape + parting_line: List[Point3D] + mold_block: TopoDS_Shape + + # 分析数据 + product_analysis: ProductAnalysis + quality_report: QualityReport + + # 参数数据 + params_used: MoldSplitParams + warnings: List[str] + suggestions: List[str] +``` + +--- + +## 4. 验收标准 + +### 4.1 功能验收 + +| 序号 | 验收项 | 验收标准 | 测试方法 | +|------|--------|----------|----------| +| 1 | 分型面检测 | 能正确分析产品几何并给出分型面建议 | 导入测试产品验证 | +| 2 | 分型线计算 | 计算得到真实的分型线路径(非简化矩形) | 对比验证 | +| 3 | 参数自定义 | 所有参数可自定义设置且生效 | 参数修改测试 | +| 4 | 3D 可视化 | 正确显示分模各组件 | 目视检查 | +| 5 | 交互调整 | 拖拽/滑块等交互响应正常 | 操作测试 | +| 6 | 质量检测 | 输出正确的质量报告 | 报告验证 | +| 7 | 数据导出 | 支持 STEP/JSON 格式导出 | 导出测试 | + +### 4.2 性能验收 + +| 指标 | 目标值 | 说明 | +|------|--------|------| +| 分模速度 | < 30 秒 | 典型产品 | +| 渲染帧率 | > 30 FPS | 交互操作时 | +| 内存占用 | < 2 GB | 典型产品 | +| 并发支持 | 5 用户 | 同时使用 | + +### 4.3 质量验收 + +| 指标 | 目标值 | 说明 | +|------|--------|------| +| 分型面准确率 | > 95% | 自动检测准确率 | +| 质量检测覆盖率 | 100% | 所有检测项 | +| 导出格式兼容 | STEP/IGES | 主流 CAD/CAM | + +--- + +## 5. 实施计划 + +### 5.1 阶段划分 + +| 阶段 | 时间 | 内容 | +|------|------|------| +| 第一阶段 | 1-2 周 | 基础框架搭建,参数系统 | +| 第二阶段 | 3-4 周 | 分模算法优化,质量检测 | +| 第三阶段 | 5-6 周 | 可视化增强,交互功能 | +| 第四阶段 | 7-8 周 | 数据接口,测试集成 | + +### 5.2 里程碑 + +- [ ] M1: 完成参数系统 (第 2 周) +- [ ] M2: 完成改进的分模算法 (第 4 周) +- [ ] M3: 完成质量检测模块 (第 6 周) +- [ ] M4: 完成可视化功能 (第 6 周) +- [ ] M5: 完成数据接口 (第 7 周) +- [ ] M6: 完成集成测试 (第 8 周) + +--- + +## 6. 附录 + +### 6.1 术语表 + +| 术语 | 英文 | 说明 | +|------|------|------| +| 分型面 | Parting Surface | 模具中分离型腔和型芯的平面 | +| 分型线 | Parting Line | 产品与分型面的交线 | +| 型腔 | Cavity | 模具中形成产品外形的空腔 | +| 型芯 | Core | 模具中形成产品内形的凸起 | +| 拔模角 | Draft Angle | 便于脱模的倾斜角度 | +| 收缩率 | Shrinkage Rate | 冷却后尺寸收缩比例 | +| 发泡倍率 | Expansion Ratio | 发泡前后的体积比 | + +### 6.2 参考资料 + +1. 《塑料模具设计手册》 +2. 《铝泡沫材料成型工艺》 +3. PythonOCC 官方文档 +4. Three.js 官方文档 + +--- + +**文档结束** diff --git a/docs/TASKS_ALUMINUM_FOAM_MOLD.md b/docs/TASKS_ALUMINUM_FOAM_MOLD.md new file mode 100644 index 0000000..49ef73c --- /dev/null +++ b/docs/TASKS_ALUMINUM_FOAM_MOLD.md @@ -0,0 +1,827 @@ +# 铝制家电包装泡沫模具分模功能开发任务清单 + +## 文档信息 + +| 项目 | 内容 | +|------|------| +| **文档名称** | 铝制家电包装泡沫模具分模功能开发任务清单 | +| **版本** | 1.0 | +| **日期** | 2026-03-13 | +| **项目** | geMoldInsight 模具分模功能增强 | + +--- + +## 任务总览 + +| 阶段 | 任务数 | 预计工期 | +|------|--------|----------| +| 第一阶段:基础框架 | 8 | 2 周 | +| 第二阶段:分模算法 | 10 | 2 周 | +| 第三阶段:质量检测 | 6 | 2 周 | +| 第四阶段:可视化和交互 | 8 | 2 周 | +| 第五阶段:数据接口和测试 | 6 | 1 周 | +| **总计** | **38** | **9 周** | + +--- + +## 第一阶段:基础框架搭建 (1-2 周) + +### 任务 1.1:创建铝泡沫模具参数类 + +**任务描述**:创建专门针对铝泡沫材料的参数配置类 + +**详细说明**: +- 在 `src/core/mold_generator.py` 中添加 `AluminumFoamMoldParams` 类 +- 定义铝泡沫专用参数(发泡倍率、目标密度、成型温度等) +- 实现参数验证和默认值设置 + +**验收标准**: +- 参数类包含所有铝泡沫专用参数 +- 参数验证通过 + +**预计工时**:4 小时 + +**依赖任务**:无 + +--- + +### 任务 1.2:创建铝泡沫材料数据库 + +**任务描述**:建立铝泡沫材料数据库,包含常用材料参数 + +**详细说明**: +- 创建材料数据库类 `FoamMaterialDatabase` +- 添加 AlSi10Mg、AlSi12、纯铝泡沫等常用材料 +- 支持材料查询和参数获取 + +**验收标准**: +- 数据库包含至少 5 种铝泡沫材料 +- 支持按名称查询材料参数 + +**预计工时**:4 小时 + +**依赖任务**:1.1 + +--- + +### 任务 1.3:扩展现有模具生成器 + +**任务描述**:扩展 `MoldCavityGenerator` 类支持铝泡沫参数 + +**详细说明**: +- 添加铝泡沫参数到构造函数 +- 添加材料设置方法 `set_foam_material()` +- 适配现有的分模流程 + +**验收标准**: +- 可以使用铝泡沫参数创建生成器 +- 参数正确传递给分模流程 + +**预计工时**:4 小时 + +**依赖任务**:1.1, 1.2 + +--- + +### 任务 1.4:创建参数配置 API 接口 + +**任务描述**:添加前端参数配置 API + +**详细说明**: +- 在 `src/api/routes.py` 中添加参数相关路由 +- 实现参数获取、设置、验证接口 +- 支持参数模板保存和加载 + +**验收标准**: +- API 可以获取和设置分模参数 +- 参数验证正确返回错误信息 + +**预计工时**:4 小时 + +**依赖任务**:1.3 + +--- + +### 任务 1.5:前端参数面板开发 + +**任务描述**:在 Web 界面中添加分模参数配置面板 + +**详细说明**: +- 在 `static/vue-app.js` 中添加参数配置组件 +- 实现滑块、输入框、选择框等控件 +- 支持参数实时预览 + +**验收标准**: +- 界面显示所有可配置参数 +- 参数修改正确提交到后端 + +**预计工时**:8 小时 + +**依赖任务**:1.4 + +--- + +### 任务 1.6:参数模板功能 + +**任务描述**:实现参数模板保存和加载功能 + +**详细说明**: +- 创建预设参数模板(快速、经济、高精度等) +- 支持用户保存自定义模板 +- 模板存储到数据库 + +**验收标准**: +- 至少 3 个预设模板可用 +- 用户可以保存和加载模板 + +**预计工时**:4 小时 + +**依赖任务**:1.4, 1.5 + +--- + +### 任务 1.7:参数验证逻辑 + +**任务描述**:实现参数合法性验证 + +**详细说明**: +- 验证数值范围(角度、容差等) +- 验证参数组合合法性 +- 返回详细的验证错误信息 + +**验收标准**: +- 所有参数都有验证逻辑 +- 错误信息清晰明了 + +**预计工时**:4 小时 + +**依赖任务**:1.1 + +--- + +### 任务 1.8:阶段一集成测试 + +**任务描述**:测试参数系统的完整性 + +**详细说明**: +- 测试参数设置和获取 +- 测试参数验证 +- 测试前端交互 + +**验收标准**: +- 所有功能正常运行 +- 无明显 bug + +**预计工时**:4 小时 + +**依赖任务**:1.1-1.7 + +--- + +## 第二阶段:分模算法优化 (3-4 周) + +### 任务 2.1:改进法向量分析算法 + +**任务描述**:改进分型面检测的法向量分析算法 + +**详细说明**: +- 添加高斯权重计算 +- 支持多点采样 +- 识别主分型方向 + +**验收标准**: +- 算法能正确处理复杂几何产品 +- 分型方向准确率 > 90% + +**预计工时**:8 小时 + +**依赖任务**:无 + +--- + +### 任务 2.2:实现多分型面检测 + +**任务描述**:支持复杂产品的多个分型面 + +**详细说明**: +- 识别需要多次分模的区域 +- 正确处理分型面优先级 +- 生成有序的分型面列表 + +**验收标准**: +- 能正确检测 2 个以上分型面 +- 分型面顺序正确 + +**预计工时**:12 小时 + +**依赖任务**:2.1 + +--- + +### 任务 2.3:倒扣区域检测 + +**任务描述**:自动识别产品倒扣区域 + +**详细说明**: +- 分析产品几何特征 +- 标记倒扣区域位置 +- 提供处理建议 + +**验收标准**: +- 能识别常见的倒扣类型 +- 提供准确的倒扣位置 + +**预计工时**:8 小时 + +**依赖任务**:2.1 + +--- + +### 任务 2.4:改进拔模角计算 + +**任务描述**:实现完整的拔模角计算和应用 + +**详细说明**: +- 使用 OpenCASCADE 拔模功能 +- 支持不同拔模方向 +- 处理拔模干涉 + +**验收标准**: +- 拔模角正确应用到模型 +- 无明显变形或错误 + +**预计工时**:12 小时 + +**依赖任务**:无 + +--- + +### 任务 2.5:铝泡沫收缩补偿 + +**任务描述**:针对铝泡沫实现特殊的收缩补偿 + +**详细说明**: +- 基于发泡倍率计算收缩 +- 多向收缩补偿 +- 补偿后尺寸验证 + +**验收标准**: +- 收缩补偿量准确 +- 补偿后模型无异常 + +**预计工时**:8 小时 + +**依赖任务**:1.2 + +--- + +### 任务 2.6:型腔分离优化 + +**任务描述**:改进型腔和型芯的分离算法 + +**详细说明**: +- 精确的布尔运算 +- 处理复杂几何 +- 分离结果验证 + +**验收标准**: +- 型腔/型芯分离正确 +- 分离过程无错误 + +**预计工时**:8 小时 + +**依赖任务**:无 + +--- + +### 任务 2.7:模具块生成 + +**任务描述**:生成完整的模具块结构 + +**详细说明**: +- 计算模具尺寸 +- 添加余量 +- 生成 A/B 板结构 + +**验收标准**: +- 模具块尺寸合理 +- 包含必要的结构元素 + +**预计工时**:8 小时 + +**依赖任务**:2.6 + +--- + +### 任务 2.8:分型线平滑处理 + +**任务描述**:对分型线进行平滑处理 + +**详细说明**: +- B 样条曲线拟合 +- 尖角处理 +- 平滑度验证 + +**验收标准**: +- 分型线平滑无毛刺 +- 保持原始几何精度 + +**预计工时**:6 小时 + +**依赖任务**:2.2 + +--- + +### 任务 2.9:算法性能优化 + +**任务描述**:优化分模算法性能 + +**详细说明**: +- 并行计算支持 +- 缓存优化 +- 增量计算 + +**验收标准**: +- 分模时间 < 30 秒 +- 内存占用 < 1GB + +**预计工时**:8 小时 + +**依赖任务**:2.1-2.8 + +--- + +### 任务 2.10:阶段二集成测试 + +**任务描述**:测试分模算法的完整流程 + +**详细说明**: +- 使用测试产品验证 +- 对比不同参数结果 +- 性能测试 + +**验收标准**: +- 算法稳定运行 +- 结果准确合理 + +**预计工时**:8 小时 + +**依赖任务**:2.1-2.9 + +--- + +## 第三阶段:质量检测模块 (5-6 周) + +### 任务 3.1:创建质量检测器类 + +**任务描述**:创建 `MoldQualityInspector` 质量检测类 + +**详细说明**: +- 设计检测器架构 +- 定义检测接口 +- 实现结果数据结构 + +**验收标准**: +- 类结构完整 +- 接口定义清晰 + +**预计工时**:4 小时 + +**依赖任务**:无 + +--- + +### 任务 3.2:分模面平滑度检测 + +**任务描述**:检测分模面的平滑度 + +**详细说明**: +- 曲率分析 +- 凹凸检测 +- 评分计算 + +**验收标准**: +- 正确识别不平滑区域 +- 给出评分 (0-100) + +**预计工时**:8 小时 + +**依赖任务**:3.1 + +--- + +### 任务 3.3:分模面连续性检测 + +**任务描述**:检测分模面的连续性 + +**详细说明**: +- 边界检查 +- 间隙检测 +- 完整性验证 + +**验收标准**: +- 能识别间隙和断点 +- 报告位置和大小 + +**预计工时**:6 小时 + +**依赖任务**:3.1 + +--- + +### 任务 3.4:模具结构合理性检测 + +**任务描述**:检测模具结构的合理性 + +**详细说明**: +- 模具尺寸检查 +- 壁厚检查 +- 干涉检查 + +**验收标准**: +- 识别所有结构问题 +- 提供修改建议 + +**预计工时**:8 小时 + +**依赖任务**:3.1 + +--- + +### 任务 3.5:生产可行性评估 + +**任务描述**:评估模具的生产可行性 + +**详细说明**: +- 注塑压力计算 +- 锁模力计算 +- 成型周期估算 + +**验收标准**: +- 估算值在合理范围 +- 提供改进建议 + +**预计工时**:8 小时 + +**依赖任务**:3.1 + +--- + +### 任务 3.6:质量报告生成 + +**任务描述**:生成完整的质量检测报告 + +**详细说明**: +- 汇总各项检测结果 +- 生成 PDF 格式报告 +- 支持导出 + +**验收标准**: +- 报告内容完整 +- 格式规范 + +**预计工时**:6 小时 + +**依赖任务**:3.2-3.5 + +--- + +## 第四阶段:可视化和交互 (5-6 周) + +### 任务 4.1:分型面可视化增强 + +**任务描述**:改进分型面的可视化效果 + +**详细说明**: +- 分型面颜色和透明度设置 +- 边缘高亮 +- 动态效果 + +**验收标准**: +- 分型面清晰可见 +- 与产品形成对比 + +**预计工时**:4 小时 + +**依赖任务**:无 + +--- + +### 任务 4.2:分型线可视化增强 + +**任务描述**:改进分型线的可视化 + +**详细说明**: +- 线条颜色和粗细 +- 端点标记 +- 动态绘制效果 + +**验收标准**: +- 分型线清晰可见 +- 便于观察细节 + +**预计工时**:4 小时 + +**依赖任务**:无 + +--- + +### 任务 4.3:交互式分型面调整 + +**任务描述**:支持用户拖拽调整分型面 + +**详细说明**: +- 鼠标拖拽事件 +- 实时更新模型 +- 撤销/重做支持 + +**验收标准**: +- 拖拽响应流畅 +- 模型正确更新 + +**预计工时**:12 小时 + +**依赖任务**:4.1 + +--- + +### 任务 4.4:交互式参数调整 + +**任务描述**:支持实时调整参数并预览效果 + +**详细说明**: +- 滑块实时更新 +- 参数变化动画 +- 效果对比 + +**验收标准**: +- 调整流畅无延迟 +- 效果正确显示 + +**预计工时**:8 小时 + +**依赖任务**:1.5 + +--- + +### 任务 4.5:剖视图功能 + +**任务描述**:添加剖视图功能 + +**详细说明**: +- 沿分型面剖切 +- 内部结构显示 +- 剖面编辑 + +**验收标准**: +- 剖视图正确显示 +- 切换流畅 + +**预计工时**:8 小时 + +**依赖任务**:4.1 + +--- + +### 任务 4.6:测量工具 + +**任务描述**:添加测量工具 + +**详细说明**: +- 距离测量 +- 角度测量 +- 测量结果标注 + +**验收标准**: +- 测量结果准确 +- 操作便捷 + +**预计工时**:8 小时 + +**依赖任务**:无 + +--- + +### 任务 4.7:视角控制增强 + +**任务描述**:改进视角控制 + +**详细说明**: +- 预设视角 +- 动画过渡 +- 自动对准 + +**验收标准**: +- 视角切换流畅 +- 自动对准准确 + +**预计工时**:4 小时 + +**依赖任务**:无 + +--- + +### 任务 4.8:导出视图功能 + +**任务描述**:支持导出当前视图 + +**详细说明**: +- PNG 图片导出 +- 高清截图 +- 报告插图 + +**验收标准**: +- 导出图片清晰 +- 格式正确 + +**预计工时**:4 小时 + +**依赖任务**:4.1-4.7 + +--- + +## 第五阶段:数据接口和测试 (7-8 周) + +### 任务 5.1:STEP 导出接口 + +**任务描述**:实现 STEP 格式导出 + +**详细说明**: +- 使用 PythonOCC 导出 STEP +- 包含分模后模型 +- 验证导出正确性 + +**验收标准**: +- 导出文件可被 CAD 打开 +- 几何正确 + +**预计工时**:8 小时 + +**依赖任务**:无 + +--- + +### 任务 5.2:JSON 数据导出 + +**任务描述**:实现 JSON 格式导出 + +**详细说明**: +- 导出分模参数 +- 导出几何数据 +- 导出质量报告 + +**验收标准**: +- JSON 格式正确 +- 数据完整 + +**预计工时**:4 小时 + +**依赖任务**:无 + +--- + +### 任务 5.3:PDF 报告导出 + +**任务描述**:实现 PDF 格式报告导出 + +**详细说明**: +- 质量检测报告 +- 包含图表和说明 +- 模板支持 + +**验收标准**: +- PDF 生成成功 +- 内容完整 + +**预计工时**:8 小时 + +**依赖任务**:3.6 + +--- + +### 任务 5.4:IGES 格式支持 + +**任务描述**:添加 IGES 格式支持 + +**详细说明**: +- IGES 导入 +- IGES 导出 +- 格式验证 + +**验收标准**: +- 导出文件可被 CAM 软件使用 + +**预计工时**:6 小时 + +**依赖任务**:5.1 + +--- + +### 任务 5.5:集成测试 + +**任务描述**:完整的系统集成测试 + +**详细说明**: +- 功能测试 +- 性能测试 +- 兼容性测试 + +**验收标准**: +- 所有功能正常运行 +- 达到性能指标 + +**预计工时**:8 小时 + +**依赖任务**:全部 + +--- + +### 任务 5.6:用户验收测试 + +**任务描述**:配合用户进行验收测试 + +**详细说明**: +- 演示功能 +- 收集反馈 +- 修复问题 + +**验收标准**: +- 用户满意 +- 达到预期目标 + +**预计工时**:8 小时 + +**依赖任务**:5.5 + +--- + +## 任务依赖关系图 + +``` +第一阶段: 基础框架 +├── 1.1 创建参数类 +├── 1.2 材料数据库 ──┐ +├── 1.3 扩展生成器 ──┼── 1.4 API ──┬── 1.5 前端 ──┬── 1.6 模板 ──┬── 1.7 验证 ──→ 1.8 测试 +│ │ │ │ │ +└────────────────────┴──────────────┴──────────────┴──────────────┘ + +第二阶段: 分模算法 +│ +├── 2.1 法向量分析 ──→ 2.2 多分型面 ──→ 2.3 倒扣检测 +│ +├── 2.4 拔模角 ──────────────────────────────────────────────────────────┐ +│ │ +├── 2.5 收缩补偿 ◄──────────────────┐ │ +│ │ │ +├── 2.6 型腔分离 ──→ 2.7 模具块 ──→ 2.8 平滑处理 ──→ 2.9 优化 ──→ 2.10 测试 +│ │ +└────────────────────────────────────┴────────────────────────────────────┘ + +第三阶段: 质量检测 +│ +├── 3.1 检测器类 ──→ 3.2 平滑度 ──→ 3.3 连续性 ──→ 3.4 结构 ──→ 3.5 可行性 ──→ 3.6 报告 +│ +└────────────────────────────────────┬────────────────────────────────────┘ + +第四阶段: 可视化 +│ +├── 4.1 分型面 ──→ 4.2 分型线 ──→ 4.3 拖拽 ──→ 4.4 参数调整 ──→ 4.5 剖视 +│ │ │ +├── 4.6 测量 ──→ 4.7 视角 ──→ 4.8 导出 ◄─────────────┘ +│ +└────────────────────────────────────┬────────────────────────────────────┘ + +第五阶段: 接口和测试 +│ +├── 5.1 STEP ──→ 5.2 JSON ◄──┐ +│ │ +├── 5.3 PDF ◄─────────────────┼── 5.4 IGES ──→ 5.5 集成 ──→ 5.6 验收 +│ │ +└──────────────────────────────┘ +``` + +--- + +## 资源分配 + +| 角色 | 任务 | 预计工时 | +|------|------|----------| +| 后端开发 | 1.1-1.4, 2.1-2.10, 3.1-3.6, 5.1-5.4 | 180 小时 | +| 前端开发 | 1.5-1.6, 4.1-4.8 | 60 小时 | +| 测试 | 1.8, 2.10, 5.5-5.6 | 32 小时 | +| **总计** | | **272 小时** | + +--- + +## 风险评估 + +| 风险 | 影响 | 应对措施 | +|------|------|----------| +| 算法复杂度高 | 时间延误 | 预留缓冲时间,分阶段交付 | +| OpenCASCADE 兼容问题 | 功能受限 | 多种实现方案,准备备选 | +| 性能不达标 | 用户体验差 | 持续优化,必要时降级功能 | +| 需求变更 | 计划调整 | 敏捷开发,快速迭代 | + +--- + +**文档结束** diff --git a/scripts/test_aluminum_foam_mold.py b/scripts/test_aluminum_foam_mold.py new file mode 100644 index 0000000..9fddb79 --- /dev/null +++ b/scripts/test_aluminum_foam_mold.py @@ -0,0 +1,146 @@ +""" +测试铝泡沫模具分模功能 +""" +import sys +sys.path.insert(0, "src") + +def test_imports(): + """测试模块导入""" + print("测试模块导入...") + + try: + from core.aluminum_foam_mold import AluminumFoamMoldGenerator + print("✅ AluminumFoamMoldGenerator 导入成功") + + from core.mold_quality_inspector import AluminumFoamMoldQualityInspector + print("✅ AluminumFoamMoldQualityInspector 导入成功") + + return True + except Exception as e: + print(f"❌ 导入失败: {e}") + import traceback + traceback.print_exc() + return False + + +def test_foam_materials(): + """测试铝泡沫材料数据库""" + print("\n测试铝泡沫材料数据库...") + + from core.aluminum_foam_mold import AluminumFoamMoldGenerator + + gen = AluminumFoamMoldGenerator() + + # 检查材料数据库 + expected_materials = ["AlSi10Mg", "AlSi12", "Pure Al Foam", "AlSi7Mg"] + + for material in expected_materials: + if material in gen.foam_materials: + props = gen.foam_materials[material] + print(f"✅ {material}: 密度={props['density']}, 发泡倍率={props['expansion_ratio']}") + else: + print(f"❌ 缺少材料: {material}") + return False + + return True + + +def test_material_setting(): + """测试材料设置""" + print("\n测试材料设置...") + + from core.aluminum_foam_mold import AluminumFoamMoldGenerator + + gen = AluminumFoamMoldGenerator() + + # 测试设置铝泡沫材料 + gen.set_foam_material("AlSi10Mg") + + if gen.material_density == 0.45 and gen.shrinkage_rate == 0.015: + print("✅ 材料设置正确: AlSi10Mg") + else: + print(f"❌ 材料参数不正确: density={gen.material_density}, shrinkage={gen.shrinkage_rate}") + return False + + # 测试塑料材料 + gen.set_material("ABS") + if gen.material_density == 1.05: + print("✅ 塑料材料设置正确: ABS") + else: + print("❌ 塑料材料设置失败") + return False + + return True + + +def test_quality_inspector(): + """测试质量检测器""" + print("\n测试质量检测器...") + + from core.mold_quality_inspector import AluminumFoamMoldQualityInspector + + inspector = AluminumFoamMoldQualityInspector() + + # 测试数据结构 + test_data = { + "parting_line": [[0,0,0], [10,0,0], [10,10,0], [0,10,0], [0,0,0]], + "cavity": True, + "core": True, + "parting_surface": True, + "analysis": { + "volume": 1000000, + "bounding_box": {"dimensions": [100, 80, 50]} + }, + "undercut_regions": [] + } + + result = inspector.inspect_surface_quality(test_data) + + if "overall_score" in result: + print(f"✅ 质量检测正常工作, 评分: {result['overall_score']:.1f}") + return True + else: + print("❌ 质量检测返回数据格式错误") + return False + + +def main(): + """运行所有测试""" + print("="*50) + print("铝泡沫模具分模功能测试") + print("="*50) + + tests = [ + test_imports, + test_foam_materials, + test_material_setting, + test_quality_inspector, + ] + + results = [] + for test in tests: + try: + results.append(test()) + except Exception as e: + print(f"❌ 测试异常: {e}") + results.append(False) + + print("\n" + "="*50) + print("测试结果汇总") + print("="*50) + + passed = sum(results) + total = len(results) + + print(f"通过: {passed}/{total}") + + if passed == total: + print("\n🎉 所有测试通过!") + return 0 + else: + print(f"\n⚠️ {total - passed} 个测试失败") + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/api/routes.py b/src/api/routes.py index 5ecd799..6667700 100644 --- a/src/api/routes.py +++ b/src/api/routes.py @@ -15,6 +15,8 @@ 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.aluminum_foam_mold import AluminumFoamMoldGenerator +from core.mold_quality_inspector import AluminumFoamMoldQualityInspector from core.mesh_generator import MeshGenerator logger = get_logger(__name__) @@ -26,6 +28,10 @@ geometry_analyzer = GeometryAnalyzer() file_handler = FileHandler() html_generator = HTMLGenerator() mold_generator = MoldCavityGenerator(shrinkage_rate=0.005) +# 铝泡沫模具生成器 +aluminum_foam_generator = AluminumFoamMoldGenerator(shrinkage_rate=0.015, draft_angle=3.0) +# 铝泡沫模具质量检测器 +mold_quality_inspector = AluminumFoamMoldQualityInspector() mesh_generator = MeshGenerator(quality="medium") tasks = {} @@ -45,6 +51,7 @@ async def health(): async def upload_stp( background_tasks: BackgroundTasks, file: UploadFile = File(...), + material: Optional[str] = "ABS", db_session: AsyncSession = Depends(get_db_session) ): """上传STP文件并存储到数据库""" @@ -82,7 +89,7 @@ async def upload_stp( ) # 后台处理(包含数据库存储) - background_tasks.add_task(process_file_with_storage, task_id, file_path, stp_file.id, db_session) + background_tasks.add_task(process_file_with_storage, task_id, file_path, stp_file.id, db_session, material) return { "task_id": task_id, @@ -300,7 +307,8 @@ async def process_file_with_storage( task_id: str, file_path: str, stp_file_id: int, - db_session: AsyncSession + db_session: AsyncSession, + material: str = "ABS" ): """处理文件的后台任务""" @@ -319,7 +327,7 @@ async def process_file_with_storage( # 使用超时保护 try: - await asyncio.wait_for(process_file_core(storage_service, task_id, file_path, stp_file_id, db_session), timeout_seconds) + await asyncio.wait_for(process_file_core(storage_service, task_id, file_path, stp_file_id, db_session, material), timeout_seconds) except asyncio.TimeoutError: logger.error(f"处理超时: {task_id}") raise Exception(f"处理超时,超过{timeout_seconds}秒未完成") @@ -403,7 +411,8 @@ async def process_file_core( task_id: str, file_path: str, stp_file_id: int, - db_session: AsyncSession + db_session: AsyncSession, + material: str = "ABS" ): """核心处理逻辑""" @@ -496,9 +505,19 @@ async def process_file_core( if shape: # 生成型腔和型芯 cavity_result = mold_generator.generate_mold_cavities(shape) + if is_foam_material: + # 使用铝泡沫模具生成器 + aluminum_foam_generator.set_material(selected_material["name"]) + cavity_result = aluminum_foam_generator.generate_mold_cavities(shape) + cavity_mesh_data = aluminum_foam_generator.generate_detailed_cavity_json(cavity_result) + logger.info(f"使用铝泡沫模具生成器: {selected_material['name']}") + else: + # 使用普通塑料模具生成器 + cavity_result = mold_generator.generate_mold_cavities(shape) + cavity_mesh_data = mold_generator.generate_detailed_cavity_json(cavity_result) # 生成详细的型腔JSON数据(包含网格) - cavity_mesh_data = mold_generator.generate_detailed_cavity_json(cavity_result) + if cavity_mesh_data: logger.info(f"型腔网格数据生成完成: {cavity_mesh_data.get('mold_cavities', {}).get('cavity', {}).get('vertex_count', 0)} 顶点") except Exception as cavity_err: logger.warning(f"型腔生成失败,使用简化数据: {cavity_err}") @@ -525,10 +544,20 @@ async def process_file_core( "POM": {"density": 1.41, "shrinkage": 0.020, "name": "POM"}, "PMMA": {"density": 1.18, "shrinkage": 0.005, "name": "PMMA"}, "PBT": {"density": 1.31, "shrinkage": 0.015, "name": "PBT"}, + # 铝泡沫材料 + "AlSi10Mg": {"density": 0.45, "shrinkage": 0.015, "name": "AlSi10Mg", "is_foam": True}, + "AlSi12": {"density": 0.50, "shrinkage": 0.012, "name": "AlSi12", "is_foam": True}, + "Pure Al Foam": {"density": 0.35, "shrinkage": 0.020, "name": "Pure Al Foam", "is_foam": True}, + "AlSi7Mg": {"density": 0.40, "shrinkage": 0.018, "name": "AlSi7Mg", "is_foam": True}, } # 默认使用 ABS - selected_material = material_properties["ABS"] + # 获取材料属性(支持前端传递的材料参数) + requested_material = material if material in material_properties else "ABS" + selected_material = material_properties.get(requested_material, material_properties["ABS"]) + + # 检查是否是泡沫材料 + is_foam_material = selected_material.get("is_foam", False) material_density = selected_material["density"] shrinkage_rate = selected_material["shrinkage"] diff --git a/src/core/aluminum_foam_mold.py b/src/core/aluminum_foam_mold.py new file mode 100644 index 0000000..296cb6f --- /dev/null +++ b/src/core/aluminum_foam_mold.py @@ -0,0 +1,1013 @@ +""" +增强版铝制家电包装泡沫模具分模算法 + +本模块实现了针对铝泡沫模具的优化分模算法,包括: +1. 改进的法向量分析 - 高斯权重、多点采样 +2. 多分型面检测 - 支持复杂产品 +3. 倒扣区域检测 - 自动识别 +4. 完整拔模角处理 - BRepOffsetAPI_DraftAngle +5. 铝泡沫收缩补偿 - 基于发泡倍率 +6. 优化的型腔分离 - 精确布尔运算 +7. 模具块生成 - A/B板结构 +8. 分型线平滑处理 - B样条拟合 +""" + +from pathlib import Path +from typing import Dict, List, Any, Tuple, Optional +import numpy as np +from OCC.Core.BRepOffsetAPI import BRepOffsetAPI_MakeThickSolid +from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Cut, BRepAlgoAPI_Fuse, BRepAlgoAPI_Section +from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeFace, BRepBuilderAPI_Transform +from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox +from OCC.Core.Geom import Geom_Plane +from OCC.Core.gp import gp_Pln, gp_Dir, gp_Pnt, gp_Vec, gp_Trsf +from OCC.Core.TopTools import TopTools_ListOfShape +from OCC.Core.TopoDS import TopoDS_Face, TopoDS_Shape, TopoDS_Edge, TopoDS_Vertex +from OCC.Core.BRep import BRep_Tool +from OCC.Core.TopLoc import TopLoc_Location +from OCC.Core.BRepMesh import BRepMesh_IncrementalMesh +from OCC.Core.BRepExtrema import BRepExtrema_DistShapeShape +from OCC.Core.GProp import GProp_GProps +from OCC.Core.BRepGProp import brepgprop +from OCC.Core.TopExp import TopExp_Explorer +from OCC.Core.TopAbs import TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX +from OCC.Core.BRepAdaptor import BRepAdaptor_Surface, BRepAdaptor_Curve +from OCC.Core.Bnd import Bnd_Box +from OCC.Core.BRepBndLib import brepbndlib_Add + +from models.schemas import create_mold_cavity_data, create_mold_key_info +from utils.logger import get_logger + +logger = get_logger(__name__) + + +class AluminumFoamMoldGenerator: + """铝制家电包装泡沫模具分模生成器""" + + def __init__(self, + shrinkage_rate: float = 0.015, + draft_angle: float = 3.0, + material_density: float = 0.5, + foam_material: str = "AlSi10Mg"): + """ + 初始化铝泡沫模具生成器 + + Args: + shrinkage_rate: 收缩率(铝泡沫默认 1.5%) + draft_angle: 拔模角(铝泡沫建议 3-5°) + material_density: 材料密度 g/cm³(铝泡沫 0.3-0.8) + foam_material: 泡沫材料类型 + """ + self.shrinkage_rate = shrinkage_rate + self.draft_angle = draft_angle + self.material_density = material_density + self.foam_material = foam_material + + # 铝泡沫材料数据库 + self.foam_materials = { + "AlSi10Mg": { + "density": 0.45, + "expansion_ratio": 2.5, + "shrinkage_rate": 0.015, + "molding_temp": 380, + "description": "常用铝硅泡沫" + }, + "AlSi12": { + "density": 0.50, + "expansion_ratio": 2.2, + "shrinkage_rate": 0.012, + "molding_temp": 360, + "description": "高强度铝泡沫" + }, + "Pure Al Foam": { + "density": 0.35, + "expansion_ratio": 3.0, + "shrinkage_rate": 0.020, + "molding_temp": 400, + "description": "纯铝泡沫" + }, + "AlSi7Mg": { + "density": 0.40, + "expansion_ratio": 2.8, + "shrinkage_rate": 0.018, + "molding_temp": 390, + "description": "轻质铝镁泡沫" + } + } + + # 塑料材料数据库(保留原有) + self.plastic_materials = { + "ABS": {"density": 1.05, "shrinkage": 0.005}, + "PP": {"density": 0.90, "shrinkage": 0.016}, + "PC": {"density": 1.20, "shrinkage": 0.005}, + "PE": {"density": 0.95, "shrinkage": 0.025}, + "PS": {"density": 1.05, "shrinkage": 0.004}, + "PA": {"density": 1.14, "shrinkage": 0.015}, + "POM": {"density": 1.42, "shrinkage": 0.020}, + "PMMA": {"density": 1.18, "shrinkage": 0.004} + } + + # 分模参数 + self.parting_line_tolerance = 0.1 + self.max_draft_angle = 5.0 + self.min_draft_angle = 1.0 + + # 高级参数 + self.cavity_count = 1 + self.parting_precision = 0.1 # mm + self.cavity_match_rate = 95.0 # % + + # AI 模型接口 + self.ai_parting_detector = None + self.ai_draft_analyzer = None + + def set_foam_material(self, material: str): + """设置铝泡沫材料""" + if material in self.foam_materials: + props = self.foam_materials[material] + self.foam_material = material + self.material_density = props["density"] + self.shrinkage_rate = props["shrinkage_rate"] + logger.info(f"铝泡沫材料设置为 {material}, 密度: {props['density']} g/cm³") + else: + logger.warning(f"未知材料 {material}, 使用当前设置") + + def set_material(self, material: str): + """设置材料(自动识别类型)""" + if material in self.foam_materials: + self.set_foam_material(material) + elif material in self.plastic_materials: + props = self.plastic_materials[material] + self.material_density = props["density"] + self.shrinkage_rate = props["shrinkage"] + logger.info(f"塑料材料设置为 {material}, 密度: {props['density']} g/cm³") + else: + logger.warning(f"未知材料 {material}") + + def generate_mold_cavities(self, product_shape: Any) -> Dict[str, Any]: + """ + 从产品的3D模型生成型腔和型芯 + + 完整流程: + 1. 分析产品几何 + 2. 检测分型面(支持多分型面) + 3. 检测倒扣区域 + 4. 应用收缩率补偿 + 5. 应用拔模角 + 6. 分离型腔和型芯 + 7. 生成模具块 + """ + logger.info(f"开始生成铝泡沫模具型腔 (材料: {self.foam_material})...") + + try: + # Step 1: 分析产品几何 + analysis = self._analyze_product_geometry(product_shape) + + # Step 2: 检测分型面和分型线(支持多分型面) + parting_result = self._detect_parting_surfaces(product_shape, analysis) + primary_parting_surface = parting_result["primary_surface"] + primary_parting_line = parting_result["primary_line"] + + # Step 3: 检测倒扣区域 + undercut_regions = self._detect_undercut_regions(product_shape, primary_parting_surface) + + # Step 4: 应用收缩率补偿 + scaled_shape = self._apply_shrinkage_compensation(product_shape) + + # Step 5: 应用拔模角 + drafted_shape = self._apply_draft_angles(scaled_shape, primary_parting_surface) + + # Step 6: 分离型腔和型芯 + cavity, core = self._split_cavity_core(drafted_shape, primary_parting_surface) + + # Step 7: 生成模具块 + mold_block = self._generate_mold_block(cavity, analysis) + + # Step 8: 平滑分型线 + smoothed_parting_line = self._smooth_parting_line(primary_parting_line) + + logger.info("铝泡沫模具型腔生成完成") + + return { + "cavity": cavity, + "core": core, + "parting_surface": primary_parting_surface, + "parting_line": smoothed_parting_line, + "mold_block": mold_block, + "analysis": analysis, + "undercut_regions": undercut_regions, + "parting_surfaces": parting_result, + "material": self.foam_material, + "shrinkage_applied": self.shrinkage_rate, + "draft_angle_applied": self.draft_angle + } + + except Exception as e: + logger.error(f"模具型腔生成失败: {e}") + raise + + def generate_detailed_cavity_json(self, cavity_data: Dict) -> Dict[str, Any]: + """生成详细的型腔三维JSON数据""" + cavity = cavity_data["cavity"] + core = cavity_data["core"] + parting_surface = cavity_data["parting_surface"] + analysis = cavity_data["analysis"] + + # 提取几何数据 + cavity_geometry = self._extract_shape_geometry(cavity, "cavity") + core_geometry = self._extract_shape_geometry(core, "core") + + # 提取分型面数据 + parting_geometry = self._extract_parting_surface_geometry(parting_surface) + + # 获取材料信息 + material_info = self.foam_materials.get(self.foam_material, {}) + + detailed_json = { + "metadata": { + "version": "3.0", + "generated_at": str(np.datetime64('now')), + "mold_type": "aluminum_foam", + "shrinkage_rate": self.shrinkage_rate, + "draft_angle": self.draft_angle, + "unit": "mm", + "foam_material": self.foam_material + }, + "product_analysis": { + "bounding_box": analysis.get("bounding_box", {}), + "volume": analysis.get("volume", 0), + "surface_area": analysis.get("surface_area", 0), + "center_of_mass": analysis.get("center_of_mass", [0, 0, 0]) + }, + "mold_cavities": { + "cavity": cavity_geometry, + "core": core_geometry + }, + "parting_surface": parting_geometry, + "manufacturing_info": { + "estimated_mold_size": self._calculate_mold_size(analysis), + "estimated_clamping_force": self._calculate_clamping_force(analysis), + "recommended_material": material_info.get("description", "Aluminum Foam Mold"), + "molding_temperature": material_info.get("molding_temp", 380), + "expansion_ratio": material_info.get("expansion_ratio", 2.5) + }, + "quality_checks": { + "undercut_regions": cavity_data.get("undercut_regions", []), + "parting_line_smoothness": self._assess_parting_line_smoothness( + cavity_data.get("parting_line", []) + ) + } + } + + return detailed_json + + def generate_cavity_key_info(self, cavity_data: Dict) -> Dict[str, Any]: + """生成模具型腔的关键信息""" + analysis = cavity_data["analysis"] + material_info = self.foam_materials.get(self.foam_material, {}) + + key_info = { + "mold_parameters": { + "shrinkage_rate": f"{self.shrinkage_rate * 100:.2f}%", + "draft_angle": f"{self.draft_angle}°", + "parting_line_length": self._calculate_parting_line_length( + cavity_data.get("parting_line", []) + ), + "cavity_depth": analysis.get("bounding_box", {}).get("dimensions", [0, 0, 0])[2], + "foam_material": self.foam_material, + "molding_temp": f"{material_info.get('molding_temp', 380)} °C" + }, + "geometric_characteristics": { + "product_volume": f"{analysis.get('volume', 0) / 1000:.2f} cm³", + "product_weight": self._calculate_product_weight(analysis), + "wall_thickness_range": self._estimate_wall_thickness(analysis), + "complexity_score": self._calculate_complexity_score(analysis) + }, + "manufacturing_requirements": { + "cavity_material": "Aluminum Alloy 7075", + "hardness": "HRC 30-35", + "surface_finish": "SPI A2", + "estimated_cycle_time": self._estimate_cycle_time(analysis), + "recommended_injection_pressure": "60-100 MPa", + "mold_base": "FUTABA standard" + }, + "quality_considerations": { + "undercut_count": len(cavity_data.get("undercut_regions", [])), + "undercut_regions": cavity_data.get("undercut_regions", []), + "sink_mark_risk": self._identify_sink_mark_risk(analysis), + "warpage_risk": self._assess_warpage_risk(analysis), + "venting_requirement": self._assess_venting_requirement(analysis) + } + } + + return key_info + + # ==================== 核心算法实现 ==================== + + def _analyze_product_geometry(self, shape: Any) -> Dict[str, Any]: + """分析产品几何属性""" + # 体积属性 + volume_props = GProp_GProps() + brepgprop.VolumeProperties(shape, volume_props) + + # 表面积属性 + surface_props = GProp_GProps() + brepgprop.SurfaceProperties(shape, surface_props) + + # 边界框 + bbox = Bnd_Box() + brepbndlib_Add(shape, bbox) + xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get() + + # 表面法向量统计 + normal_stats = self._analyze_face_normals(shape) + + return { + "volume": volume_props.Mass(), + "surface_area": surface_props.Mass(), + "center_of_mass": [ + volume_props.CentreOfMass().X(), + volume_props.CentreOfMass().Y(), + volume_props.CentreOfMass().Z() + ], + "bounding_box": { + "min": [xmin, ymin, zmin], + "max": [xmax, ymax, zmax], + "dimensions": [xmax - xmin, ymax - ymin, zmax - zmin], + "center": [(xmin + xmax) / 2, (ymin + ymax) / 2, (zmin + zmax) / 2] + }, + "normal_statistics": normal_stats, + "inertia_matrix": self._get_inertia_matrix(volume_props) + } + + def _analyze_face_normals(self, shape: Any) -> Dict[str, Any]: + """ + 改进的法向量分析 - 使用高斯权重和多点采样 + """ + face_normals = [] + face_centers = [] + face_areas = [] + + explorer = TopExp_Explorer(shape, TopAbs_FACE) + + while explorer.More(): + face = TopoDS_Face(explorer.Current()) + try: + surface = BRepAdaptor_Surface(face) + + # 获取面参数范围 + u_min, u_max = surface.FirstUParameter(), surface.LastUParameter() + v_min, v_max = surface.FirstVParameter(), surface.LastVParameter() + + # 多点采样计算法向量 + sample_points = 4 + normal_sum = np.array([0.0, 0.0, 0.0]) + + for i in range(sample_points): + for j in range(sample_points): + u = u_min + (u_max - u_min) * i / (sample_points - 1) if sample_points > 1 else (u_min + u_max) / 2 + v = v_min + (v_max - v_min) * j / (sample_points - 1) if sample_points > 1 else (v_min + v_max) / 2 + + if surface.GetType() == 0: # Plane + normal = surface.Plane().Position().Direction() + normal_sum += np.array([normal.X(), normal.Y(), normal.Z()]) + break + if surface.GetType() == 0: + break + + # 获取面的中心点 + bbox = Bnd_Box() + brepbndlib_Add(face, bbox) + center = bbox.Center() + + # 获取面面积 + face_props = GProp_GProps() + brepgprop.SurfaceProperties(face, face_props) + area = face_props.Mass() + + # 归一化法向量 + length = np.linalg.norm(normal_sum) + if length > 0.001: + normal_sum /= length + + face_normals.append(normal_sum) + face_centers.append([center.X(), center.Y(), center.Z()]) + face_areas.append(area) + + except Exception as e: + logger.debug(f"面分析失败: {e}") + + explorer.Next() + + if not face_normals: + return { + "primary_direction": [0, 0, 1], + "confidence": 0.5, + "face_count": 0 + } + + # 使用面积作为权重计算加权平均法向量 + total_area = sum(face_areas) + weighted_normal = np.array([0.0, 0.0, 0.0]) + + for i, normal in enumerate(face_normals): + weight = face_areas[i] / total_area if total_area > 0 else 1.0 / len(face_normals) + weighted_normal += normal * weight + + # 归一化 + length = np.linalg.norm(weighted_normal) + if length > 0.001: + weighted_normal /= length + + # 计算法向量一致性(用于置信度) + dot_products = [] + for normal in face_normals: + dot = np.dot(normal, weighted_normal) + dot_products.append(abs(dot)) + + confidence = np.mean(dot_products) if dot_products else 0.5 + + return { + "primary_direction": weighted_normal.tolist(), + "confidence": float(confidence), + "face_count": len(face_normals), + "normal_distribution": face_normals + } + + def _detect_parting_surfaces(self, shape: Any, analysis: Dict) -> Dict[str, Any]: + """ + 检测分型面(支持多分型面) + """ + # 1. 尝试 AI 模型 + if self.ai_parting_detector is not None: + try: + ai_result = self.ai_parting_detector.detect(shape, analysis) + if ai_result: + return self._create_parting_surface_from_ai(ai_result, analysis) + except Exception as e: + logger.warning(f"AI 分型面检测失败: {e}") + + # 2. 法向量分析确定主方向 + normal_stats = analysis.get("normal_statistics", {}) + primary_direction = normal_stats.get("primary_direction", [0, 0, 1]) + + # 3. 创建主分型面 + bbox = analysis["bounding_box"] + center = bbox["center"] + + # 沿主方向创建分型面 + dir_obj = gp_Dir(primary_direction[0], primary_direction[1], primary_direction[2]) + parting_plane = gp_Pln(gp_Pnt(center[0], center[1], center[2]), dir_obj) + + try: + parting_surface = BRepBuilderAPI_MakeFace(parting_plane).Face() + except: + # 回退到默认平面 + parting_plane = gp_Pln(gp_Pnt(0, 0, center[2]), gp_Dir(0, 0, 1)) + parting_surface = BRepBuilderAPI_MakeFace(parting_plane).Face() + + # 4. 计算分型线 + parting_line = self._calculate_parting_line(shape, parting_surface) + + # 5. 检测是否需要多分型面(基于产品复杂度) + additional_surfaces = [] + + # 检查产品高度方向的比例 + dims = bbox["dimensions"] + max_dim = max(dims) + min_dim = min(dims) + + # 如果产品非常扁平,可能需要水平分型面 + if max_dim / min_dim > 5: + # 尝试添加垂直分型面 + vertical_plane = gp_Pln(gp_Pnt(center[0], center[1], center[2]), gp_Dir(1, 0, 0)) + try: + vertical_surface = BRepBuilderAPI_MakeFace(vertical_plane).Face() + additional_surfaces.append({ + "surface": vertical_surface, + "direction": [1, 0, 0], + "reason": "产品扁平,需要垂直分型" + }) + except: + pass + + return { + "primary_surface": parting_surface, + "primary_line": parting_line, + "primary_direction": primary_direction, + "confidence": normal_stats.get("confidence", 0.5), + "additional_surfaces": additional_surfaces, + "surface_count": 1 + len(additional_surfaces) + } + + def _detect_undercut_regions(self, shape: Any, parting_surface: Any) -> List[Dict]: + """ + 检测倒扣区域 + """ + undercut_regions = [] + + try: + # 获取分型面法向量 + surface = BRepAdaptor_Surface(parting_surface) + parting_normal = surface.Plane().Position().Direction() + + # 遍历所有面,检查是否存在倒扣 + explorer = TopExp_Explorer(shape, TopAbs_FACE) + + while explorer.More(): + face = TopoDS_Face(explorer.Current()) + + try: + face_surface = BRepAdaptor_Surface(face) + + if face_surface.GetType() == 0: # Plane + face_normal = face_surface.Plane().Position().Direction() + + # 计算与分型面法向量的夹角 + dot = (face_normal.X() * parting_normal.X() + + face_normal.Y() * parting_normal.Y() + + face_normal.Z() * parting_normal.Z()) + + # 如果夹角大于90度,认为是倒扣面(法线方向与分型面相反) + if dot < -0.7: # 约>135度 + # 获取面的边界框中心 + bbox = Bnd_Box() + brepbndlib_Add(face, bbox) + center = bbox.Center() + + # 检查该区域是否在分型面下方 + if center.Z() < 0: # 简化判断 + undercut_regions.append({ + "type": "negative_draft", + "location": [center.X(), center.Y(), center.Z()], + "severity": abs(dot) + }) + + except Exception as e: + logger.debug(f"倒扣检测失败: {e}") + + explorer.Next() + + logger.info(f"检测到 {len(undercut_regions)} 个倒扣区域") + + except Exception as e: + logger.warning(f"倒扣区域检测异常: {e}") + + return undercut_regions + + def _calculate_parting_line(self, shape: Any, parting_surface: Any) -> List[List[float]]: + """计算真实的分型线""" + try: + section = BRepAlgoAPI_Section(shape, parting_surface) + section.Build() + + if not section.IsDone(): + logger.warning("截面运算未完成") + return self._simple_parting_line(shape) + + # 提取交线点 + edges = [] + explorer = TopExp_Explorer(section.Shape(), TopAbs_EDGE) + + while explorer.More(): + edge = TopoDS_Edge(explorer.Current()) + + try: + curve = BRepAdaptor_Curve(edge) + first_param = curve.FirstParameter() + last_param = curve.LastParameter() + + # 采样点 + num_points = max(10, int((last_param - first_param) / 0.5)) + step = (last_param - first_param) / num_points + + for i in range(num_points + 1): + param = first_param + i * step + point = curve.Value(param) + edges.append([point.X(), point.Y(), point.Z()]) + except: + pass + + explorer.Next() + + if not edges: + return self._simple_parting_line(shape) + + logger.info(f"计算得到 {len(edges)} 个分型线点") + return edges + + except Exception as e: + logger.error(f"分型线计算失败: {e}") + return self._simple_parting_line(shape) + + def _simple_parting_line(self, shape: Any) -> List[List[float]]: + """简化的分型线""" + try: + bbox = Bnd_Box() + brepbndlib_Add(shape, bbox) + xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get() + center_z = (zmin + zmax) / 2 + + return [ + [xmin, ymin, center_z], + [xmax, ymin, center_z], + [xmax, ymax, center_z], + [xmin, ymax, center_z], + [xmin, ymin, center_z] + ] + except: + return [[0, 0, 0], [100, 0, 0], [100, 100, 0], [0, 100, 0], [0, 0, 0]] + + def _smooth_parting_line(self, parting_line: List[List[float]]) -> List[List[float]]: + """ + 分型线平滑处理 - 使用B样条拟合 + """ + if len(parting_line) < 4: + return parting_line + + try: + points = np.array(parting_line) + + # 简化的平滑算法:移动平均 + smoothed = [] + window_size = 3 + + for i in range(len(points)): + start = max(0, i - window_size // 2) + end = min(len(points), i + window_size // 2 + 1) + window = points[start:end] + + if len(window) > 0: + avg = np.mean(window, axis=0) + smoothed.append(avg.tolist()) + + return smoothed + + except Exception as e: + logger.warning(f"分型线平滑失败: {e}") + return parting_line + + def _assess_parting_line_smoothness(self, parting_line: List[List[float]]) -> float: + """评估分型线平滑度""" + if len(parting_line) < 3: + return 0.0 + + try: + points = np.array(parting_line) + + # 计算相邻线段角度变化 + angles = [] + for i in range(1, len(points) - 1): + v1 = points[i] - points[i-1] + v2 = points[i+1] - points[i] + + len1 = np.linalg.norm(v1) + len2 = np.linalg.norm(v2) + + if len1 > 0.001 and len2 > 0.001: + cos_angle = np.dot(v1, v2) / (len1 * len2) + cos_angle = max(-1, min(1, cos_angle)) + angle = np.arccos(cos_angle) + angles.append(np.degrees(angle)) + + if angles: + avg_angle_change = np.mean(angles) + # 角度变化越小越平滑 + smoothness = max(0, 100 - avg_angle_change * 2) + return smoothness + + return 50.0 + + except: + return 50.0 + + def _apply_shrinkage_compensation(self, shape: Any) -> Any: + """应用收缩率补偿(铝泡沫版本)""" + # 铝泡沫收缩率通常较大 + scale_factor = 1.0 + self.shrinkage_rate + + trsf = gp_Trsf() + trsf.SetScale(gp_Pnt(0, 0, 0), scale_factor) + + try: + scaled_shape = BRepBuilderAPI_Transform(shape, trsf, True).Shape() + logger.info(f"收缩率补偿应用: {self.shrinkage_rate*100:.2f}%") + return scaled_shape + except Exception as e: + logger.error(f"收缩补偿失败: {e}") + return shape + + def _apply_draft_angles(self, shape: Any, parting_surface: Any) -> Any: + """应用拔模角(改进版)""" + # 获取分型面法向量作为拔模方向 + try: + surface = BRepAdaptor_Surface(parting_surface) + draft_direction = surface.Plane().Position().Direction() + + logger.info(f"应用拔模角: {self.draft_angle}°, 方向: ({draft_direction.X():.3f}, {draft_direction.Y():.3f}, {draft_direction.Z():.3f})") + + # 注意:完整的拔模实现需要更复杂的 BRepOffsetAPI_DraftAngle + # 这里简化处理,返回原始形状 + return shape + + except Exception as e: + logger.warning(f"拔模角处理失败: {e}") + return shape + + def _split_cavity_core(self, shape: Any, parting_surface: Any) -> Tuple[Any, Any]: + """分离型腔和型芯(优化版)""" + try: + # 获取边界框 + bbox = Bnd_Box() + brepbndlib_Add(shape, bbox) + xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get() + + # 计算模具块尺寸 + margin = 25 # 铝泡沫模具需要更大余量 + mold_xmin = xmin - margin + mold_ymin = ymin - margin + mold_zmin = zmin - margin + mold_xmax = xmax + margin + mold_ymax = ymax + margin + mold_zmax = zmax + margin + + # 创建模具块 + mold_block = BRepPrimAPI_MakeBox( + gp_Pnt(mold_xmin, mold_ymin, mold_zmin), + gp_Pnt(mold_xmax, mold_ymax, mold_zmax) + ).Shape() + + # 型腔 = 模具块 - 产品 + cavity_operation = BRepAlgoAPI_Cut(mold_block, shape) + if cavity_operation.IsDone(): + cavity = cavity_operation.Shape() + logger.info("型腔生成成功") + else: + logger.warning("型腔布尔运算失败") + cavity = mold_block + + # 型芯 = 产品形状 + core = shape + + return cavity, core + + except Exception as e: + logger.error(f"型腔分离失败: {e}") + return shape, shape + + def _generate_mold_block(self, cavity: Any, analysis: Dict) -> Any: + """生成完整的模具块(包含A/B板结构)""" + try: + bbox = analysis["bounding_box"] + dims = bbox["dimensions"] + + # 模具总尺寸 + margin = 30 + length = dims[0] + 2 * margin + width = dims[1] + 2 * margin + height = dims[2] + margin + 80 # 增加模架高度 + + # 创建模具块 + mold_block = BRepPrimAPI_MakeBox( + gp_Pnt(-length/2, -width/2, -80), + gp_Pnt(length/2, width/2, height) + ).Shape() + + logger.info(f"模具块生成: {length}x{width}x{height} mm") + return mold_block + + except Exception as e: + logger.error(f"模具块生成失败: {e}") + return cavity + + def _extract_shape_geometry(self, shape: Any, shape_type: str) -> Dict[str, Any]: + """提取形状几何数据""" + try: + mesh = BRepMesh_IncrementalMesh(shape, 0.1) + mesh.Perform() + + vertices = [] + faces = [] + vertex_index = 0 + + explorer = TopExp_Explorer(shape, TopAbs_FACE) + + while explorer.More(): + face = TopoDS_Face(explorer.Current()) + location = TopLoc_Location() + triangulation = BRep_Tool.Triangulation(face, location) + + if triangulation: + nb_nodes = triangulation.NbNodes() + for i in range(1, nb_nodes + 1): + node = triangulation.Node(i) + transformed = node.Transformed(location.Transformation()) + vertices.extend([ + float(transformed.X()), + float(transformed.Y()), + float(transformed.Z()) + ]) + + nb_triangles = triangulation.NbTriangles() + for i in range(1, nb_triangles + 1): + triangle = triangulation.Triangle(i) + idx1 = triangle.Value(1) + vertex_index - 1 + idx2 = triangle.Value(2) + vertex_index - 1 + idx3 = triangle.Value(3) + vertex_index - 1 + faces.extend([int(idx1), int(idx2), int(idx3)]) + + vertex_index += nb_nodes + + explorer.Next() + + return { + "type": shape_type, + "vertices": vertices, + "faces": faces, + "vertex_count": len(vertices) // 3, + "face_count": len(faces) // 3 + } + + except Exception as e: + logger.error(f"{shape_type}几何提取失败: {e}") + return { + "type": shape_type, + "vertices": [], + "faces": [], + "vertex_count": 0, + "face_count": 0 + } + + def _extract_parting_surface_geometry(self, surface: Any) -> Dict[str, Any]: + """提取分型面几何数据""" + try: + adaptor = BRepAdaptor_Surface(surface) + normal = adaptor.Plane().Position().Direction() + + return { + "type": "plane", + "normal": [normal.X(), normal.Y(), normal.Z()], + "origin": [0, 0, 0], + "bounds": {"u_range": [-200, 200], "v_range": [-200, 200]} + } + except: + return { + "type": "plane", + "normal": [0, 0, 1], + "origin": [0, 0, 0], + "bounds": {"u_range": [-200, 200], "v_range": [-200, 200]} + } + + def _create_parting_surface_from_ai(self, ai_result: Dict, analysis: Dict) -> Dict: + """从 AI 结果创建分型面""" + origin = ai_result.get("origin", [0, 0, 0]) + normal = ai_result.get("normal", [0, 0, 1]) + + parting_plane = gp_Pln( + gp_Pnt(origin[0], origin[1], origin[2]), + gp_Dir(normal[0], normal[1], normal[2]) + ) + + try: + parting_surface = BRepBuilderAPI_MakeFace(parting_plane).Face() + except: + parting_plane = gp_Pln(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)) + parting_surface = BRepBuilderAPI_MakeFace(parting_plane).Face() + + parting_line = self._calculate_parting_line( + analysis.get("shape", None), + parting_surface + ) + + return { + "primary_surface": parting_surface, + "primary_line": parting_line, + "primary_direction": normal, + "confidence": ai_result.get("confidence", 0.8), + "additional_surfaces": [], + "surface_count": 1 + } + + # ==================== 辅助方法 ==================== + + def _calculate_mold_size(self, analysis: Dict) -> Dict[str, float]: + """估算模具尺寸""" + dims = analysis["bounding_box"]["dimensions"] + margin = 30 + + return { + "length": dims[0] + 2 * margin, + "width": dims[1] + 2 * margin, + "height": dims[2] + margin + 80, + "margin": margin + } + + def _calculate_clamping_force(self, analysis: Dict) -> str: + """估算锁模力""" + volume_cm3 = analysis.get("volume", 0) / 1000 + + if volume_cm3 < 10: + return "30-50 吨" + elif volume_cm3 < 50: + return "50-100 吨" + elif volume_cm3 < 200: + return "100-200 吨" + else: + return "200+ 吨" + + def _calculate_product_weight(self, analysis: Dict) -> str: + """计算产品重量""" + volume_cm3 = analysis.get("volume", 0) / 1000 + weight_g = volume_cm3 * self.material_density + return f"{weight_g:.2f} g" + + def _estimate_wall_thickness(self, analysis: Dict) -> str: + """估算壁厚范围""" + volume = analysis.get("volume", 0) + surface_area = analysis.get("surface_area", 0) + + if surface_area > 0 and volume > 0: + avg_thickness = (volume / surface_area) * 0.6 + return f"{avg_thickness * 0.7:.2f} - {avg_thickness * 1.3:.2f} mm" + + return "10.0 - 30.0 mm (铝泡沫典型)" + + def _calculate_complexity_score(self, analysis: Dict) -> float: + """计算复杂度评分""" + volume = analysis.get("volume", 0) + surface_area = analysis.get("surface_area", 0) + + if surface_area > 0 and volume > 0: + thickness_ratio = (volume / surface_area) * 0.6 + complexity = min(thickness_ratio / 5.0, 10.0) + return round(complexity, 1) + + return 5.0 + + def _estimate_cycle_time(self, analysis: Dict) -> str: + """估算成型周期""" + volume_cm3 = analysis.get("volume", 0) / 1000 + + if volume_cm3 < 10: + return "60-90 秒" + elif volume_cm3 < 50: + return "90-120 秒" + elif volume_cm3 < 200: + return "120-180 秒" + else: + return "180-300 秒" + + def _identify_sink_mark_risk(self, analysis: Dict) -> str: + """识别缩痕风险""" + return "中 - 铝泡沫壁厚大,需控制发泡均匀性" + + def _assess_warpage_risk(self, analysis: Dict) -> str: + """评估翘曲风险""" + bbox = analysis.get("bounding_box", {}).get("dimensions", [1, 1, 1]) + aspect_ratio = max(bbox) / min(bbox) + + if aspect_ratio > 5: + return "高 - 建议增加加强筋" + elif aspect_ratio > 3: + return "中 - 需优化冷却" + else: + return "低" + + def _assess_venting_requirement(self, analysis: Dict) -> str: + """评估排气需求""" + volume = analysis.get("volume", 0) + + if volume > 50000000: # > 50 cm³ + return "高 - 需要加强排气系统" + elif volume > 10000000: # > 10 cm³ + return "中 - 建议标准排气" + else: + return "低 - 常规排气即可" + + def _get_inertia_matrix(self, props: GProp_GProps) -> List[List[float]]: + """获取惯性矩阵""" + inertia = props.MatrixOfInertia() + return [ + [inertia.Value(1, 1), inertia.Value(1, 2), inertia.Value(1, 3)], + [inertia.Value(2, 1), inertia.Value(2, 2), inertia.Value(2, 3)], + [inertia.Value(3, 1), inertia.Value(3, 2), inertia.Value(3, 3)] + ] + + def _calculate_parting_line_length(self, parting_line: List) -> float: + """计算分型线长度""" + if not parting_line or len(parting_line) < 2: + return 0.0 + + total_length = 0.0 + for i in range(1, len(parting_line)): + p1 = np.array(parting_line[i-1]) + p2 = np.array(parting_line[i]) + total_length += np.linalg.norm(p2 - p1) + + return total_length + + def set_ai_model(self, parting_detector: Any = None, draft_analyzer: Any = None): + """设置 AI 模型接口""" + self.ai_parting_detector = parting_detector + self.ai_draft_analyzer = draft_analyzer + logger.info("AI 模型接口已设置") diff --git a/src/core/mold_quality_inspector.py b/src/core/mold_quality_inspector.py new file mode 100644 index 0000000..6b14636 --- /dev/null +++ b/src/core/mold_quality_inspector.py @@ -0,0 +1,422 @@ +""" +铝泡沫模具质量检测模块 + +提供分模面质量检测、模具结构合理性评估、生产可行性分析等功能 +""" + +from typing import Dict, List, Any, Tuple +import numpy as np +from OCC.Core.BRep import BRep_Tool +from OCC.Core.BRepMesh import BRepMesh_IncrementalMesh +from OCC.Core.TopExp import TopExp_Explorer +from OCC.Core.TopAbs import TopAbs_FACE, TopAbs_EDGE +from OCC.Core.BRepAdaptor import BRepAdaptor_Surface, BRepAdaptor_Curve +from OCC.Core.Bnd import Bnd_Box +from OCC.Core.BRepBndLib import brepbndlib_Add +from OCC.Core.gp import gp_Dir + +from utils.logger import get_logger + +logger = get_logger(__name__) + + +class AluminumFoamMoldQualityInspector: + """铝泡沫模具质量检测器""" + + def __init__(self): + self.quality_threshold = { + "smoothness_score": 80.0, + "continuity_score": 95.0, + "structure_score": 90.0 + } + + def inspect_mold(self, cavity_data: Dict, params: Dict) -> Dict[str, Any]: + """ + 完整的模具质量检测 + + Args: + cavity_data: 模具型腔数据 + params: 分模参数 + + Returns: + 质量检测报告 + """ + logger.info("开始模具质量检测...") + + report = { + "surface_quality": self.inspect_surface_quality(cavity_data), + "structure_quality": self.inspect_structure_quality(cavity_data, params), + "feasibility": self.assess_production_feasibility(cavity_data, params), + "overall_score": 0.0, + "passed": False, + "warnings": [], + "recommendations": [] + } + + # 计算综合评分 + scores = [ + report["surface_quality"]["overall_score"], + report["structure_quality"]["overall_score"], + report["feasibility"]["score"] + ] + report["overall_score"] = sum(scores) / len(scores) + report["passed"] = report["overall_score"] >= 80.0 + + logger.info(f"质量检测完成,综合评分: {report['overall_score']:.1f}%") + + return report + + def inspect_surface_quality(self, cavity_data: Dict) -> Dict[str, Any]: + """ + 检测分模面质量 + + 检测项目: + - 平滑度:曲率分析 + - 连续性:边界检查 + - 完整性:破面检测 + """ + parting_line = cavity_data.get("parting_line", []) + parting_surface = cavity_data.get("parting_surface") + + # 1. 平滑度检测 + smoothness = self._check_smoothness(parting_line) + + # 2. 连续性检测 + continuity = self._check_continuity(parting_line) + + # 3. 完整性检测 + completeness = self._check_completeness(cavity_data) + + overall = (smoothness["score"] * 0.4 + + continuity["score"] * 0.3 + + completeness["score"] * 0.3) + + return { + "smoothness": smoothness, + "continuity": continuity, + "completeness": completeness, + "overall_score": overall, + "passed": overall >= self.quality_threshold["smoothness_score"] + } + + def _check_smoothness(self, parting_line: List) -> Dict[str, Any]: + """检查分型线平滑度""" + if len(parting_line) < 3: + return {"score": 50.0, "issues": ["分型线点数不足"]} + + try: + points = np.array(parting_line) + + # 计算相邻线段角度变化 + angle_changes = [] + for i in range(1, len(points) - 1): + v1 = points[i] - points[i-1] + v2 = points[i+1] - points[i] + + len1, len2 = np.linalg.norm(v1), np.linalg.norm(v2) + if len1 > 0.001 and len2 > 0.001: + cos_angle = np.clip(np.dot(v1, v2) / (len1 * len2), -1, 1) + angle = np.degrees(np.arccos(cos_angle)) + angle_changes.append(angle) + + if not angle_changes: + return {"score": 70.0, "issues": []} + + # 计算角度变化统计 + max_angle = max(angle_changes) + avg_angle = np.mean(angle_changes) + + # 评分:角度变化越小越好 + score = max(0, 100 - avg_angle * 2 - max_angle * 0.5) + + issues = [] + if max_angle > 30: + issues.append(f"存在尖角,最大角度变化: {max_angle:.1f}°") + if avg_angle > 15: + issues.append(f"分型线不够平滑,平均角度变化: {avg_angle:.1f}°") + + return {"score": score, "issues": issues, "max_angle": max_angle, "avg_angle": avg_angle} + + except Exception as e: + logger.warning(f"平滑度检测失败: {e}") + return {"score": 50.0, "issues": ["检测过程出错"]} + + def _check_continuity(self, parting_line: List) -> Dict[str, Any]: + """检查分型线连续性""" + if len(parting_line) < 2: + return {"score": 0.0, "issues": ["分型线不完整"]} + + try: + # 检查是否有明显的间隙 + points = np.array(parting_line) + gaps = [] + + for i in range(1, len(points)): + gap = np.linalg.norm(points[i] - points[i-1]) + if gap > 10.0: # 10mm 以上认为有间隙 + gaps.append(gap) + + # 评分 + if not gaps: + score = 100.0 + issues = [] + elif len(gaps) == 1 and max(gaps) < 20: + score = 80.0 + issues = [f"存在轻微间隙: {max(gaps):.1f}mm"] + else: + score = max(0, 100 - len(gaps) * 20) + issues = [f"存在 {len(gaps)} 处间隙"] + + return {"score": score, "issues": issues, "gap_count": len(gaps)} + + except Exception as e: + logger.warning(f"连续性检测失败: {e}") + return {"score": 50.0, "issues": ["检测过程出错"]} + + def _check_completeness(self, cavity_data: Dict) -> Dict[str, Any]: + """检查分模完整性""" + issues = [] + + # 检查必要的组件是否存在 + required_keys = ["cavity", "core", "parting_surface", "parting_line"] + missing = [k for k in required_keys if k not in cavity_data] + + if missing: + issues.append(f"缺少组件: {', '.join(missing)}") + return {"score": 0.0, "issues": issues} + + # 检查分型线点数 + parting_line = cavity_data.get("parting_line", []) + if len(parting_line) < 4: + issues.append("分型线点数不足") + score = len(parting_line) * 20 + else: + score = 100.0 + + return {"score": score, "issues": issues} + + def inspect_structure_quality(self, cavity_data: Dict, params: Dict) -> Dict[str, Any]: + """ + 检测模具结构合理性 + + 检测项目: + - 模具尺寸 + - 壁厚 + - 拔模角 + - 倒扣处理 + """ + analysis = cavity_data.get("analysis", {}) + bbox = analysis.get("bounding_box", {}).get("dimensions", [0, 0, 0]) + + issues = [] + recommendations = [] + + # 1. 模具尺寸检查 + mold_size = cavity_data.get("mold_block") + if mold_size: + # 检查尺寸是否足够 + min_dimension = min(bbox) + if min_dimension < 20: + issues.append("产品尺寸过小,可能影响模具强度") + recommendations.append("建议增加产品尺寸或使用嵌件") + + # 2. 拔模角检查 + draft_angle = params.get("draft_angle", 0) + if draft_angle < 2.0: + issues.append("拔模角偏小,可能导致脱模困难") + recommendations.append("建议增大拔模角到 2-5°") + + # 3. 倒扣区域检查 + undercut_regions = cavity_data.get("undercut_regions", []) + if undercut_regions: + issues.append(f"存在 {len(undercut_regions)} 个倒扣区域") + recommendations.append("建议添加滑块或斜顶机构") + + # 4. 铝泡沫特殊检查 + foam_material = params.get("foam_material", "") + if foam_material: + # 检查排气系统需求 + volume = analysis.get("volume", 0) + if volume > 50000000: # > 50 cm³ + issues.append("大型铝泡沫产品,需要加强排气系统") + recommendations.append("建议增加排气槽或排气针") + + # 评分 + issue_count = len(issues) + score = max(0, 100 - issue_count * 15) + + return { + "score": score, + "issues": issues, + "recommendations": recommendations, + "overall_score": score, + "passed": score >= self.quality_threshold["structure_score"] + } + + def assess_production_feasibility(self, cavity_data: Dict, params: Dict) -> Dict[str, Any]: + """ + 评估生产可行性 + + 评估项目: + - 注塑压力 + - 锁模力 + - 成型周期 + - 材料利用率 + """ + analysis = cavity_data.get("analysis", {}) + + # 计算投影面积 (mm²) + bbox = analysis.get("bounding_box", {}).get("dimensions", [0, 0, 0]) + projected_area = bbox[0] * bbox[1] # X * Y + + # 体积 (mm³) + volume = analysis.get("volume", 0) + volume_cm3 = volume / 1000 + + # 1. 注塑压力估算 (MPa) + injection_pressure = 30 + projected_area / 1000 # 简化估算 + + # 2. 锁模力估算 (吨) + # 铝泡沫需要较低的压力 + clamping_force_ton = projected_area * 0.0015 # 简化估算 + + # 3. 成型周期估算 (秒) + # 铝泡沫成型周期较长 + if volume_cm3 < 10: + cycle_time = 60 + elif volume_cm3 < 50: + cycle_time = 90 + elif volume_cm3 < 200: + cycle_time = 120 + else: + cycle_time = 180 + + # 4. 材料利用率 + material_utilization = min(95, 85 + volume_cm3 / 10) + + # 评估结果 + feasibility_items = [] + + if injection_pressure < 100: + feasibility_items.append({ + "item": "注塑压力", + "value": f"{injection_pressure:.1f} MPa", + "status": "ok", + "message": "压力在设备范围内" + }) + else: + feasibility_items.append({ + "item": "注塑压力", + "value": f"{injection_pressure:.1f} MPa", + "status": "warning", + "message": "压力较高,需要高压设备" + }) + + if clamping_force_ton < 300: + feasibility_items.append({ + "item": "锁模力", + "value": f"{clamping_force_ton:.1f} 吨", + "status": "ok", + "message": "锁模力在设备范围内" + }) + else: + feasibility_items.append({ + "item": "锁模力", + "value": f"{clamping_force_ton:.1f} 吨", + "status": "warning", + "message": "需要大型注塑机" + }) + + feasibility_items.append({ + "item": "成型周期", + "value": f"{cycle_time} 秒", + "status": "ok", + "message": "周期正常" + }) + + feasibility_items.append({ + "item": "材料利用率", + "value": f"{material_utilization:.1f}%", + "status": "ok", + "message": "材料利用率良好" if material_utilization > 80 else "材料利用率偏低" + }) + + # 综合评分 + ok_count = sum(1 for item in feasibility_items if item["status"] == "ok") + score = (ok_count / len(feasibility_items)) * 100 + + return { + "items": feasibility_items, + "score": score, + "projected_area": f"{projected_area:.0f} mm²", + "volume": f"{volume_cm3:.1f} cm³", + "injection_pressure": f"{injection_pressure:.1f} MPa", + "clamping_force": f"{clamping_force_ton:.1f} 吨", + "cycle_time": f"{cycle_time} 秒", + "material_utilization": f"{material_utilization:.1f}%", + "passed": score >= 75.0 + } + + def generate_quality_report(self, cavity_data: Dict, params: Dict) -> str: + """ + 生成质量检测报告文本 + + Returns: + Markdown 格式的报告文本 + """ + report = self.inspect_mold(cavity_data, params) + + lines = [ + "# 铝泡沫模具质量检测报告", + "", + f"**综合评分**: {report['overall_score']:.1f}%", + f"**检测结果**: {'✅ 通过' if report['passed'] else '❌ 未通过'}", + "", + "## 一、分模面质量", + "", + f"- 平滑度: {report['surface_quality']['smoothness']['score']:.1f}分", + f"- 连续性: {report['surface_quality']['continuity']['score']:.1f}分", + f"- 完整性: {report['surface_quality']['completeness']['score']:.1f}分", + "", + ] + + # 添加问题列表 + if report["surface_quality"]["smoothness"].get("issues"): + lines.append("**发现的问题**:") + for issue in report["surface_quality"]["smoothness"]["issues"]: + lines.append(f"- {issue}") + lines.append("") + + # 添加结构质量 + lines.extend([ + "## 二、模具结构质量", + "", + f"- 评分: {report['structure_quality']['score']:.1f}分", + "", + ]) + + if report["structure_quality"].get("issues"): + lines.append("**结构问题**:") + for issue in report["structure_quality"]["issues"]: + lines.append(f"- {issue}") + lines.append("") + + if report["structure_quality"].get("recommendations"): + lines.append("**改进建议**:") + for rec in report["structure_quality"]["recommendations"]: + lines.append(f"- {rec}") + lines.append("") + + # 添加生产可行性 + lines.extend([ + "## 三、生产可行性", + "", + ]) + + for item in report["feasibility"]["items"]: + status_icon = "✅" if item["status"] == "ok" else "⚠️" + lines.append(f"{status_icon} **{item['item']}**: {item['value']} - {item['message']}") + + lines.append("") + + return "\n".join(lines) diff --git a/static/style.css b/static/style.css index 0e6baed..f0bd374 100644 --- a/static/style.css +++ b/static/style.css @@ -473,8 +473,131 @@ body { } .upload-zone.dragover { - border-color: var(--primary-500); - background: var(--primary-100); + background: #e3f2fd; + border-color: #1976d2; +} + +.material-panel { + background: #fafafa; + border-radius: 8px; + padding: 16px; + margin-top: 16px; + border: 1px solid #e0e0e0; +} + +.panel-header { + margin-bottom: 16px; +} + +.panel-title { + font-size: 16px; + font-weight: 600; + color: #333; +} + +.form-group { + margin-bottom: 16px; +} + +.form-label { + display: block; + font-size: 14px; + font-weight: 500; + color: #555; + margin-bottom: 8px; +} + +.form-select { + width: 100%; + padding: 10px 12px; + font-size: 14px; + border: 1px solid #ddd; + border-radius: 6px; + background: white; + color: #333; + cursor: pointer; +} + +.form-select:focus { + outline: none; + border-color: #1976d2; + box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.1); +} + +optgroup { + font-weight: 600; + color: #333; +} + +.foam-params { + margin-top: 16px; + padding: 16px; + background: #fff3e0; + border-radius: 6px; + border: 1px solid #ffb74d; +} + +.param-section { + margin-bottom: 12px; +} + +.param-title { + display: block; + font-size: 14px; + font-weight: 600; + color: #e65100; + margin-bottom: 12px; +} + +.form-row { + display: flex; + gap: 16px; + margin-bottom: 12px; +} + +.form-row .form-group { + flex: 1; +} + +.form-range { + width: 100%; + height: 6px; + border-radius: 3px; + background: #ddd; + outline: none; + -webkit-appearance: none; +} + +.form-range::-webkit-slider-thumb { + -webkit-appearance: none; + width: 16px; + height: 16px; + border-radius: 50%; + background: #1976d2; + cursor: pointer; +} + +.range-value { + display: inline-block; + margin-top: 4px; + font-size: 13px; + color: #666; + font-weight: 500; +} + +.btn-clear { + background: none; + border: none; + color: #999; + font-size: 20px; + cursor: pointer; + padding: 4px 8px; + border-radius: 4px; +} + +.btn-clear:hover { + background: #f5f5f5; + color: #f44336; } .upload-icon { diff --git a/static/vue-app.js b/static/vue-app.js index 2454581..27e0e7e 100644 --- a/static/vue-app.js +++ b/static/vue-app.js @@ -762,6 +762,13 @@ const MoldInsightView = { const router = useRouter(); const state = reactive({ selectedFile: null, + selectedMaterial: 'ABS', + moldParams: { + draftAngle: 2.0, + shrinkageRate: 0.5, + partingPrecision: 0.1, + cavityMatch: 95 + }, uploading: false, error: "", currentTask: null, @@ -834,6 +841,7 @@ const MoldInsightView = { const formData = new FormData(); formData.append("file", state.selectedFile); + formData.append("material", state.selectedMaterial); try { const res = await fetch("/api/upload", { @@ -944,6 +952,72 @@ const MoldInsightView = {
{{ state.selectedFile.name }} {{ formatFileSize(state.selectedFile.size) }} + +
+ + +
+
+ 📦 材料与参数设置 +
+ + +
+ + +
+ + +
+
+ ⚙️ 铝泡沫专用参数 + +
+
+ + + {{ state.moldParams.draftAngle }}° +
+ +
+ + + {{ state.moldParams.shrinkageRate }}% +
+
+ +
+
+ + + {{ state.moldParams.partingPrecision }} mm +
+ +
+ + + {{ state.moldParams.cavityMatch }}% +
+
+
+
{{ state.error }}
@@ -1091,7 +1165,7 @@ const ResultView = { return priorityMap[priority] || priority; }; - return { state, formatFileSize, formatDateTime, formatNumber, getPriorityText }; + return { state, formatFileSize, formatDateTime, formatNumber, getPriorityText, isFoamMaterial }; }, template: `