refactor(cdsl_engine): executor registry + per-family executor package
Phase 3 of the decoupling refactor (behavior-preserving): - registry.py: atomic_executor decorator, ALL_ATOMIC_IDS with fail-fast registration validation, execute_node dispatcher - executors/: one module per family (extrude, revolve, surfaces, loft_sweep, bodies, context, primitives, parametric, holes, dressup, patterns) + shared helpers in executors/common - executors/__init__: explicit aggregation + completeness check (registry must cover every declared atomic id at import time) - runtime.py: slimmed to entry points (analyze_cdsl/rebuild_cdsl) plus full historical re-exports incl. test-referenced privates Adding an atomic operation now touches only one executor module and its schema contract; the shared registry never changes. Verified against baseline: zero new failures.
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
"""Surface-feature executors (extrude_surface / revolve_surface).
|
||||
|
||||
Surface features register an independent shell and never touch the active
|
||||
solid body's fuse/cut lifecycle.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from ..extents import _normal_from_sketch
|
||||
from ..registry import atomic_executor
|
||||
from ..specs import AxisSpec, PlaneSpec, vector_cross, vector_dot, vector_scale, vector_unit
|
||||
from ..topology import FeaturePlanNode, FeatureResult
|
||||
from .common import _revolve_axis, _validate_revolve_axis_in_sketch_plane
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover - import for type checkers only
|
||||
from ..session import ExecutionSession
|
||||
|
||||
|
||||
def _execute_revolve_surface(node: FeaturePlanNode, session: "ExecutionSession") -> FeatureResult:
|
||||
# Surface revolve 的 profile 是单一闭合 wire。它只生成独立 shell,不能参与
|
||||
# 当前实体 body 的 fuse/cut,也不能把其结果误报为新的实体 body。
|
||||
sketch = session.sketches.get(str(node.sketch_id))
|
||||
if sketch is None:
|
||||
raise ValueError("surface revolve has no resolved sketch")
|
||||
faces = session.adapter.faces_for_sketch(sketch)
|
||||
if len(faces) != 1 or faces[0].inner_wires():
|
||||
raise ValueError("surface revolve requires exactly one closed profile without holes")
|
||||
axis = _revolve_axis(node, session)
|
||||
_validate_revolve_axis_in_sketch_plane(axis, sketch)
|
||||
angle = float(node.params.get("angle_deg") or 0.0)
|
||||
if angle <= 0:
|
||||
raise ValueError("surface revolve requires angle_deg > 0")
|
||||
if bool(node.params.get("reverse")):
|
||||
angle = -angle
|
||||
surface_id = session.register_surface(
|
||||
node.feature_id,
|
||||
session.adapter.revolve_surface(faces[0].outer_wire(), angle, axis),
|
||||
)
|
||||
return session.result(node, include_body=False, surface_id=surface_id)
|
||||
|
||||
|
||||
@atomic_executor("revolve_surface")
|
||||
def _revolve_surface_executor(node: FeaturePlanNode, session: "ExecutionSession", sketch: dict[str, Any] | None) -> FeatureResult:
|
||||
del sketch
|
||||
return _execute_revolve_surface(node, session)
|
||||
|
||||
|
||||
def _execute_extrude_surface(node: FeaturePlanNode, session: "ExecutionSession") -> FeatureResult:
|
||||
# surfaceEntities 的曲面拉伸沿用实体特征已 lower 的距离,但始终独立登记为
|
||||
# shell。它既不改变 active solid,也不以曲面参与实体 fuse/cut。
|
||||
sketch = session.sketches.get(str(node.sketch_id))
|
||||
if sketch is None:
|
||||
raise ValueError("surface extrude has no resolved sketch")
|
||||
direction = vector_unit(_normal_from_sketch(sketch), field_name="sketch normal")
|
||||
if bool(node.params.get("reverse")):
|
||||
direction = vector_scale(direction, -1)
|
||||
distance = float(node.params.get("distance_mm") or 0.0)
|
||||
if distance <= 0:
|
||||
raise ValueError("surface extrude requires distance_mm > 0")
|
||||
wires = session.adapter.surface_wires_for_sketch(sketch)
|
||||
surface = session.adapter.extrude_surface(wires, vector_scale(direction, distance))
|
||||
reverse_distance = float(node.params.get("reverse_distance_mm") or 0.0)
|
||||
if reverse_distance > 0:
|
||||
opposite = session.adapter.extrude_surface(wires, vector_scale(direction, -reverse_distance))
|
||||
surface = session.adapter.combine_surfaces(surface, opposite)
|
||||
surface_id = session.register_surface(node.feature_id, surface)
|
||||
return session.result(node, include_body=False, surface_id=surface_id)
|
||||
|
||||
|
||||
@atomic_executor("extrude_surface")
|
||||
def _extrude_surface_executor(node: FeaturePlanNode, session: "ExecutionSession", sketch: dict[str, Any] | None) -> FeatureResult:
|
||||
del sketch
|
||||
return _execute_extrude_surface(node, session)
|
||||
Reference in New Issue
Block a user