feat: 完善 STEP 一级参数化编辑识别与关系式建模
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user