feat: 增强一级关系识别与保持关系策略

This commit is contained in:
2026-08-10 14:56:50 +08:00
parent 12250603dd
commit 83c44265ba
24 changed files with 3460 additions and 241 deletions
+57
View File
@@ -146,6 +146,62 @@ def assert_rectangular_feature_ui(
raise AssertionError(f"unexpected rectangular feature UI parameters: {actual}")
def find_multistep_transition_face(model: StepModel) -> tuple[int, dict[str, object]]:
matches: list[tuple[int, dict[str, object]]] = []
for face_id in range(len(model.faces)):
info = model.feature_info(face_id)
if info.get("multistep_prismatic_status") != "blocked":
continue
center = info.get("area_center")
z_value = float(center[2]) if isinstance(center, (list, tuple)) and len(center) >= 3 else -1.0
matches.append((face_id, info | {"_z_sort": z_value}))
if not matches:
raise AssertionError("expected at least one blocked multistep transition face")
matches.sort(key=lambda item: float(item[1].get("_z_sort", -1.0)), reverse=True)
face_id, info = matches[0]
info.pop("_z_sort", None)
return face_id, info
def assert_multistep_transition_guard(model: StepModel) -> None:
face_id, info = find_multistep_transition_face(model)
blockers = str(info.get("multistep_prismatic_blockers") or info.get("recognition_blockers") or "")
if "多台阶" not in blockers or "暂不支持" not in blockers:
raise AssertionError(f"multistep transition blocker should explain unsupported scope: {info}")
if "复杂多台阶凸台" not in str(info.get("feature_type")):
raise AssertionError(f"unexpected multistep transition label: {info.get('feature_type')}")
if feature_dimension_rows(model, face_id, info) != ():
raise AssertionError("blocked multistep transition face should not expose editable dimensions")
target_center = info.get("area_center")
if not isinstance(target_center, (list, tuple)) or len(target_center) != 3:
raise AssertionError(f"multistep transition face lacks a stable center: {info}")
center_target = (float(target_center[0]) + 0.5, float(target_center[1]), float(target_center[2]))
plans = (
model.push_pull_plan(face_id, 1.0),
model.shell_thickness_plan(face_id, 2.5),
model.face_size_local_resize_plan(face_id, 9.0, "width"),
model.face_center_local_move_plan(face_id, center_target),
)
for plan in plans:
if plan.get("status") != "blocked":
raise AssertionError(f"multistep transition plan should be blocked: {plan}")
message = str(plan.get("message") or plan.get("blockers") or "")
if "多台阶" not in message or "暂不支持" not in message:
raise AssertionError(f"multistep transition plan should explain unsupported scope: {plan}")
leaked_entries = [
item
for item in model.editable_feature_candidates(limit=80, detailed=False)
if int(item.get("target_id", -1)) == face_id
and str(item.get("operation_key") or "") in {"push_pull_plane", "resize_shell_thickness"}
]
if leaked_entries:
raise AssertionError(
f"blocked multistep transition face should not leak editable scan entries: {leaked_entries}"
)
def assert_prismatic_feature_display_labels() -> None:
state = object.__new__(WindowStateMixin)
if state._feature_display_label("矩形口袋候选") != "矩形槽/口袋":
@@ -432,6 +488,7 @@ def main() -> int:
multistep_path = temp_path / "rectangular-multistep-boss.step"
write_rectangular_multistep_boss_model(multistep_path)
multistep_model = StepModel.load(multistep_path)
assert_multistep_transition_guard(multistep_model)
multistep_face_id, multistep_info = find_prismatic_semantics(multistep_model, "additive-boss")
assert_prismatic_sizes(multistep_info, 6.0, 4.0, 2.0)
assert_rectangular_feature_ui(