91 lines
3.9 KiB
Python
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())
|