from __future__ import annotations import tempfile import unittest from pathlib import Path from engine.cdsl_engine.runtime import rebuild_cdsl from engine.cdsl_engine.sketch_solver import resolve_profile def _spline_profile(sketch_id: str, z: float) -> dict: return { "id": sketch_id, "workplane": {"origin_mm": [0, 0, z], "x_dir": [1, 0, 0], "normal": [0, 0, 1]}, "profile": { "type": "analytic_contours", "contours": [{ "role": "outer", "closed": True, "segments": [{ "type": "bspline", "start": [0, 0], "end": [0, 0], "points": [[0, 0], [20, 0], [25, 10], [15, 18], [0, 10], [0, 0]], }], }], }, } class LoftGeometryTests(unittest.TestCase): def test_periodic_bspline_supports_centripetal_parameterization(self): sketch = { "id": "profile", "workplane": {"origin_mm": [0, 0, 0], "x_dir": [1, 0, 0], "normal": [0, 0, 1]}, "profile": {"type": "analytic_contours", "contours": [{ "role": "outer", "closed": True, "segments": [{ "type": "bspline", "periodic": True, "parameterization": "centripetal", "start": [0, 0], "end": [0, 0], "points": [[0, 0], [16, 0], [16, 9], [0, 9], [0, 0]], }], }]}, } resolved = resolve_profile(sketch) parameters = resolved["contour_regions_mm"][0]["outer"][0]["parameters"] self.assertEqual(parameters, [0.0, 4.0, 7.0, 11.0, 14.0]) def test_open_bspline_segment_can_close_with_other_contour_edges(self): cdsl = { "schema": "cad.cdsl.llm.v1", "schema_version": "1.1.0", "kind": "part", "part_id": "open-bspline-contour", "meta": {"unit": "mm"}, "geometry": {"sketches": [{ "id": "profile", "workplane": {"origin_mm": [0, 0, 0], "x_dir": [1, 0, 0], "normal": [0, 0, 1]}, "profile": {"type": "analytic_contours", "contours": [{ "role": "outer", "closed": True, "segments": [ {"type": "line", "start": [0, 0], "end": [0, 10]}, { "type": "bspline", "start": [0, 10], "end": [0, 0], "points": [[0, 10], [4, 10], [4, 0], [0, 0]], }, ], }]}, }]}, "features": [{ "id": "add", "atomic_id": "extrude_add_blind", "depends_on": [], "sketch_id": "profile", "params": {"distance_mm": 5}, }], } with tempfile.TemporaryDirectory() as tmp: rebuilt = rebuild_cdsl(cdsl, Path(tmp) / "open-bspline-contour.step") self.assertGreater(rebuilt["volume_mm3"], 1.0) def test_reversed_bspline_transports_the_parameter_domain(self): sketch = { "id": "profile", "workplane": {"origin_mm": [0, 0, 0], "x_dir": [1, 0, 0], "normal": [0, 0, 1]}, "profile": {"type": "analytic_contours", "contours": [{ "role": "outer", "closed": True, "segments": [ {"type": "line", "start": [0, 0], "end": [0, 4]}, { "type": "bspline", "start": [3, 0], "end": [0, 4], "points": [[3, 0], [3, 2], [1, 4], [0, 4]], "parameters": [0, 2, 4, 6], "start_tangent": [2, 0], "end_tangent": [0, -3], }, {"type": "line", "start": [3, 0], "end": [0, 0]}, ], }]}, } resolved = resolve_profile(sketch) spline = next(edge for edge in resolved["contour_regions_mm"][0]["outer"] if edge["type"] == "bspline") self.assertEqual(spline["points_mm"], [[0.0, 4.0, 0.0], [1.0, 4.0, 0.0], [3.0, 2.0, 0.0], [3.0, 0.0, 0.0]]) self.assertEqual(spline["parameters"], [0.0, 2.0, 4.0, 6.0]) self.assertEqual(spline["start_tangent_mm"], [0.0, 3.0, 0.0]) self.assertEqual(spline["end_tangent_mm"], [-2.0, 0.0, 0.0]) def test_bspline_loft_and_mirror_replay_produce_step(self): cdsl = { "schema": "cad.cdsl.llm.v1", "schema_version": "1.1.0", "kind": "part", "part_id": "bspline-loft-mirror", "meta": {"unit": "mm"}, "geometry": {"sketches": [_spline_profile("lower", 0), _spline_profile("upper", 20)]}, "features": [ { "id": "mirror_plane", "atomic_id": "reference_plane", "depends_on": [], "params": {"plane": {"origin_mm": [35, 0, 0], "x_dir": [0, 1, 0], "normal": [1, 0, 0]}}, "execution_status": "supported", }, { "id": "loft", "atomic_id": "loft_add", "depends_on": [], "params": {"profile_sketch_ids": ["lower", "upper"]}, "execution_status": "supported", }, { "id": "mirror", "atomic_id": "pattern_mirror", "depends_on": ["mirror_plane", "loft"], "params": { "source_feature_ids": ["loft"], "mirror_plane": { "kind": "plane", "owner_feature_id": "mirror_plane", "stable_id": "mirror-plane", "source": "runtime_snapshot", "confidence": 1.0, }, }, "selectors": [{ "kind": "plane", "owner_feature_id": "mirror_plane", "stable_id": "mirror-plane", "source": "runtime_snapshot", "confidence": 1.0, }], "execution_status": "supported", }, ], } with tempfile.TemporaryDirectory() as tmp: rebuilt = rebuild_cdsl(cdsl, Path(tmp) / "loft.step") self.assertGreater(rebuilt["volume_mm3"], 1.0) self.assertEqual(rebuilt["solid_count"], 2) self.assertEqual([item["feature_id"] for item in rebuilt["feature_results"]], ["mirror_plane", "loft", "mirror.m.loft", "mirror"]) if __name__ == "__main__": unittest.main()