Files
pythonocc-step-editor/step_editor/recognition_priority.py
T

159 lines
5.6 KiB
Python
Raw Normal View History

from __future__ import annotations
import math
from typing import Mapping
USER_OPERATION_PRIORITY: dict[str, int] = {
"push_pull_plane": 10,
"resize_cylinder": 20,
"resize_depth": 24,
"suppress_cylinder": 28,
"resize_slot_width": 30,
"resize_slot_depth": 31,
"resize_slot_arc_length": 34,
"resize_slot_angular_span": 35,
"resize_boss": 40,
"resize_boss_height": 41,
"move_boss_axis": 44,
"inspect_existing_fillet": 50,
"fillet_edge": 52,
"chamfer_edge": 53,
"resize_shell_thickness": 60,
"resize_edge_length": 70,
"resize_ellipse_edge_major_radius": 72,
"resize_ellipse_edge_minor_radius": 73,
}
USER_PRIORITY_BUCKETS: tuple[tuple[int, str, str], ...] = (
(10, "Face 面编辑", "最常用:平面拉伸/切除、面尺寸、中心和偏移。"),
(20, "孔", "常用:孔径、孔深、孔轴心和封堵。"),
(30, "槽/半孔", "常用:槽宽、槽深、弧长、弧角和槽轴心。"),
(40, "凸台/外圆", "常用:凸台直径、高度和轴心。"),
(50, "圆角/倒角", "常用但风险更高:已有圆角半径、新增圆角或倒角。"),
(60, "壳体厚度", "专项:相对面可识别时修改局部厚度。"),
(70, "Edge 边编辑", "受限:边长、端点、圆边半径等一级关系编辑。"),
(80, "解析曲面", "较少直接修改:圆锥、球面、环面等解析曲面参数。"),
(90, "只读/诊断", "暂未稳定归类为可修改特征。"),
)
def _text(value: object) -> str:
return str(value or "").strip()
def _float_or_none(value: object) -> float | None:
try:
return float(value)
except (TypeError, ValueError):
return None
def _is_effectively_full_cylinder(info: Mapping[str, object]) -> bool:
if bool(info.get("is_full_cylinder")):
return True
for key in ("same_domain_angular_span", "angular_span"):
angular_span = _float_or_none(info.get(key))
if angular_span is not None and angular_span >= math.tau * 0.92:
return True
return False
def feature_recognition_priority(info: Mapping[str, object]) -> int:
"""Rank feature candidates by likely user editing frequency.
The rank is intentionally product-facing, not a geometry confidence score:
lower numbers should appear earlier in editable-feature lists.
"""
operation_key = _text(info.get("operation_key"))
if operation_key in USER_OPERATION_PRIORITY:
return USER_OPERATION_PRIORITY[operation_key]
surface = _text(info.get("surface"))
feature_guess = _text(info.get("feature_guess"))
feature_type = _text(info.get("feature_type"))
feature_actions = _text(info.get("feature_edit_actions"))
ready_actions = _text(info.get("recognition_ready_actions"))
combined_text = "".join(item for item in (feature_type, feature_actions, ready_actions) if item)
if surface == "plane":
return 10
if surface == "cylinder":
if feature_guess == "hole/groove candidate":
angular_span = _float_or_none(info.get("angular_span"))
if (
not _is_effectively_full_cylinder(info)
and angular_span is not None
and angular_span < math.tau * 0.92
) or _text(info.get("slot_kind")) == "partial-cylindrical-groove" or "槽/半孔候选" in feature_type:
return 30
return 20
if feature_guess == "boss/outer-round candidate":
return 40
if feature_guess == "round/fillet candidate":
return 50
if "孔" in combined_text:
return 20
if "槽" in combined_text or "半孔" in combined_text:
return 30
if "凸台" in combined_text or "外圆" in combined_text:
return 40
if "圆角" in combined_text or "倒圆" in combined_text:
return 50
return 90
if surface == "edge" or _text(info.get("curve")):
if "圆角" in combined_text:
return 52
if "倒角" in combined_text:
return 53
return 70
if surface in {"cone", "sphere", "torus"}:
return 80
if "壳体" in combined_text or _text(info.get("shell_region_status")) == "candidate":
return 60
return 90
def feature_recognition_priority_bucket(priority: int) -> tuple[int, str, str]:
selected = USER_PRIORITY_BUCKETS[-1]
for bucket in USER_PRIORITY_BUCKETS:
if priority >= bucket[0]:
selected = bucket
else:
break
return selected
def feature_recognition_priority_label(info: Mapping[str, object]) -> str:
priority = feature_recognition_priority(info)
_start, label, _reason = feature_recognition_priority_bucket(priority)
return f"{priority:02d} · {label}"
def feature_recognition_priority_reason(info: Mapping[str, object]) -> str:
priority = feature_recognition_priority(info)
_start, _label, reason = feature_recognition_priority_bucket(priority)
return reason
def feature_recognition_sort_key(info: Mapping[str, object]) -> tuple[int, int, int, int]:
status_order = {"ready": 0, "candidate": 0, "caution": 1, "blocked": 2}
risk_order = {"low": 0, "medium": 1, "high": 2, "blocked": 3}
target_id = info.get("target_id", info.get("face_id", info.get("edge_id", -1)))
try:
numeric_target = int(target_id)
except (TypeError, ValueError):
numeric_target = -1
return (
feature_recognition_priority(info),
status_order.get(_text(info.get("status")), 9),
risk_order.get(_text(info.get("risk")), 9),
numeric_target,
)