119 lines
5.5 KiB
Python
119 lines
5.5 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
import sys
|
|
import tempfile
|
|
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
if str(PROJECT_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(PROJECT_ROOT))
|
|
SCRIPTS_ROOT = PROJECT_ROOT / "scripts"
|
|
if str(SCRIPTS_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(SCRIPTS_ROOT))
|
|
|
|
from step_editor.model import StepModel
|
|
from verify_edge_coordinate_edit import _tuple3
|
|
from verify_edge_length_resize import _line_edge_ids_near_length
|
|
from verify_ellipse_edge_resize import _ellipse_edge_ids, _write_ellipse_face_model
|
|
from verify_hole_resize import _write_through_hole_model
|
|
|
|
|
|
DEFAULT_CUBE = PROJECT_ROOT / "assets" / "models" / "cube_10mm.step"
|
|
|
|
|
|
def _assert_blocked(plan: dict[str, object], label: str) -> None:
|
|
if str(plan.get("status") or "") != "blocked" or str(plan.get("risk") or "") != "blocked":
|
|
raise AssertionError(f"{label} should be blocked, got status={plan.get('status')}, plan={plan}")
|
|
message = str(plan.get("message") or plan.get("blockers") or "")
|
|
if not message.strip():
|
|
raise AssertionError(f"{label} should explain why it is blocked: {plan}")
|
|
|
|
|
|
def _cube_edge(model: StepModel) -> int:
|
|
edge_ids = _line_edge_ids_near_length(model, 10.0, 1e-5)
|
|
if not edge_ids:
|
|
raise AssertionError("cube has no 10mm line Edge")
|
|
return edge_ids[0]
|
|
|
|
|
|
def _verify_straight_edge_guards() -> None:
|
|
model = StepModel.load(DEFAULT_CUBE)
|
|
edge_id = _cube_edge(model)
|
|
info = model.edge_info(edge_id)
|
|
current_length = float(info.get("length") or 0.0)
|
|
start = _tuple3(info.get("start_point"), "edge start")
|
|
end = _tuple3(info.get("end_point"), "edge end")
|
|
center = _tuple3(info.get("length_center"), "edge center")
|
|
|
|
_assert_blocked(model.general_edge_length_plan(edge_id, current_length), "same Edge length")
|
|
_assert_blocked(model.general_edge_length_plan(edge_id, 0.0), "zero Edge length")
|
|
_assert_blocked(model.general_edge_length_plan(edge_id, -1.0), "negative Edge length")
|
|
_assert_blocked(model.edge_endpoint_move_plan(edge_id, "start", start), "same start point")
|
|
_assert_blocked(model.edge_endpoint_move_plan(edge_id, "end", end), "same end point")
|
|
_assert_blocked(model.edge_endpoint_move_plan(edge_id, "start", end), "collapsed endpoint")
|
|
_assert_blocked(model.edge_center_move_plan(edge_id, center), "same Edge center")
|
|
_assert_blocked(model.edge_fillet_plan(edge_id, 0.0), "zero Edge fillet radius")
|
|
_assert_blocked(model.edge_fillet_plan(edge_id, current_length * 0.45), "oversized Edge fillet radius")
|
|
_assert_blocked(model.edge_chamfer_plan(edge_id, 0.0), "zero Edge chamfer distance")
|
|
_assert_blocked(model.edge_chamfer_plan(edge_id, current_length * 0.45), "oversized Edge chamfer distance")
|
|
_assert_blocked(model.edge_asymmetric_chamfer_plan(edge_id, 0.0, 0.5), "zero asymmetric chamfer distance")
|
|
_assert_blocked(
|
|
model.edge_asymmetric_chamfer_plan(edge_id, current_length * 0.45, 0.5),
|
|
"oversized asymmetric chamfer distance",
|
|
)
|
|
_assert_blocked(model.edge_distance_angle_chamfer_plan(edge_id, 0.0, 45.0), "zero distance-angle chamfer")
|
|
_assert_blocked(model.edge_distance_angle_chamfer_plan(edge_id, 0.5, 0.0), "zero distance-angle angle")
|
|
_assert_blocked(model.edge_distance_angle_chamfer_plan(edge_id, 0.5, 90.0), "too large distance-angle angle")
|
|
print("straight Edge target guards ok")
|
|
|
|
|
|
def _verify_ellipse_guards() -> None:
|
|
with tempfile.TemporaryDirectory(prefix="geom_param_edge_guard_ellipse_") 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 AssertionError("ellipse model has no ellipse Edge")
|
|
edge_id = edge_ids[0]
|
|
info = model.edge_info(edge_id)
|
|
major = float(info.get("major_radius") or 0.0)
|
|
minor = float(info.get("minor_radius") or 0.0)
|
|
|
|
_assert_blocked(model.ellipse_edge_axis_radius_plan(edge_id, major, axis_kind="major"), "same ellipse major radius")
|
|
_assert_blocked(model.ellipse_edge_axis_radius_plan(edge_id, minor, axis_kind="minor"), "same ellipse minor radius")
|
|
_assert_blocked(model.ellipse_edge_axis_radius_plan(edge_id, 0.0, axis_kind="major"), "zero ellipse major radius")
|
|
_assert_blocked(model.ellipse_edge_axis_radius_plan(edge_id, -1.0, axis_kind="minor"), "negative ellipse minor radius")
|
|
print("ellipse Edge target guards ok")
|
|
|
|
|
|
def _verify_circular_axis_guard() -> None:
|
|
with tempfile.TemporaryDirectory(prefix="geom_param_edge_guard_circle_") as temp_dir:
|
|
model_path = Path(temp_dir) / "hole.step"
|
|
_write_through_hole_model(model_path)
|
|
model = StepModel.load(model_path)
|
|
for edge_id in range(len(model.edges)):
|
|
info = model.edge_info(edge_id)
|
|
if info.get("curve") != "circle":
|
|
continue
|
|
center = info.get("center")
|
|
if center is None:
|
|
continue
|
|
_assert_blocked(model.circular_edge_axis_move_plan(edge_id, center), "same circular Edge center")
|
|
print("circular Edge axis target guard ok")
|
|
return
|
|
raise AssertionError("hole model has no circular Edge with center")
|
|
|
|
|
|
def main() -> int:
|
|
_verify_straight_edge_guards()
|
|
_verify_ellipse_guards()
|
|
_verify_circular_axis_guard()
|
|
print("Edge target guard suite passed.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|