feat: 完善 Face 一级编辑与隔离计算

This commit is contained in:
2026-08-05 15:08:16 +08:00
parent a76282d7dd
commit ed1faf51d8
28 changed files with 3740 additions and 876 deletions
+83 -5
View File
@@ -19,6 +19,11 @@ if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
from step_editor.model import StepModel
from step_editor.window_actions import WindowActionMixin
class _WindowActionProbe(WindowActionMixin):
pass
def _wire_count(face) -> int:
@@ -240,17 +245,54 @@ def main() -> int:
raise SystemExit(
f"multi-boundary cap inward push/pull plan should be quick: {multi_inward_elapsed:.3f}s"
)
if multi_inward_plan.get("status") != "blocked":
if multi_inward_plan.get("status") == "blocked":
raise SystemExit(
f"multi-boundary cap inward push/pull should be blocked until second-level propagation exists: "
f"multi-boundary cap shallow inward push/pull should be allowed by boundary shell rebuild: "
f"{multi_inward_plan}"
)
multi_inward_message = str(multi_inward_plan.get("message") or "")
if "二级关系" not in multi_inward_message or "通用 OCCT 布尔" not in multi_inward_message:
if multi_inward_plan.get("planar_cap_extension_method") != "boundary-shell-rebuild":
raise SystemExit(
f"multi-boundary cap inward blocker should explain topology depth and slow Boolean risk: "
f"multi-boundary cap shallow inward should use boundary shell rebuild: {multi_inward_plan}"
)
multi_inward_message = str(multi_inward_plan.get("message") or "")
if "向内收缩" not in multi_inward_message and "重建侧壁" not in multi_inward_message:
raise SystemExit(
f"multi-boundary cap shallow inward message should explain boundary shell semantics: "
f"{multi_inward_plan}"
)
multi_inward_result_model = StepModel.load(path)
started = time.perf_counter()
multi_inward_result = multi_inward_result_model.push_pull_face(multi_face_id, -1.0)
multi_inward_result_elapsed = time.perf_counter() - started
if multi_inward_result_elapsed > 15.0:
raise SystemExit(
f"multi-boundary cap shallow inward push/pull took too long: "
f"{multi_inward_result_elapsed:.3f}s; result={multi_inward_result}"
)
if "boundary-shell rebuild" not in multi_inward_result or "actual=56.5" not in multi_inward_result:
raise SystemExit(
f"multi-boundary cap shallow inward should move to 56.5 by boundary shell rebuild: {multi_inward_result}"
)
if multi_inward_result_model.stats().solids != 1:
raise SystemExit(f"multi-boundary cap shallow inward should keep one Solid: {multi_inward_result_model.stats()}")
inward_retained_ids = multi_inward_result_model.face_ids_for_logical_id(multi_logical_id)
if len(inward_retained_ids) != 1:
raise SystemExit(f"multi-boundary cap shallow inward logical Face should follow the moved cap: {inward_retained_ids}")
inward_info = multi_inward_result_model.quick_face_info(inward_retained_ids[0])
if int(inward_info.get("inner_boundary_wires", 0) or 0) < 5:
raise SystemExit(f"multi-boundary cap shallow inward should keep inner wires: {inward_info}")
multi_deep_inward_plan = multi_model.push_pull_plan(multi_face_id, -77.5)
if multi_deep_inward_plan.get("status") != "blocked":
raise SystemExit(
f"multi-boundary cap deep inward push/pull should still be blocked: {multi_deep_inward_plan}"
)
multi_deep_inward_message = str(multi_deep_inward_plan.get("message") or "")
if "材料厚度" not in multi_deep_inward_message and "二级关系" not in multi_deep_inward_message:
raise SystemExit(
f"multi-boundary cap deep inward blocker should explain cut-through or topology depth: "
f"{multi_deep_inward_plan}"
)
started = time.perf_counter()
multi_result = multi_model.push_pull_face(multi_face_id, 34.5)
@@ -351,6 +393,42 @@ def main() -> int:
raise SystemExit(
f"large multi-boundary cap isolated worker used the wrong path: {multi_isolated_message}"
)
isolated_output_model = StepModel.load(output_path)
probe = _WindowActionProbe()
direction = multi_plan.get("outward_direction") or multi_plan.get("plane_direction")
context = {
"operation_name": "拉伸/切除平面",
"target_kind": "face",
"target_id": multi_face_id,
"target_logical_id": multi_face_id,
"parameters": {
"part_id": multi_plan.get("part_id"),
"solid_id": multi_plan.get("solid_id"),
"surface": "plane",
"outward_direction": direction,
"current_plane_position": multi_plan.get("current_plane_position"),
"target_plane_position": multi_plan.get("target_plane_position"),
"bbox_diagonal": multi_plan.get("bbox_diagonal"),
"resize_strategy": multi_plan.get("resize_strategy"),
},
}
blocker = probe._face_target_integrity_blocker(isolated_output_model, context)
if blocker:
raise SystemExit(f"window-layer isolated target check should accept the moved cap: {blocker}")
probe._preserve_isolated_face_logical_id(isolated_output_model, context, multi_isolated_message)
retained_after_isolation = isolated_output_model.face_ids_for_logical_id(multi_face_id)
if not retained_after_isolation:
raise SystemExit("window-layer isolated logical Face retention lost the moved cap")
if not probe._face_target_plane_position_matches(
isolated_output_model,
retained_after_isolation,
float(multi_plan["target_plane_position"]),
direction,
float(multi_plan["bbox_diagonal"]),
):
raise SystemExit(
f"window-layer isolated logical Face retention points at the wrong cap: {retained_after_isolation}"
)
print(
"large stepped cap push/pull ok: "