142 lines
5.7 KiB
Python
142 lines
5.7 KiB
Python
"""TDD coverage for the remaining structural 2.0 items."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import unittest
|
|
import simplecadapi as scad
|
|
from simplecadapi.graph import GraphSession
|
|
|
|
|
|
class TestRemainingStructuralKernel(unittest.TestCase):
|
|
def test_curve_builders_return_ocp_wrapped_shapes(self):
|
|
shapes = [
|
|
scad.make_line_redge((0, 0, 0), (1, 0, 0)),
|
|
scad.make_circle_redge((0, 0, 0), 1.0),
|
|
scad.make_three_point_arc_redge((0, 0, 0), (1, 1, 0), (2, 0, 0)),
|
|
scad.make_angle_arc_redge((0, 0, 0), 1.0, 0.0, 1.57),
|
|
scad.make_spline_redge(
|
|
control_points=[(0, 0, 0), (0.6, 1, 0), (1.4, 1, 0), (2, 0, 0)]
|
|
),
|
|
scad.make_helix_rwire(1.0, 3.0, 0.5),
|
|
]
|
|
for shape in shapes:
|
|
self.assertTrue(hasattr(shape, "wrapped"))
|
|
self.assertFalse(hasattr(shape, "cq_edge"))
|
|
self.assertFalse(hasattr(shape, "cq_wire"))
|
|
|
|
def test_loft_sweep_and_helical_sweep_do_not_depend_on_cadquery_feature_builders(
|
|
self,
|
|
):
|
|
rect1 = scad.make_rectangle_rwire(2.0, 2.0, center=(0, 0, 0))
|
|
rect2 = scad.make_rectangle_rwire(1.0, 1.0, center=(0, 0, 2.0))
|
|
profile = scad.make_circle_rface((0, 0, 0), 0.5)
|
|
path = scad.make_segment_rwire((0, 0, 0), (0, 0, 3.0))
|
|
helix_profile = scad.make_rectangle_rwire(0.4, 0.2)
|
|
|
|
loft = scad.loft_rsolid([rect1, rect2])
|
|
sweep = scad.sweep_rsolid(profile, path)
|
|
helical = scad.helical_sweep_rsolid(
|
|
helix_profile, pitch=1.0, height=2.0, radius=1.0
|
|
)
|
|
for solid in (loft, sweep, helical):
|
|
self.assertIsInstance(solid, scad.Solid)
|
|
self.assertTrue(hasattr(solid, "wrapped"))
|
|
self.assertFalse(hasattr(solid, "cq_solid"))
|
|
|
|
|
|
class TestRemainingStructuralSemanticAndFrame(unittest.TestCase):
|
|
def test_semantic_delta_uses_higher_level_entity_types(self):
|
|
with GraphSession() as session:
|
|
face = scad.make_circle_rface((0, 0, 0), 2.0)
|
|
scad.extrude_rsolid(face, (0, 0, 1), 3.0)
|
|
|
|
nodes = session.graph.topological_order()
|
|
created_entity_types = {
|
|
ref.entity_type
|
|
for node in nodes
|
|
if node.semantic_delta is not None
|
|
for ref in node.semantic_delta.created
|
|
}
|
|
self.assertIn("Sketch", created_entity_types)
|
|
self.assertIn("Feature", created_entity_types)
|
|
self.assertNotEqual(created_entity_types, {"ShapeOutput"})
|
|
|
|
def test_graph_session_owns_independent_frame_graph(self):
|
|
with GraphSession() as session:
|
|
with scad.SimpleWorkplane(origin=(1.0, 2.0, 3.0)):
|
|
scad.make_point_rvertex(1.0, 0.0, 0.0)
|
|
|
|
self.assertTrue(hasattr(session, "frame_graph"))
|
|
self.assertGreaterEqual(session.frame_graph.node_count, 1)
|
|
|
|
def test_session_and_model_export_include_frame_graph(self):
|
|
with GraphSession() as session:
|
|
with scad.SimpleWorkplane(origin=(1.0, 2.0, 3.0)):
|
|
scad.make_point_rvertex(1.0, 0.0, 0.0)
|
|
|
|
session_payload = scad.import_session_json(scad.export_session_json(session))
|
|
self.assertIn("frame_graph", session_payload)
|
|
self.assertGreaterEqual(session_payload["frame_graph"].node_count, 1)
|
|
|
|
model_payload = scad.import_model_json(scad.export_model_json(session))
|
|
self.assertIn("frame_graph", model_payload)
|
|
self.assertGreaterEqual(model_payload["frame_graph"].node_count, 1)
|
|
|
|
raw_model = json.loads(scad.export_model_json(session))
|
|
self.assertIn("frame_graph", raw_model)
|
|
self.assertGreaterEqual(len(raw_model["frame_graph"]["nodes"]), 1)
|
|
|
|
def test_model_export_includes_semantic_entity_registry_for_sketch_and_feature(
|
|
self,
|
|
):
|
|
with GraphSession() as session:
|
|
face = scad.make_circle_rface((0.0, 0.0, 0.0), 2.0)
|
|
scad.extrude_rsolid(face, (0.0, 0.0, 1.0), 3.0)
|
|
|
|
raw = json.loads(scad.export_model_json(session))
|
|
self.assertIn("semantic_entity_registry", raw)
|
|
entity_types = {item["entity_type"] for item in raw["semantic_entity_registry"]}
|
|
self.assertIn("Sketch", entity_types)
|
|
self.assertIn("Feature", entity_types)
|
|
self.assertNotIn("AssemblyConstraint", entity_types)
|
|
|
|
|
|
class TestHelicalSweepMacroRecording(unittest.TestCase):
|
|
def test_helical_sweep_expands_to_helix_plus_sweep_nodes(self):
|
|
with GraphSession() as session:
|
|
profile = scad.make_rectangle_rwire(0.4, 0.2)
|
|
result = scad.helical_sweep_rsolid(
|
|
profile, pitch=1.0, height=2.0, radius=1.0
|
|
)
|
|
|
|
self.assertIsInstance(result, scad.Solid)
|
|
ops = [node.op for node in session.graph.topological_order()]
|
|
self.assertIn("make_helix_redge", ops)
|
|
self.assertIn("make_wire_from_edges_rwire", ops)
|
|
self.assertIn("make_sweep_rsolid", ops)
|
|
self.assertNotIn("helical_sweep", ops)
|
|
|
|
def test_helical_sweep_roundtrip_replays_as_macro_graph(self):
|
|
with GraphSession() as session:
|
|
profile = scad.make_rectangle_rwire(0.4, 0.2)
|
|
swept = scad.helical_sweep_rsolid(
|
|
profile, pitch=1.0, height=2.0, radius=1.0
|
|
)
|
|
|
|
restored = scad.import_graph_json(scad.export_graph_json(session.graph))
|
|
ops = [node.op for node in restored.topological_order()]
|
|
|
|
self.assertIn("make_helix_redge", ops)
|
|
self.assertIn("make_wire_from_edges_rwire", ops)
|
|
self.assertIn("make_sweep_rsolid", ops)
|
|
self.assertNotIn("helical_sweep", ops)
|
|
|
|
replayed = scad.replay_graph(restored)
|
|
self.assertEqual(len(replayed), 1)
|
|
self.assertAlmostEqual(replayed[0].get_volume(), swept.get_volume(), places=4)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|