feat: 扩展Face保持关系编辑语义

This commit is contained in:
2026-08-10 17:50:50 +08:00
parent 61f0b76e59
commit 3a851d0967
8 changed files with 382 additions and 41 deletions
+12
View File
@@ -14,6 +14,10 @@ CASES: tuple[tuple[str, tuple[str, ...]], ...] = (
"face width, current face only",
("verify_face_resize_semantics.py", "--strategy", "local", "--axis", "width", "--target-size", "15"),
),
(
"face width, keep first-level planar relations",
("verify_face_resize_semantics.py", "--strategy", "keep_relations", "--axis", "width", "--target-size", "15"),
),
(
"Face first-level shared-edge topology",
("verify_face_first_level_topology.py",),
@@ -30,6 +34,10 @@ CASES: tuple[tuple[str, tuple[str, ...]], ...] = (
"face height, current face only",
("verify_face_resize_semantics.py", "--strategy", "local", "--axis", "height", "--target-size", "15"),
),
(
"face height, keep first-level planar relations",
("verify_face_resize_semantics.py", "--strategy", "keep_relations", "--axis", "height", "--target-size", "15"),
),
(
"face height, owning feature",
("verify_face_resize_semantics.py", "--strategy", "owning", "--axis", "height", "--target-size", "15"),
@@ -50,6 +58,10 @@ CASES: tuple[tuple[str, tuple[str, ...]], ...] = (
"face center, current face only",
("verify_face_resize_semantics.py", "--property", "center", "--strategy", "local", "--center-offset", "2,0,3"),
),
(
"face center, keep first-level planar relations",
("verify_face_resize_semantics.py", "--property", "center", "--strategy", "keep_relations", "--center-offset", "2,0,3"),
),
(
"face center, owning feature",
("verify_face_resize_semantics.py", "--property", "center", "--strategy", "owning", "--center-offset", "2,0,3"),
+21 -7
View File
@@ -15,12 +15,15 @@ DEFAULT_MODEL = PROJECT_ROOT / "assets" / "models" / "cube_10mm.step"
FACE_CASES = (
("size", "local", "width"),
("size", "keep_relations", "width"),
("size", "owning", "width"),
("size", "local", "height"),
("size", "keep_relations", "height"),
("size", "owning", "height"),
("area", "local", "width"),
("area", "owning", "width"),
("center", "local", "width"),
("center", "keep_relations", "width"),
("center", "owning", "width"),
("offset", "local", "width"),
("offset", "owning", "width"),
@@ -183,13 +186,19 @@ def main() -> int:
before = model.stats()
current_info = model.face_info(face_id)
if args.strategy in {"push_pull", "keep_relations"} and args.property != "offset":
raise SystemExit("--strategy push_pull/keep_relations is only valid with --property offset")
if args.strategy == "push_pull" and args.property != "offset":
raise SystemExit("--strategy push_pull is only valid with --property offset")
if args.strategy == "keep_relations" and args.property not in {"size", "center", "offset"}:
raise SystemExit("--strategy keep_relations is only valid with --property size/center/offset")
if args.property == "size" and args.strategy == "local":
plan = model.face_size_local_resize_plan(face_id, args.target_size, args.axis)
result = model.resize_face_size_local(face_id, args.target_size, args.axis)
expected_strategy = f"local-face-{args.axis}-only-deform"
elif args.property == "size" and args.strategy == "keep_relations":
plan = model.face_size_local_resize_keep_relations_plan(face_id, args.target_size, args.axis)
result = model.resize_face_size_local_keep_relations(face_id, args.target_size, args.axis)
expected_strategy = f"axis-scale-owning-shape-from-face-{args.axis}"
elif args.property == "size":
plan = model.face_size_owning_scale_plan(face_id, args.target_size, args.axis)
result = model.resize_face_size_owning_scale(face_id, args.target_size, args.axis)
@@ -202,7 +211,7 @@ def main() -> int:
plan = model.face_area_scale_plan(face_id, args.target_area)
result = model.resize_face_area(face_id, args.target_area)
expected_strategy = "uniform-scale-face-area-fallback"
elif args.property == "center" and args.strategy == "local":
elif args.property == "center" and args.strategy in {"local", "keep_relations"}:
current_center = current_info.get("area_center") or current_info.get("bbox_center")
if not isinstance(current_center, tuple) or len(current_center) != 3:
raise SystemExit("selected Face does not have a stable center")
@@ -212,9 +221,14 @@ def main() -> int:
float(current_center[1]) + offset[1],
float(current_center[2]) + offset[2],
)
plan = model.face_center_local_move_plan(face_id, target_center)
result = model.move_face_center_local(face_id, target_center)
expected_strategy = "local-face-only-deform"
if args.strategy == "keep_relations":
plan = model.face_center_local_move_keep_relations_plan(face_id, target_center)
result = model.move_face_center_local_keep_relations(face_id, target_center)
expected_strategy = "translate-owning-shape-from-face-center"
else:
plan = model.face_center_local_move_plan(face_id, target_center)
result = model.move_face_center_local(face_id, target_center)
expected_strategy = "local-face-only-deform"
elif args.property == "center":
current_center = current_info.get("area_center") or current_info.get("bbox_center")
if not isinstance(current_center, tuple) or len(current_center) != 3:
@@ -298,7 +312,7 @@ def main() -> int:
resolved_strategy = "push-pull-planar-face"
if resolved_strategy != expected_strategy:
raise SystemExit(f"expected {expected_strategy}, got {resolved_strategy or '<none>'}")
if args.property == "offset" and args.strategy == "keep_relations":
if args.strategy == "keep_relations":
if plan.get("face_push_pull_planar_relation_constraint_requested") is not True:
raise SystemExit(f"keep-relations plan should record requested relation constraint: {plan}")
if plan.get("face_push_pull_planar_constraint_status") != "ready":
+23 -2
View File
@@ -498,6 +498,27 @@ def main() -> int:
raise SystemExit(f"Face plane-offset keep-relations scope should use its own action: {offset_keep_relations}")
if not bool(offset_keep_relations.get("enabled", False)):
raise SystemExit(f"Face plane-offset keep-relations scope should be available on simple planar Face: {offset_keep_relations}")
width_keep_relations = _scope_mode(plane_specs, "local_face_width", "keep_relations")
if str(width_keep_relations.get("label") or "") != "保持关系":
raise SystemExit(f"Face width keep-relations scope should be labelled clearly: {width_keep_relations}")
if str(width_keep_relations.get("action") or "") != "resize_face_width_keep_relations":
raise SystemExit(f"Face width keep-relations scope should use its own action: {width_keep_relations}")
if not bool(width_keep_relations.get("enabled", False)):
raise SystemExit(f"Face width keep-relations scope should be available on simple planar Face: {width_keep_relations}")
height_keep_relations = _scope_mode(plane_specs, "local_face_height", "keep_relations")
if str(height_keep_relations.get("label") or "") != "保持关系":
raise SystemExit(f"Face height keep-relations scope should be labelled clearly: {height_keep_relations}")
if str(height_keep_relations.get("action") or "") != "resize_face_height_keep_relations":
raise SystemExit(f"Face height keep-relations scope should use its own action: {height_keep_relations}")
if not bool(height_keep_relations.get("enabled", False)):
raise SystemExit(f"Face height keep-relations scope should be available on simple planar Face: {height_keep_relations}")
center_keep_relations = _scope_mode(plane_specs, "face_center_position", "keep_relations")
if str(center_keep_relations.get("label") or "") != "保持关系":
raise SystemExit(f"Face center keep-relations scope should be labelled clearly: {center_keep_relations}")
if str(center_keep_relations.get("action") or "") != "move_selected_face_center_keep_relations":
raise SystemExit(f"Face center keep-relations scope should use its own action: {center_keep_relations}")
if not bool(center_keep_relations.get("enabled", False)):
raise SystemExit(f"Face center keep-relations scope should be available on simple planar Face: {center_keep_relations}")
_assert_scoped_hint_fragments(
plane_specs,
"face_target_normal_position",
@@ -581,7 +602,7 @@ def main() -> int:
if "push_pull_distance" in plane_keys:
raise SystemExit("plane Face should not expose a separate push_pull_distance row")
for key in ("local_face_width", "local_face_height"):
for mode in ("local", "owning"):
for mode in ("local", "keep_relations", "owning"):
_assert_scoped_hint_fragments(
plane_specs,
key,
@@ -595,7 +616,7 @@ def main() -> int:
mode,
("会被阻止",),
)
for mode in ("local", "owning"):
for mode in ("local", "keep_relations", "owning"):
_assert_scoped_hint_fragments(
plane_specs,
"face_center_position",