feat: 完善 STEP 一级参数化编辑识别与关系式建模

This commit is contained in:
2026-08-14 18:42:39 +08:00
parent 70b59c1de6
commit a633b5a338
26 changed files with 4676 additions and 77 deletions
@@ -22,6 +22,7 @@ from verify_boss_resize import _first_boss_face, _write_boss_model # noqa: E402
from verify_ellipse_edge_resize import _write_ellipse_face_model # noqa: E402
from verify_edge_round_chamfer import ( # noqa: E402
_first_existing_fillet_face,
_write_filleted_box_model,
_write_mixed_radius_filleted_box_model,
)
from verify_shell_thickness_resize import _first_open_shell_wall_face, _write_open_thin_wall_box_model # noqa: E402
@@ -64,6 +65,66 @@ def _first_surface_face(model: StepModel, surface: str) -> int:
raise AssertionError(f"no {surface} Face was found")
def _first_adjacent_face(model: StepModel, face_id: int) -> int:
edge_ids = model._face_boundary_edge_ids(face_id) # noqa: SLF001
adjacent_ids = sorted(model._adjacent_face_ids_for_edges(edge_ids, face_id)) # noqa: SLF001
for adjacent_id in adjacent_ids:
if 0 <= int(adjacent_id) < len(model.faces):
return int(adjacent_id)
raise AssertionError(f"Face {face_id} has no adjacent Face")
def _install_synthetic_asitus_support(
model: StepModel,
face_id: int,
*,
relation_type: str,
angle_type: str,
) -> int:
adjacent_id = _first_adjacent_face(model, face_id)
face_info = model.quick_face_info(face_id)
adjacent_info = model.quick_face_info(adjacent_id)
result = {
"ok": True,
"reason": "ok",
"groups": (),
"faces": (
{
"id": face_id + 1,
"surface": str(face_info.get("surface") or ""),
"neighbor_ids": (adjacent_id + 1,),
},
{
"id": adjacent_id + 1,
"surface": str(adjacent_info.get("surface") or ""),
"neighbor_ids": (face_id + 1,),
},
),
"adjacency": (
{
"face_ids": (face_id + 1, adjacent_id + 1),
"angle_type": angle_type,
"angle_rad": 0.0,
"edge_ids": (),
},
),
"geometric_relations": (
{
"face_ids": (face_id + 1, adjacent_id + 1),
"relation_type": relation_type,
"residual": 0.0,
"source": "synthetic-analysis-situs-test",
},
),
"surface_summary": {},
"angle_summary": {angle_type: 1},
"geometric_relation_summary": {relation_type: 1},
"geometric_relation_mode": "synthetic-test",
}
model.install_asitus_hole_recognition_result(result)
return adjacent_id
def _first_quick_candidate(
model: StepModel,
*,
@@ -245,6 +306,79 @@ def _verify_boss_summary(root: Path) -> None:
_assert(int(info.get("recognition_user_priority", 99)) == 40, f"boss should use boss priority: {info}")
def _assert_asitus_hint(
info: dict[str, object],
*,
preferred: str,
label: str,
) -> None:
_assert(
info.get("analysis_situs_feature_hint_preferred") == preferred,
f"{label}: Analysis Situs hint should prefer {preferred}: {info}",
)
_assert(
int(info.get("analysis_situs_feature_hint_score") or 0) > 0,
f"{label}: Analysis Situs hint score is missing: {info}",
)
_assert(
"analysis_situs_feature_hint" in set(info.get("recognition_evidence_keys") or ()),
f"{label}: recognition evidence should mention Analysis Situs feature hint: {info}",
)
def _verify_asitus_slot_boss_fillet_hints(root: Path) -> None:
slot_path = root / "asitus_slot_hint.step"
_write_half_round_slot_model(slot_path)
slot_model = StepModel.load(slot_path)
slot_face_id = _first_slot_face(slot_model)
_install_synthetic_asitus_support(slot_model, slot_face_id, relation_type="tangent", angle_type="smooth")
slot_info = slot_model.feature_info(slot_face_id)
_assert_asitus_hint(slot_info, preferred="slot", label="slot hint")
slot_candidates = [
item
for item in slot_model.editable_feature_candidates(limit=80, detailed=False)
if int(item.get("face_id", -1) or -1) == slot_face_id
]
_assert(
any(int(item.get("analysis_situs_slot_hint_score") or 0) > 0 for item in slot_candidates),
f"slot candidates should carry Analysis Situs slot support: {slot_candidates}",
)
boss_path = root / "asitus_boss_hint.step"
_write_boss_model(boss_path)
boss_model = StepModel.load(boss_path)
boss_face_id = _first_boss_face(boss_model)
_install_synthetic_asitus_support(boss_model, boss_face_id, relation_type="parallel", angle_type="convex")
boss_info = boss_model.feature_info(boss_face_id)
_assert_asitus_hint(boss_info, preferred="boss", label="boss hint")
boss_candidates = [
item
for item in boss_model.editable_feature_candidates(limit=80, detailed=False)
if int(item.get("face_id", -1) or -1) == boss_face_id
]
_assert(
any(int(item.get("analysis_situs_boss_hint_score") or 0) > 0 for item in boss_candidates),
f"boss candidates should carry Analysis Situs boss support: {boss_candidates}",
)
fillet_path = root / "asitus_fillet_hint.step"
_write_filleted_box_model(fillet_path, 1.0)
fillet_model = StepModel.load(fillet_path)
fillet_face_id = _first_existing_fillet_face(fillet_model, 1.0, 2e-4)
_install_synthetic_asitus_support(fillet_model, fillet_face_id, relation_type="tangent", angle_type="smooth")
fillet_info = fillet_model.feature_info(fillet_face_id)
_assert_asitus_hint(fillet_info, preferred="fillet", label="fillet hint")
fillet_candidates = [
item
for item in fillet_model.editable_feature_candidates(limit=80, detailed=False)
if int(item.get("face_id", -1) or -1) == fillet_face_id
]
_assert(
any(int(item.get("analysis_situs_fillet_hint_score") or 0) > 0 for item in fillet_candidates),
f"fillet candidates should carry Analysis Situs fillet support: {fillet_candidates}",
)
def _verify_torus_summary(root: Path) -> None:
path = root / "torus.step"
_write_step(BRepPrimAPI_MakeTorus(12.0, 2.0).Shape(), path)
@@ -416,6 +550,16 @@ def main() -> int:
"recognition_user_priority_label",
"recognition_user_priority_reason",
"recognition_evidence",
"recognition_external_relation_score_bonus",
"analysis_situs_feature_hint_status",
"analysis_situs_feature_hint_preferred",
"analysis_situs_feature_hint_label",
"analysis_situs_feature_hint_score",
"analysis_situs_feature_hint_summary",
"analysis_situs_feature_hint_related_face_ids",
"analysis_situs_slot_hint_score",
"analysis_situs_boss_hint_score",
"analysis_situs_fillet_hint_score",
"recognition_ready_actions",
"recognition_limited_actions",
"recognition_blockers",
@@ -431,6 +575,7 @@ def main() -> int:
_verify_hole_summary(root)
_verify_slot_summary(root)
_verify_boss_summary(root)
_verify_asitus_slot_boss_fillet_hints(root)
_verify_torus_summary(root)
_verify_user_priority_scan_order(root)
_verify_candidate_scan_cache(root)