# api/machining_router.py """CAM / 加工仿真类接口(批次 3 自 advanced_router 拆分,D1)。 加工计算为纯 Python 重计算(非 OCC),统一经 asyncio.to_thread 投放线程池执行,不阻塞事件循环。 """ import asyncio from typing import Any, Dict, List, Optional from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, Field from shared.services.auth_service import get_current_active_user from shared.models.identity import User from moldinsight.api.core_modules import get_core_module from moldinsight.api.design_router import BBox3D router = APIRouter() # ---- 请求模型 ---- class ToolSpec(BaseModel): diameter: float = 10.0 flute_length: float = 30.0 shank_diameter: float = 10.0 def _cam_cavity_bbox() -> BBox3D: return BBox3D(dimensions=[100.0, 100.0, 50.0], min=[-50.0, -50.0, -25.0], max=[50.0, 50.0, 25.0]) def _cam_stock_bbox() -> BBox3D: return BBox3D(dimensions=[150.0, 150.0, 100.0], min=[-75.0, -75.0, -50.0], max=[75.0, 75.0, 50.0]) class CamDesignRequest(BaseModel): cavity_bbox: BBox3D = Field(default_factory=_cam_cavity_bbox) stock_bbox: BBox3D = Field(default_factory=_cam_stock_bbox) mold_steel: str = "P20" surface_quality: str = "standard" controller: str = "fanuc" class CollisionCheckRequest(BaseModel): toolpath_points: List[List[float]] = Field( default_factory=lambda: [[0, 0, 50], [10, 10, -5], [20, 20, -10]] ) tool: ToolSpec = Field(default_factory=ToolSpec) stock_bbox: BBox3D = Field(default_factory=_cam_cavity_bbox) clamp_positions: Optional[List[List[float]]] = None class ToolpathOptimizeRequest(BaseModel): toolpath_points: List[List[float]] = Field( default_factory=lambda: [[0, 0, 50], [10, 10, -5], [20, 20, -10]] ) cutting_params: Dict[str, Any] = Field(default_factory=lambda: {"feed_rate_mm_min": 500}) stock_bbox: Optional[BBox3D] = None class ElectrodeDesignRequest(BaseModel): undercut_regions: List[Dict[str, Any]] = Field( default_factory=lambda: [{"center": [0, 0, 0], "area": 100, "type": "undercut"}] ) cavity_bbox: BBox3D = Field(default_factory=BBox3D) material: str = "copper" spark_gap: float = 0.05 overburn: float = 0.1 class MachiningSimulateRequest(BaseModel): operations: List[Dict[str, Any]] = Field( default_factory=lambda: [{"strategy": "z_level_roughing", "levels": [{"z": -5}]}] ) stock_bbox: BBox3D = Field(default_factory=_cam_cavity_bbox) resolution: float = 2.0 @router.post("/design-cam") async def design_mold_cam( body: CamDesignRequest, current_user: User = Depends(get_current_active_user), ): cam = get_core_module("mold_cam_designer") if not cam: raise HTTPException(503, "服务不可用:核心模块未加载") result = await asyncio.to_thread( cam.design_mold_cam, cavity_bbox=body.cavity_bbox.model_dump(exclude_none=True), stock_bbox=body.stock_bbox.model_dump(exclude_none=True), mold_steel=body.mold_steel, surface_quality=body.surface_quality, controller=body.controller, ) return {"status": "success", "data": result} @router.post("/check-collision") async def check_toolpath_collision( body: CollisionCheckRequest, current_user: User = Depends(get_current_active_user), ): cd = get_core_module("collision_detector") if not cd: raise HTTPException(503, "服务不可用:核心模块未加载") result = await asyncio.to_thread( cd.check_toolpath_safety, body.toolpath_points, body.tool.model_dump(), body.stock_bbox.model_dump(exclude_none=True), body.clamp_positions, ) return {"status": "success", "data": result} @router.post("/optimize-toolpath") async def optimize_toolpath( body: ToolpathOptimizeRequest, current_user: User = Depends(get_current_active_user), ): to = get_core_module("toolpath_optimizer") if not to: raise HTTPException(503, "服务不可用:核心模块未加载") result = await asyncio.to_thread( to.optimize_toolpath, body.toolpath_points, body.cutting_params, body.stock_bbox.model_dump(exclude_none=True) if body.stock_bbox else None, ) return {"status": "success", "data": result} @router.post("/design-electrodes") async def design_edm_electrodes( body: ElectrodeDesignRequest, current_user: User = Depends(get_current_active_user), ): ed = get_core_module("edm_designer") if not ed: raise HTTPException(503, "服务不可用:核心模块未加载") result = await asyncio.to_thread( ed.design_electrodes, body.undercut_regions, body.cavity_bbox.model_dump(exclude_none=True), body.material, body.spark_gap, body.overburn, ) return {"status": "success", "data": result} @router.post("/simulate-machining") async def simulate_machining( body: MachiningSimulateRequest, current_user: User = Depends(get_current_active_user), ): ms = get_core_module("machining_simulator") if not ms: raise HTTPException(503, "服务不可用:核心模块未加载") result = await asyncio.to_thread( ms.simulate_machining, body.operations, body.stock_bbox.model_dump(exclude_none=True), body.resolution, ) return {"status": "success", "data": result}