Files
geMoldInsight/src/services/calculation_service.py
T

241 lines
9.5 KiB
Python
Raw Normal View History

2026-04-13 09:43:24 +08:00
# services/calculation_service.py
"""模具工程参数计算服务 — 从 process_file_core 中抽取的纯计算逻辑"""
from typing import Dict, Any, List, Optional
from datetime import datetime
from pathlib import Path
class CalculationService:
"""将 process_file_core 中的工程计算逻辑抽取为独立服务,方便单测和复用"""
# ─── 基础计算 ───
@staticmethod
def calculate_product_weight(volume_mm3: float, density: float) -> float:
"""计算产品重量(克)"""
volume_cm3 = volume_mm3 / 1000
return volume_cm3 * density
@staticmethod
def calculate_projected_area(bbox_dims: List[float]) -> float:
"""计算投影面积(cm²),取 X、Y 方向"""
if len(bbox_dims) >= 2:
return (bbox_dims[0] * bbox_dims[1]) / 100
return 0.0
@staticmethod
def calculate_cavity_count(product_weight_g: float, projected_area_cm2: float) -> int:
"""
计算最优型腔数量
基于产品重量和投影面积:
- 小产品(< 50g)可以多型腔
- 大产品(> 1000g)通常单型腔
"""
if product_weight_g < 50:
cavity_count = 8
elif product_weight_g < 100:
cavity_count = 4
elif product_weight_g < 300:
cavity_count = 2
else:
cavity_count = 1
# 根据投影面积调整
if projected_area_cm2 > 400:
cavity_count = 1
elif projected_area_cm2 > 200 and cavity_count > 2:
cavity_count = 2
return cavity_count
@staticmethod
def calculate_clamping_force(
projected_area_cm2: float,
cavity_count: int,
runner_ratio: float = 0.20,
injection_pressure: float = 700,
) -> int:
"""
计算所需夹紧力(吨)
runner_ratio: 流道系统占型腔投影面积比(0.15-0.25)
injection_pressure: 注塑压力 kg/cm²
"""
total_projected_area = projected_area_cm2 * cavity_count * (1 + runner_ratio)
clamping_force_ton = int(total_projected_area * injection_pressure / 1000)
return max(50, min(clamping_force_ton, 3000))
@staticmethod
def calculate_wall_thickness(volume_mm3: float, surface_area_mm2: float) -> Dict[str, float]:
"""计算壁厚范围"""
if surface_area_mm2 > 0 and volume_mm3 > 0:
avg = (volume_mm3 / surface_area_mm2) * 0.6
return {
"avg_thickness_mm": avg,
"wall_thickness_min": avg * 0.7,
"wall_thickness_max": avg * 1.3,
}
return {
"avg_thickness_mm": 2.5,
"wall_thickness_min": 2.0,
"wall_thickness_max": 3.0,
}
@staticmethod
def calculate_complexity(avg_thickness_mm: float) -> float:
"""计算复杂度评分(0~1)"""
return min((avg_thickness_mm / 5.0), 1.0) if avg_thickness_mm > 0 else 0.5
@staticmethod
def calculate_mold_size(
bbox_dims: List[float], cavity_count: int,
cavity_spacing: float = 30, edge_margin: float = 50,
) -> Dict[str, float]:
"""计算模具尺寸(长×宽×高),单位 mm"""
dim_x = max(bbox_dims[0] if len(bbox_dims) > 0 else 120, 120)
dim_y = max(bbox_dims[1] if len(bbox_dims) > 1 else 100, 100)
dim_z = max(bbox_dims[2] if len(bbox_dims) > 2 else 60, 60)
if cavity_count == 1:
length = dim_x + 2 * edge_margin
width = dim_y + 2 * edge_margin
elif cavity_count == 2:
length = 2 * dim_x + cavity_spacing + 2 * edge_margin
width = dim_y + 2 * edge_margin
elif cavity_count == 4:
length = 2 * dim_x + cavity_spacing + 2 * edge_margin
width = 2 * dim_y + cavity_spacing + 2 * edge_margin
else: # 8 型腔: 2x4
length = 4 * dim_x + 3 * cavity_spacing + 2 * edge_margin
width = 2 * dim_y + cavity_spacing + 2 * edge_margin
height = dim_z + 80 # 包含冷却系统
return {"length": length, "width": width, "height": height}
@staticmethod
def calculate_parting_line_length(bbox_dims: List[float], cavity_count: int) -> float:
"""计算分型线长度(mm)"""
if len(bbox_dims) >= 2:
return 2 * (bbox_dims[0] + bbox_dims[1]) * cavity_count
return 0.0
@staticmethod
def calculate_cycle_time(
wall_thickness_max: float, volume_cm3: float, cavity_count: int,
) -> int:
"""
估算成型周期(秒)
周期 = 冷却时间 + 注塑时间 + 顶出时间 + 开合模时间
"""
cooling_time = (wall_thickness_max ** 2) * 4
injection_time = max(3, volume_cm3 / 100)
ejection_time = 3
cycle_time = cooling_time + injection_time + ejection_time + 5
# 多型腔需要更长冷却时间
if cavity_count > 1:
cycle_time = cycle_time * (1 + 0.1 * (cavity_count - 1))
return int(cycle_time)
# ─── 组装方法 ───
@classmethod
def build_detailed_cavity_json(
cls,
geometry_data: Dict[str, Any],
material: Dict[str, Any],
file_path: str,
cavity_mesh_data: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
"""
组装完整的 detailed_cavity_json(整合以上所有计算结果)
Args:
geometry_data: STP 解析得到的几何数据
material: MaterialService.get_material() 返回的材料属性字典
file_path: STP 文件路径
cavity_mesh_data: 型腔网格数据(可选)
"""
volume_mm3 = geometry_data.get("volume", 0)
surface_area_mm2 = geometry_data.get("surface_area", 0)
bbox = geometry_data.get("bounding_box", {})
bbox_dims = bbox.get("dimensions", [0, 0, 0])
material_density = material["density"]
shrinkage_rate = material["shrinkage"]
# 各项计算
volume_cm3 = volume_mm3 / 1000
product_weight_g = cls.calculate_product_weight(volume_mm3, material_density)
projected_area_cm2 = cls.calculate_projected_area(bbox_dims)
cavity_count = cls.calculate_cavity_count(product_weight_g, projected_area_cm2)
clamping_force_ton = cls.calculate_clamping_force(projected_area_cm2, cavity_count)
wall = cls.calculate_wall_thickness(volume_mm3, surface_area_mm2)
complexity_score = cls.calculate_complexity(wall["avg_thickness_mm"])
mold_size = cls.calculate_mold_size(bbox_dims, cavity_count)
parting_line_length = cls.calculate_parting_line_length(bbox_dims, cavity_count)
cycle_time = cls.calculate_cycle_time(wall["wall_thickness_max"], volume_cm3, cavity_count)
injection_pressure = 700 # kg/cm²
detailed_cavity_json = {
"metadata": {
"file_name": Path(file_path).name,
"analysis_date": datetime.now().isoformat(),
"shrinkage_rate": shrinkage_rate,
"draft_angle": 2.0,
"selected_material": material["name"],
},
"product_analysis": {
"volume": volume_mm3,
"surface_area": surface_area_mm2,
"bounding_box": bbox,
},
"manufacturing_info": {
"recommended_material": material["name"],
"material_density": f"{material_density} g/cm³",
"estimated_clamping_force": f"{clamping_force_ton} 吨",
"estimated_mold_size": {
"length": int(mold_size["length"]),
"width": int(mold_size["width"]),
"height": int(mold_size["height"]),
},
"mold_material": "铝合金7075" if clamping_force_ton < 200 else "P20钢材",
"mold_hardness": "HB 150-170" if clamping_force_ton < 200 else "HRC 28-32",
"surface_finish": "Ra 0.8 μm",
"parting_line_length": f"{parting_line_length:.2f} mm",
"estimated_cycle_time": f"{cycle_time} 秒",
"injection_pressure": f"{injection_pressure} kg/cm²",
},
"mold_cavities": {
"cavity_count": cavity_count,
},
}
# 合并型腔网格数据
if cavity_mesh_data and "mold_cavities" in cavity_mesh_data:
mold_cavities = cavity_mesh_data["mold_cavities"]
for key in ("cavity", "core", "parting_surface"):
if key in mold_cavities:
detailed_cavity_json["mold_cavities"][key] = mold_cavities[key]
# 添加型腔关键信息
detailed_cavity_json["mold_cavities"]["cavity_key_info"] = {
"geometric_characteristics": {
"product_weight": f"{product_weight_g:.2f} g",
"wall_thickness_range": f"{wall['wall_thickness_min']:.2f} - {wall['wall_thickness_max']:.2f} mm",
"complexity_score": round(complexity_score, 2),
"product_volume": f"{volume_cm3:.2f} cm³",
"projected_area": f"{projected_area_cm2:.2f} cm²",
},
"quality_considerations": {
"potential_weld_lines": "center" if cavity_count > 1 else "minimal",
"sink_mark_areas": "thick_sections" if wall["wall_thickness_max"] > 4 else "minimal",
"warpage_risk": "medium" if wall["wall_thickness_max"] > 5 else "low",
},
}
return detailed_cavity_json