feat(cadfs): expand selector provenance coverage
This commit is contained in:
@@ -5,8 +5,8 @@ from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from ..registry import atomic_executor
|
||||
from ..topology import FeaturePlanNode, FeatureResult
|
||||
from .common import _sweep_path
|
||||
from ..topology import FeaturePlanNode, FeatureResult, TopologyRecord
|
||||
from .common import _apply_primary_tool, _sweep_path
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover - import for type checkers only
|
||||
from ..session import ExecutionSession
|
||||
@@ -66,13 +66,18 @@ def _execute_sweep_add(node: FeaturePlanNode, session: "ExecutionSession", sketc
|
||||
profile = sketch or session.sketches.get(str(node.sketch_id))
|
||||
if profile is None:
|
||||
raise ValueError("sweep has no resolved profile sketch")
|
||||
faces = session.adapter.faces_for_sketch(profile)
|
||||
faces, source_anchor_specs = session.adapter.faces_for_sketch_with_source_anchors(profile)
|
||||
if len(faces) != 1:
|
||||
raise ValueError("sweep requires exactly one closed profile region")
|
||||
solid, topology_delta = session.adapter.sweep_with_topology_delta(
|
||||
faces[0], _sweep_path(node, session),
|
||||
is_frenet=bool(node.params.get("is_frenet", False)),
|
||||
)
|
||||
if node.atomic_id == "sweep_cut":
|
||||
# The PipeShell is a transient cutting tool. Its own builder history
|
||||
# cannot become selector provenance after the BRepAlgoAPI_Cut; only
|
||||
# the cut's exact target-side delta may survive registration.
|
||||
return _apply_primary_tool(node, session, solid, cutting=True)
|
||||
is_new_body = node.params.get("result_mode") == "new_body"
|
||||
body = session.adapter.combine(session.body, solid) if is_new_body else session.adapter.fuse(session.body, solid)
|
||||
# A union rebuilds topology, so the pipe-shell builder cannot prove the
|
||||
@@ -80,10 +85,37 @@ def _execute_sweep_add(node: FeaturePlanNode, session: "ExecutionSession", sketc
|
||||
# subshape identity and may expose evidence for the new member.
|
||||
if session.body is not None and not is_new_body:
|
||||
topology_delta = None
|
||||
session.register_body(node.feature_id, body, replay_node=node, topology_delta=topology_delta)
|
||||
topology_anchors: list[TopologyRecord] = []
|
||||
if topology_delta is not None:
|
||||
for index, spec in enumerate(source_anchor_specs):
|
||||
kind = spec.get("kind")
|
||||
if kind not in {"edge", "vertex"} or spec.get("value") is None:
|
||||
continue
|
||||
source_entity = spec.get("source_entity")
|
||||
source_entities = tuple(spec.get("source_entities") or ())
|
||||
if not isinstance(source_entity, tuple) and not source_entities:
|
||||
continue
|
||||
topology_anchors.append(TopologyRecord(
|
||||
record_id=f"anchor:{node.feature_id}:{kind}:{index}",
|
||||
kind=kind,
|
||||
feature_id=node.feature_id,
|
||||
geometry={},
|
||||
value=spec["value"],
|
||||
source_entity=source_entity if isinstance(source_entity, tuple) else None,
|
||||
source_entities=source_entities,
|
||||
))
|
||||
session.register_body(
|
||||
node.feature_id, body, replay_node=node, topology_delta=topology_delta,
|
||||
topology_anchors=topology_anchors,
|
||||
)
|
||||
return session.result(node)
|
||||
|
||||
|
||||
@atomic_executor("sweep_add")
|
||||
def _sweep_executor(node: FeaturePlanNode, session: "ExecutionSession", sketch: dict[str, Any] | None) -> FeatureResult:
|
||||
return _execute_sweep_add(node, session, sketch)
|
||||
|
||||
|
||||
@atomic_executor("sweep_cut")
|
||||
def _sweep_cut_executor(node: FeaturePlanNode, session: "ExecutionSession", sketch: dict[str, Any] | None) -> FeatureResult:
|
||||
return _execute_sweep_add(node, session, sketch)
|
||||
|
||||
Reference in New Issue
Block a user