from __future__ import annotations from pathlib import Path import sys PROJECT_ROOT = Path(__file__).resolve().parent.parent if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) from step_editor.model import StepModel DEFAULT_MODEL = PROJECT_ROOT / "assets" / "models" / "cube_10mm.step" def _first_plane_face(model: StepModel) -> int: for face_id in range(len(model.faces)): info = model.face_info(face_id) if info.get("surface") == "plane": return face_id raise SystemExit("no plane Face found") def _assert_plan(label: str, plan: dict[str, object], status: str, risk: str | None = None) -> None: actual_status = str(plan.get("status", "")) actual_risk = str(plan.get("risk", "")) if actual_status != status: raise SystemExit(f"{label} expected status={status}, got {actual_status}: {plan}") if risk is not None and actual_risk != risk: raise SystemExit(f"{label} expected risk={risk}, got {actual_risk}: {plan}") def main() -> int: model = StepModel.load(DEFAULT_MODEL) face_id = _first_plane_face(model) shallow = model.push_pull_plan(face_id, -1.0) _assert_plan("shallow inward cut", shallow, "ready", "low") if abs(float(shallow.get("push_pull_inward_material_depth") or 0.0) - 10.0) > 1e-5: raise SystemExit(f"shallow cut should report 10mm inward material depth: {shallow}") if abs(float(shallow.get("push_pull_inward_cut_ratio") or 0.0) - 0.1) > 1e-5: raise SystemExit(f"shallow cut should report 0.1 inward cut ratio: {shallow}") near_through = model.push_pull_plan(face_id, -9.0) _assert_plan("near-through inward cut", near_through, "caution", "high") if float(near_through.get("push_pull_inward_cut_ratio") or 0.0) < 0.85: raise SystemExit(f"near-through cut should report a high inward cut ratio: {near_through}") through = model.push_pull_plan(face_id, -10.0) _assert_plan("through inward cut", through, "blocked", "blocked") message = str(through.get("message") or through.get("blockers") or "") if "材料厚度" not in message and "切空" not in message: raise SystemExit(f"through cut blocker should explain material depth: {through}") try: model.push_pull_face(face_id, -10.0) except ValueError: pass else: raise SystemExit("push_pull_face should reject an inward cut that reaches full material depth") print("Face push/pull limit guards ok") return 0 if __name__ == "__main__": raise SystemExit(main())