feat(cadfs): expand selector provenance coverage
This commit is contained in:
@@ -6,7 +6,13 @@ from pathlib import Path
|
||||
|
||||
from cadfs_to_cdsl.dataset import Sample
|
||||
from cadfs_to_cdsl.reports import read_json
|
||||
from cadfs_to_cdsl.selector_candidate_demo import _search_candidate_records, run_geometry_probe, strip_provenance_intents
|
||||
from cadfs_to_cdsl.selector_candidate_demo import (
|
||||
_query_candidate_groups,
|
||||
_search_candidate_records,
|
||||
_strip_selector_search_tokens,
|
||||
run_geometry_probe,
|
||||
strip_provenance_intents,
|
||||
)
|
||||
|
||||
|
||||
def _contains_selector_intent(value: object) -> bool:
|
||||
@@ -18,6 +24,39 @@ def _contains_selector_intent(value: object) -> bool:
|
||||
|
||||
|
||||
class SelectorCandidateDemoTests(unittest.TestCase):
|
||||
@staticmethod
|
||||
def _query_group_candidate(query_family: str, source_entity: str | None = None, source_entities: list[str] | None = None) -> dict:
|
||||
intent = {
|
||||
"version": "1.0",
|
||||
"kind": "edge" if query_family == "SWEPT_EDGE" else "face",
|
||||
"query_family": query_family,
|
||||
"source_query": {"ast": {"call": "makeQuery", "args": ["owner", query_family]}},
|
||||
"derivation_policy": {"allowed": ["boundary"], "multiplicity": "all_fragments" if query_family == "SWEPT_FACE" else "one"},
|
||||
}
|
||||
if source_entity is not None:
|
||||
intent["source_entity"] = {"sketch_id": "S", "entity_id": source_entity}
|
||||
if source_entities is not None:
|
||||
intent["source_entities"] = [{"sketch_id": "S", "entity_id": entity_id} for entity_id in source_entities]
|
||||
return {"kind": intent["kind"], "owner_feature_id": "f_extrude", "selector_intent": intent}
|
||||
|
||||
def _query_group_provenance(self, selector: dict) -> dict:
|
||||
return {
|
||||
"geometry": {
|
||||
"sketches": [{
|
||||
"id": "sketch_S", "source_sketch_id": "S",
|
||||
"workplane": {"origin_mm": [0, 0, 0], "x_dir": [1, 0, 0], "normal": [0, 0, 1]},
|
||||
"profile": {"type": "planar_imprint", "source_entities": [
|
||||
{"id": "E1", "curve": {"type": "line", "start": [0, 0], "end": [3, 0]}},
|
||||
{"id": "E2", "curve": {"type": "line", "start": [3, 0], "end": [3, 2]}},
|
||||
]},
|
||||
}],
|
||||
},
|
||||
"features": [
|
||||
{"id": "f_extrude", "atomic_id": "extrude_add_blind", "sketch_id": "sketch_S", "params": {"distance_mm": 5}},
|
||||
{"id": "f_consumer", "selectors": [selector]},
|
||||
],
|
||||
}
|
||||
|
||||
def test_search_candidates_excludes_records_below_normal_resolution_threshold(self) -> None:
|
||||
resolution = type("Resolution", (), {
|
||||
"candidates": (
|
||||
@@ -34,11 +73,85 @@ class SelectorCandidateDemoTests(unittest.TestCase):
|
||||
def test_strip_provenance_intents_removes_nested_selector_metadata(self) -> None:
|
||||
value = {
|
||||
"selector_intent": {"version": "1.0"},
|
||||
"output_role": "extrude.end",
|
||||
"output_role_source": {"owner_feature_id": "f0", "output_role": "extrude.end"},
|
||||
"params": {"reference": {"selector_intent_version": "1.0"}},
|
||||
}
|
||||
self.assertEqual(strip_provenance_intents(value), 2)
|
||||
self.assertEqual(value, {"params": {"reference": {}}})
|
||||
|
||||
def test_query_group_keeps_all_ranked_swept_face_fragments_together(self) -> None:
|
||||
selector = self._query_group_candidate("SWEPT_FACE", source_entity="E1")
|
||||
provenance = self._query_group_provenance(selector)
|
||||
resolution = type("Resolution", (), {"candidates": (
|
||||
{"record_id": "fragment-a", "score": 1.0, "geometry": {"surface_type": "plane", "plane_normal": [0, -1, 0], "plane_offset_mm": 0}},
|
||||
{"record_id": "fragment-b", "score": 1.0, "geometry": {"surface_type": "plane", "plane_normal": [0, 1, 0], "plane_offset_mm": 0}},
|
||||
{"record_id": "wrong-wall", "score": 1.0, "geometry": {"surface_type": "plane", "plane_normal": [1, 0, 0], "plane_offset_mm": 3}},
|
||||
)})()
|
||||
descriptor, groups, count = _query_candidate_groups(
|
||||
provenance, "f_consumer:selectors[0]", selector, resolution, maximum=8,
|
||||
)
|
||||
self.assertEqual(count, 1)
|
||||
self.assertEqual(descriptor["ranking_status"], "source_geometry_ranked")
|
||||
self.assertEqual(descriptor["multiplicity"], "all_fragments")
|
||||
self.assertEqual([record["record_id"] for record in groups[0]["records"]], ["fragment-a", "fragment-b"])
|
||||
self.assertEqual(groups[0]["ranking"]["method"], "all_fragments_source_geometry")
|
||||
|
||||
def test_query_group_ranks_the_source_pair_vertical_edge(self) -> None:
|
||||
selector = self._query_group_candidate("SWEPT_EDGE", source_entities=["E1", "E2"])
|
||||
provenance = self._query_group_provenance(selector)
|
||||
resolution = type("Resolution", (), {"candidates": (
|
||||
{"record_id": "source-vertex", "score": 1.0, "geometry": {"curve_type": "line", "start_mm": [3, 0, 0], "end_mm": [3, 0, 5]}},
|
||||
{"record_id": "other-vertex", "score": 1.0, "geometry": {"curve_type": "line", "start_mm": [0, 0, 0], "end_mm": [0, 0, 5]}},
|
||||
)})()
|
||||
descriptor, groups, count = _query_candidate_groups(
|
||||
provenance, "f_consumer:selectors[0]", selector, resolution, maximum=8,
|
||||
)
|
||||
self.assertEqual(count, 1)
|
||||
self.assertEqual(descriptor["query_family"], "SWEPT_EDGE")
|
||||
self.assertEqual(groups[0]["records"][0]["record_id"], "source-vertex")
|
||||
self.assertEqual(groups[0]["ranking"]["method"], "source_pair_extrusion_vertex")
|
||||
|
||||
def test_query_group_ranks_the_line_arc_intersection_edge(self) -> None:
|
||||
selector = self._query_group_candidate("SWEPT_EDGE", source_entities=["E1", "E2"])
|
||||
provenance = self._query_group_provenance(selector)
|
||||
provenance["geometry"]["sketches"][0]["profile"]["source_entities"][0]["curve"] = {
|
||||
"type": "arc", "start": [-1, 0], "end": [1, 0], "center": [0, 0], "radius_mm": 1, "clockwise": True,
|
||||
}
|
||||
provenance["geometry"]["sketches"][0]["profile"]["source_entities"][1]["curve"] = {
|
||||
"type": "line", "start": [0, -2], "end": [0, 2],
|
||||
}
|
||||
resolution = type("Resolution", (), {"candidates": (
|
||||
{"record_id": "arc-line-intersection", "score": 1.0, "geometry": {"curve_type": "line", "start_mm": [0, 1, 0], "end_mm": [0, 1, 5]}},
|
||||
{"record_id": "unrelated-vertical", "score": 1.0, "geometry": {"curve_type": "line", "start_mm": [0, -1, 0], "end_mm": [0, -1, 5]}},
|
||||
)})()
|
||||
_descriptor, groups, count = _query_candidate_groups(
|
||||
provenance, "f_consumer:selectors[0]", selector, resolution, maximum=8,
|
||||
)
|
||||
self.assertEqual(count, 1)
|
||||
self.assertEqual(groups[0]["records"][0]["record_id"], "arc-line-intersection")
|
||||
|
||||
def test_query_group_ignores_a_candidate_missing_cylinder_axis_evidence(self) -> None:
|
||||
selector = self._query_group_candidate("SWEPT_FACE", source_entity="E1")
|
||||
provenance = self._query_group_provenance(selector)
|
||||
provenance["geometry"]["sketches"][0]["profile"]["source_entities"][0]["curve"] = {
|
||||
"type": "arc", "start": [-1, 0], "end": [1, 0], "center": [0, 0], "radius_mm": 1, "clockwise": True,
|
||||
}
|
||||
resolution = type("Resolution", (), {"candidates": (
|
||||
{"record_id": "missing-axis", "score": 1.0, "geometry": {"surface_type": "cylinder", "radius_mm": 1}},
|
||||
)})()
|
||||
descriptor, groups, count = _query_candidate_groups(
|
||||
provenance, "f_consumer:selectors[0]", selector, resolution, maximum=8,
|
||||
)
|
||||
self.assertEqual(count, 1)
|
||||
self.assertEqual(descriptor["ranking_status"], "source_geometry_unavailable")
|
||||
self.assertEqual(groups[0]["records"][0]["record_id"], "missing-axis")
|
||||
|
||||
def test_experiment_search_tokens_are_not_persisted(self) -> None:
|
||||
value = {"selectors": [{"_selector_search_token": "f:selectors[0]"}]}
|
||||
self.assertEqual(_strip_selector_search_tokens(value), 1)
|
||||
self.assertEqual(value, {"selectors": [{}]})
|
||||
|
||||
def test_geometry_probe_keeps_heuristic_success_separate_from_provenance(self) -> None:
|
||||
root = Path(__file__).parents[2] / "data/cadfs-sample/CADFS_test"
|
||||
feature = root / "featurescript_rp/0000/00002243.txt"
|
||||
|
||||
Reference in New Issue
Block a user