Files
geMoldInsight/src/services/calculation_service.py
T
2026-04-13 09:43:24 +08:00

241 lines
9.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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