feat: integrate SimpleCADAPI 2.0.2 CAD workflows

This commit is contained in:
Jerry
2026-08-03 11:17:05 +08:00
parent b5738e9109
commit c3a0f269b7
481 changed files with 110229 additions and 12826 deletions
+82
View File
@@ -2,6 +2,7 @@ import unittest
import simplecadapi as scad
from simplecadapi import ql as Q
from simplecadapi import tagging
class TestQLTagPredicates(unittest.TestCase):
@@ -23,6 +24,30 @@ class TestQLTagPredicates(unittest.TestCase):
self.assertTrue(Q.tag("face.top")(top_face))
self.assertTrue(Q.tag("face.*")(top_face))
def test_tag_scope_serializes_and_roundtrips(self):
predicate = Q.tag("role.mounting_surface", scope="inherited")
payload = predicate.to_dict()
restored = Q.SerializablePredicate.from_dict(payload)
self.assertEqual(payload["kind"], "tag")
self.assertEqual(payload["data"]["scope"], "inherited")
self.assertEqual(restored.to_dict(), payload)
def test_tag_scope_evaluates_explicit_downward_inheritance(self):
box = scad.make_box_rsolid(1.0, 1.0, 1.0)
box._apply_user_tag("role.body", topology_propagation="downward")
face = box.get_faces(0)
self.assertFalse(Q.tag("role.body", scope="local")(face))
self.assertTrue(Q.tag("role.body", scope="inherited")(face))
self.assertTrue(Q.tag("role.body", scope="effective")(face))
def test_lineage_capability_error_is_not_swallowed(self):
vertex = scad.make_point_rvertex(0.0, 0.0, 0.0)
with self.assertRaises(tagging.UnsupportedQueryCapabilityError):
Q.tag("role.datum", scope="lineage")(vertex)
class TestQLMetadataPredicates(unittest.TestCase):
def test_meta_eq_and_compare(self):
@@ -229,6 +254,63 @@ class TestSerializableGeometrySelectors(unittest.TestCase):
edges = selector.resolve(result)
self.assertGreater(len(edges), 0)
def test_incident_face_query_selects_one_named_edge(self):
profile = scad.make_rectangle_rface(
4.0,
2.0,
tag_prefix="profile",
edge_tags=["bottom", "right", "top", "left"],
)
solid = scad.extrude_rsolid(
profile, (0, 0, 1), 3.0, tag_prefix="boss"
)
selector = (
Q.faces()
.where(Q.tag("boss.face.start"))
.boundary("edge")
.incident_to(
Q.faces().where(Q.tag("boss.face.start")),
Q.faces().where(Q.tag("boss.face.side.right")),
distinct=True,
)
.incident_face_count(exactly=2)
.exactly(1)
)
edges = selector.resolve(solid)
self.assertEqual(len(edges), 1)
restored = Q.selector_from_dict(selector.to_dict())
self.assertEqual(len(restored.resolve(solid)), 1)
def test_shared_boundary_intersection_uses_topology_identity(self):
solid = scad.make_cylinder_rsolid(2.0, 3.0, tag_prefix="shaft")
start = Q.faces().where(Q.tag("shaft.face.start"))
side = Q.faces().where(Q.tag("shaft.face.side"))
shared = start.shared_boundary(side).exactly(1)
self.assertEqual(len(shared.resolve(solid)), 1)
self.assertEqual(
len(Q.selector_from_dict(shared.to_dict()).resolve(solid)), 1
)
first = scad.make_cylinder_rsolid(2.0, 3.0, tag_prefix="first")
second = scad.make_cylinder_rsolid(2.0, 3.0, tag_prefix="second")
self.assertEqual(
Q.solids()
.where(Q.tag("first.solid"))
.shared_boundary(Q.solids().where(Q.tag("first.solid")))
.resolve(first),
first.get_edges(),
)
self.assertEqual(
len(
Q.solids()
.where(Q.tag("first.solid"))
.shared_boundary(Q.solids().where(Q.tag("second.solid")))
.resolve([first, second])
),
0,
)
def test_selector_exactly_enforces_cardinality(self):
box = scad.make_box_rsolid(1.0, 1.0, 1.0)
selector = (