Files
pythonocc-step-editor/scripts/verify_ellipse_edge_resize.py

91 lines
3.9 KiB
Python

from __future__ import annotations
import argparse
from pathlib import Path
import sys
import tempfile
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeFace, BRepBuilderAPI_MakeWire
from OCC.Core.gp import gp_Ax2, gp_Dir, gp_Elips, gp_Pnt
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
def _write_ellipse_face_model(path: Path) -> None:
edge = BRepBuilderAPI_MakeEdge(
gp_Elips(gp_Ax2(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)), 5.0, 2.0)
).Edge()
wire = BRepBuilderAPI_MakeWire(edge).Wire()
face = BRepBuilderAPI_MakeFace(wire).Face()
_write_step(face, path)
def _ellipse_edge_ids(model: StepModel) -> list[int]:
return [edge_id for edge_id in range(len(model.edges)) if model.edge_info(edge_id).get("curve") == "ellipse"]
def _run_case(axis_kind: str, target: float, expected_other: float, tolerance: float) -> None:
with tempfile.TemporaryDirectory(prefix=f"geom_param_ellipse_{axis_kind}_") as temp_dir:
model_path = Path(temp_dir) / "ellipse.step"
_write_ellipse_face_model(model_path)
model = StepModel.load(model_path)
edge_ids = _ellipse_edge_ids(model)
if not edge_ids:
raise SystemExit("no ellipse Edge was recognized")
edge_id = edge_ids[0]
before = model.stats()
plan = model.ellipse_edge_axis_radius_plan(edge_id, target, axis_kind=axis_kind)
if plan["status"] == "blocked":
raise SystemExit(f"{axis_kind} radius plan was blocked: {plan['message']}")
expected_strategy = f"ellipse-edge-{axis_kind}-axis-affine"
if plan.get("resize_strategy") != expected_strategy:
raise SystemExit(f"expected {expected_strategy}, got {plan.get('resize_strategy')}")
result = model.resize_ellipse_edge_axis_radius(edge_id, target, axis_kind=axis_kind)
after = model.stats()
sampled = model._ellipse_edge_axis_radius_sampled_result(plan)
if sampled is None:
raise SystemExit("could not sample the edited ellipse-like Edge")
verified_edge, value, other, error = sampled
other_error = abs(other - expected_other)
if error > tolerance:
raise SystemExit(f"{axis_kind} radius verification failed: target={target:g}, value={value:g}, error={error:g}")
if other_error > tolerance:
raise SystemExit(
f"{axis_kind} radius changed the other radius too much: expected={expected_other:g}, "
f"value={other:g}, error={other_error:g}"
)
print(f"mode={axis_kind}")
print(f"source_edge={edge_id}")
print(f"strategy={plan.get('resize_strategy')}")
print(f"before={before}")
print(f"after={after}")
print(f"verified_edge={verified_edge}")
print(f"target={target:.6f} value={value:.6f} error={error:.6g}")
print(f"other_radius={other:.6f} other_error={other_error:.6g}")
print(result.encode("ascii", "backslashreplace").decode("ascii"))
def main() -> int:
parser = argparse.ArgumentParser(description="Verify ellipse Edge major/minor radius resize operations.")
parser.add_argument("--mode", default="all", choices=["all", "major", "minor"])
parser.add_argument("--major-radius", type=float, default=7.5)
parser.add_argument("--minor-radius", type=float, default=3.0)
parser.add_argument("--tolerance", type=float, default=5e-3)
args = parser.parse_args()
if args.mode in {"all", "major"}:
_run_case("major", args.major_radius, expected_other=2.0, tolerance=args.tolerance)
if args.mode in {"all", "minor"}:
_run_case("minor", args.minor_radius, expected_other=5.0, tolerance=args.tolerance)
return 0
if __name__ == "__main__":
raise SystemExit(main())