x
This commit is contained in:
+45
-174
@@ -28,6 +28,7 @@ from OCC.Core.BRepGProp import brepgprop
|
||||
from models.schemas import create_mold_cavity_data, create_mold_key_info
|
||||
from utils.logger import get_logger
|
||||
from core.base_mold_generator import BaseMoldGenerator
|
||||
from core.side_action_designer import SideActionDesigner
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
@@ -102,6 +103,7 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
||||
self.cavity_count = 1
|
||||
self.parting_precision = 0.1
|
||||
self.cavity_match_rate = 95.0
|
||||
self.side_action_designer = SideActionDesigner()
|
||||
|
||||
def set_foam_material(self, material: str):
|
||||
"""设置铝泡沫材料"""
|
||||
@@ -147,8 +149,17 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
||||
parting_result = self._detect_parting_surfaces(product_shape, analysis)
|
||||
primary_parting_surface = parting_result["primary_surface"]
|
||||
primary_parting_line = parting_result["primary_line"]
|
||||
primary_parting_direction = parting_result["primary_direction"]
|
||||
|
||||
undercut_regions = self._detect_undercut_regions(product_shape, primary_parting_surface)
|
||||
side_action_result = self.side_action_designer.analyze_and_design(
|
||||
shape=product_shape,
|
||||
parting_direction=primary_parting_direction,
|
||||
mold_size=self._calculate_mold_size(analysis),
|
||||
parting_surface=primary_parting_surface,
|
||||
)
|
||||
undercut_regions = self._build_undercut_regions(
|
||||
side_action_result.get("undercut_analysis", {})
|
||||
)
|
||||
|
||||
scaled_shape = self._apply_shrinkage_compensation(product_shape)
|
||||
|
||||
@@ -170,6 +181,7 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
||||
"mold_block": mold_block,
|
||||
"analysis": analysis,
|
||||
"undercut_regions": undercut_regions,
|
||||
"side_actions": side_action_result,
|
||||
"parting_surfaces": parting_result,
|
||||
"material": self.foam_material,
|
||||
"shrinkage_applied": self.shrinkage_rate,
|
||||
@@ -224,6 +236,7 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
||||
},
|
||||
"quality_checks": {
|
||||
"undercut_regions": cavity_data.get("undercut_regions", []),
|
||||
"side_actions": cavity_data.get("side_actions", {}),
|
||||
"parting_line_smoothness": self._assess_parting_line_smoothness(
|
||||
cavity_data.get("parting_line", [])
|
||||
)
|
||||
@@ -265,6 +278,7 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
||||
"quality_considerations": {
|
||||
"undercut_count": len(cavity_data.get("undercut_regions", [])),
|
||||
"undercut_regions": cavity_data.get("undercut_regions", []),
|
||||
"side_action_summary": cavity_data.get("side_actions", {}).get("summary", {}),
|
||||
"sink_mark_risk": self._identify_sink_mark_risk(analysis),
|
||||
"warpage_risk": self._assess_warpage_risk(analysis),
|
||||
"venting_requirement": self._assess_venting_requirement(analysis)
|
||||
@@ -278,130 +292,27 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
||||
def _analyze_product_geometry(self, shape: Any) -> Dict[str, Any]:
|
||||
"""分析产品几何属性(扩展基类版本,增加法向量统计)"""
|
||||
result = super()._analyze_product_geometry(shape)
|
||||
result["normal_statistics"] = self._analyze_face_normals(shape)
|
||||
result["normal_statistics"] = self._analyze_parting_direction(shape)
|
||||
return result
|
||||
|
||||
def _split_cavity_core(self, shape: Any, parting_surface: Any) -> Tuple[Any, Any]:
|
||||
"""分离型腔和型芯(铝泡沫使用更大余量)"""
|
||||
return super()._split_cavity_core(shape, parting_surface, margin=25)
|
||||
|
||||
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:
|
||||
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]:
|
||||
"""
|
||||
检测分型面(支持多分型面)
|
||||
"""
|
||||
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, shape)
|
||||
except Exception as e:
|
||||
logger.warning(f"AI 分型面检测失败: {e}")
|
||||
primary_parting = self._detect_primary_parting(shape, analysis)
|
||||
parting_surface = primary_parting["surface"]
|
||||
parting_line = self.optimize_parting_line(primary_parting["line"])
|
||||
primary_direction = primary_parting["direction"]
|
||||
|
||||
normal_stats = analysis.get("normal_statistics", {})
|
||||
primary_direction = normal_stats.get("primary_direction", [0, 0, 1])
|
||||
additional_surfaces = []
|
||||
|
||||
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 Exception:
|
||||
parting_plane = gp_Pln(gp_Pnt(0, 0, center[2]), gp_Dir(0, 0, 1))
|
||||
parting_surface = BRepBuilderAPI_MakeFace(parting_plane).Face()
|
||||
|
||||
parting_line = self._calculate_parting_line(shape, parting_surface)
|
||||
|
||||
additional_surfaces = []
|
||||
|
||||
dims = bbox["dimensions"]
|
||||
max_dim = max(dims)
|
||||
min_dim = min(dims)
|
||||
@@ -422,59 +333,29 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
||||
"primary_surface": parting_surface,
|
||||
"primary_line": parting_line,
|
||||
"primary_direction": primary_direction,
|
||||
"confidence": normal_stats.get("confidence", 0.5),
|
||||
"confidence": primary_parting["confidence"],
|
||||
"method": primary_parting["method"],
|
||||
"additional_surfaces": additional_surfaces,
|
||||
"surface_count": 1 + len(additional_surfaces)
|
||||
}
|
||||
|
||||
def _detect_undercut_regions(self, shape: Any, parting_surface: Any) -> List[Dict]:
|
||||
"""
|
||||
检测倒扣区域
|
||||
"""
|
||||
undercut_regions = []
|
||||
def _build_undercut_regions(self, undercut_analysis: Dict[str, Any]) -> List[Dict[str, Any]]:
|
||||
"""将侧向机构分析结果转换为兼容旧结构的倒扣区域列表。"""
|
||||
undercut_faces = undercut_analysis.get("undercut_faces", [])
|
||||
regions = []
|
||||
|
||||
try:
|
||||
surface = BRepAdaptor_Surface(parting_surface)
|
||||
parting_normal = surface.Plane().Position().Direction()
|
||||
for face in undercut_faces:
|
||||
regions.append({
|
||||
"type": "negative_draft",
|
||||
"location": face.get("center", [0, 0, 0]),
|
||||
"severity": face.get("severity", "medium"),
|
||||
"area": face.get("area", 0),
|
||||
"is_outer": face.get("is_outer", False),
|
||||
"face_index": face.get("face_index"),
|
||||
})
|
||||
|
||||
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:
|
||||
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())
|
||||
|
||||
if dot < -0.7:
|
||||
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
|
||||
logger.info(f"转换得到 {len(regions)} 个兼容倒扣区域")
|
||||
return regions
|
||||
|
||||
def _smooth_parting_line(self, parting_line: List[List[float]]) -> List[List[float]]:
|
||||
"""
|
||||
@@ -561,23 +442,13 @@ class AluminumFoamMoldGenerator(BaseMoldGenerator):
|
||||
|
||||
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 Exception:
|
||||
return {
|
||||
"type": "plane",
|
||||
"normal": [0, 0, 1],
|
||||
"origin": [0, 0, 0],
|
||||
"bounds": {"u_range": [-200, 200], "v_range": [-200, 200]}
|
||||
}
|
||||
metadata = self._extract_plane_metadata(surface)
|
||||
return {
|
||||
"type": "plane",
|
||||
"normal": metadata["normal"],
|
||||
"origin": metadata["origin"],
|
||||
"bounds": metadata["bounds"],
|
||||
}
|
||||
|
||||
def _create_parting_surface_from_ai(self, ai_result: Dict, analysis: Dict,
|
||||
shape: Any = None) -> Dict:
|
||||
|
||||
Reference in New Issue
Block a user