"""Extrusion executors (blind / two-sided / cut / through / from-face).""" from __future__ import annotations from typing import TYPE_CHECKING, Any from ..registry import atomic_executor from ..topology import FeaturePlanNode, FeatureResult from .common import _apply_primary_tool, _extruded_tool, _shape_from_primary if TYPE_CHECKING: # pragma: no cover - import for type checkers only from ..session import ExecutionSession @atomic_executor( "extrude_add_blind", "extrude_add_blind_with_hole", "extrude_add_two_sided", "extrude_cut_blind", "extrude_cut_two_sided", "extrude_cut_through", ) def _primary_executor(node: FeaturePlanNode, session: "ExecutionSession", sketch: dict[str, Any] | None) -> FeatureResult: return _shape_from_primary(node, session, sketch=sketch) def _execute_extrude_from_face(node: FeaturePlanNode, session: "ExecutionSession") -> FeatureResult: resolved = [session.resolve(selector) for selector in node.selectors] failed = next((item for item in resolved if item.status != "resolved"), None) if failed or len(resolved) != 1 or resolved[0].record is None or resolved[0].record.kind != "face": raise ValueError(failed.diagnostic.message if failed and failed.diagnostic else "derived profile face is unresolved") face = resolved[0].record.value tool, topology_delta = _extruded_tool(node, [face], session.adapter.face_normal(face), session) return _apply_primary_tool( node, session, tool, cutting=node.params.get("operation") == "cut", topology_delta=topology_delta, ) @atomic_executor("extrude_from_face") def _extrude_from_face_executor(node: FeaturePlanNode, session: "ExecutionSession", sketch: dict[str, Any] | None) -> FeatureResult: del sketch return _execute_extrude_from_face(node, session)