feat: 完善 Face 参数化编辑和隔离执行

This commit is contained in:
2026-07-31 16:36:05 +08:00
parent 27e4f7236c
commit bb44e3920d
31 changed files with 5428 additions and 252 deletions
+99
View File
@@ -0,0 +1,99 @@
from __future__ import annotations
from pathlib import Path
import sys
import tempfile
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox
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
from step_editor.step_io import _write_step
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 _first_shell_face(model: StepModel, thickness: float, tolerance: float) -> int:
candidates: list[tuple[int, int]] = []
for face_id in range(len(model.faces)):
info = model.feature_info(face_id)
if info.get("surface") != "plane":
continue
if info.get("shell_region_status") != "candidate":
continue
current = float(info.get("shell_thickness_estimate") or 0.0)
if abs(current - thickness) > tolerance:
continue
confidence_rank = {"high": 0, "medium": 1, "low": 2}.get(str(info.get("shell_confidence")), 3)
candidates.append((confidence_rank, face_id))
if not candidates:
raise SystemExit(f"no shell thickness candidate near {thickness:g}")
candidates.sort()
return candidates[0][1]
def _assert_noop_blocked(label: str, plan: dict[str, object]) -> None:
status = str(plan.get("status", ""))
message = str(plan.get("message", ""))
if status != "blocked":
raise SystemExit(f"{label} no-op plan was not blocked: status={status}, message={message}")
if not any(fragment in message for fragment in ("不需要修改", "无需移动", "为 0", "几乎相同")):
raise SystemExit(f"{label} no-op blocker did not explain unchanged target: {message}")
def _run_cube_face_noops() -> None:
model = StepModel.load(DEFAULT_MODEL)
face_id = _first_plane_face(model)
info = model.face_info(face_id)
center = info.get("area_center") or info.get("bbox_center")
if not isinstance(center, tuple) or len(center) != 3:
raise SystemExit("plane Face center is missing")
area = float(info.get("area") or 0.0)
width = float(info.get("local_face_width") or 0.0)
height = float(info.get("local_face_height") or 0.0)
_assert_noop_blocked("Face push/pull distance", model.push_pull_plan(face_id, 0.0))
_assert_noop_blocked("Face offset current face", model.face_plane_offset_local_plan(face_id, 0.0))
_assert_noop_blocked("Face offset owning feature", model.face_plane_offset_owning_translation_plan(face_id, 0.0))
_assert_noop_blocked("Face center current face", model.face_center_local_move_plan(face_id, center))
_assert_noop_blocked("Face center owning feature", model.face_center_owning_translation_plan(face_id, center))
_assert_noop_blocked("Face area current face", model.face_area_local_resize_plan(face_id, area))
_assert_noop_blocked("Face area owning feature", model.face_area_scale_plan(face_id, area))
_assert_noop_blocked("Face width current face", model.face_size_local_resize_plan(face_id, width, "width"))
_assert_noop_blocked("Face width owning feature", model.face_size_owning_scale_plan(face_id, width, "width"))
_assert_noop_blocked("Face height current face", model.face_size_local_resize_plan(face_id, height, "height"))
_assert_noop_blocked("Face height owning feature", model.face_size_owning_scale_plan(face_id, height, "height"))
def _run_shell_noops() -> None:
with tempfile.TemporaryDirectory(prefix="geom_param_face_noop_shell_") as temp_dir:
model_path = Path(temp_dir) / "plate.step"
_write_step(BRepPrimAPI_MakeBox(30.0, 20.0, 2.0).Shape(), model_path)
model = StepModel.load(model_path)
face_id = _first_shell_face(model, 2.0, 2e-4)
current = float(model.feature_info(face_id).get("shell_thickness_estimate") or 0.0)
_assert_noop_blocked("thin wall current face", model.shell_thickness_plan(face_id, current))
_assert_noop_blocked("thin wall owning feature", model.shell_thickness_owning_scale_plan(face_id, current))
def main() -> int:
_run_cube_face_noops()
_run_shell_noops()
print("Face no-op guards ok")
return 0
if __name__ == "__main__":
raise SystemExit(main())