"""Parametric feature executors (thread / bend / gear / rack). Each executor parses its runtime-neutral spec from ``runtime_types`` specs, asks the geometry adapter to build and place the local-frame solid, then fuses it into the active body (or subtracts, for thread_cut). """ from __future__ import annotations from typing import TYPE_CHECKING, Any from ..registry import atomic_executor from ..specs import BendSpec, GearSpec, RackSpec, ThreadSpec from ..topology import FeaturePlanNode, FeatureResult, RuntimeDiagnostic from .common import _register_added_solid if TYPE_CHECKING: # pragma: no cover - import for type checkers only from ..session import ExecutionSession def _execute_thread(node: FeaturePlanNode, session: "ExecutionSession") -> FeatureResult: # 螺纹特征(thread_add)执行入口:按规格生成参数化螺纹段并并入当前主体。 # 1. 解析并校验尺寸/牙距/轴,非法输入抛出带具体原因的 ValueError。 spec = ThreadSpec.from_feature(node.atomic_id, node.params) # 2. 由适配器门面生成沿 spec.axis 放置的外螺纹实心段。 solid = session.adapter.thread_solid(spec) # 3. 与当前主体做布尔并(fuse)后登记为新主体,并返回该特征的结果对象。 _register_added_solid(session, node, solid) return session.result(node) def _execute_thread_cut(node: FeaturePlanNode, session: "ExecutionSession") -> FeatureResult: # 内螺纹(thread_cut)执行入口:ThreadSpec.from_feature 对 thread_cut 恒置 # internal=True,生成牙顶外放 INTERNAL_CUT_OVERLAP_MM 的切削刀具,沿 # spec.axis 放置后从当前主体布尔差出全深螺旋牙槽(宿主通常已预打光孔, # 刀具 core 落在孔腔中,仅外放的牙槽层切入孔壁)。 # 1. 解析并校验尺寸/牙距/轴,非法输入抛出带具体原因的 ValueError。 spec = ThreadSpec.from_feature(node.atomic_id, node.params) # 2. 由适配器门面生成沿 spec.axis 放置的内螺纹切削刀具实心段。 tool = session.adapter.thread_solid(spec) # 3. 从当前主体布尔差(cut)后登记为新主体,并返回该特征的结果对象。 session.register_body(node.feature_id, session.adapter.cut(session.body, tool), replay_node=node) return session.result(node) @atomic_executor("thread_add", "thread_cut") def _thread_executor(node: FeaturePlanNode, session: "ExecutionSession", sketch: dict[str, Any] | None) -> FeatureResult: # 螺纹特征(thread_add/thread_cut)不需要草图平面,丢弃该参数后执行。 # thread_cut 走布尔差分支:从已有主体切出内螺纹槽,而非并入外螺纹段。 del sketch if node.atomic_id == "thread_cut": return _execute_thread_cut(node, session) return _execute_thread(node, session) def _execute_bend(node: FeaturePlanNode, session: "ExecutionSession") -> FeatureResult: # 折弯特征(bend_add)执行入口:按规格生成等厚折弯板并并入当前主体。 # 1. 解析并校验板厚/宽度/折痕链与放置平面,非法输入抛出带具体原因的 ValueError。 spec = BendSpec.from_feature(node.params) # 2. 由适配器门面生成沿 spec.frame 放置的折弯实心段。 solid = session.adapter.bend_solid(spec) # 3. 与当前主体做布尔并(fuse)后登记为新主体,并返回该特征的结果对象。 _register_added_solid(session, node, solid) return session.result(node) @atomic_executor("bend_add") def _bend_executor(node: FeaturePlanNode, session: "ExecutionSession", sketch: dict[str, Any] | None) -> FeatureResult: # 折弯特征(bend_add)不需要草图平面,丢弃该参数后执行。 del sketch return _execute_bend(node, session) def _execute_gear(node: FeaturePlanNode, session: "ExecutionSession") -> FeatureResult: # 齿轮特征(gear_add)执行入口:按规格生成渐开线齿轮并入当前主体。 # 1. 解析并校验模数/齿数/齿宽/螺旋角与放置轴,非法输入抛出带具体原因的 ValueError。 spec = GearSpec.from_feature(node.params) # 2. 由适配器门面生成沿 spec.axis 放置的齿轮实体(直齿/斜齿/人字齿)。 solid = session.adapter.gear_solid(spec) # 3. 与当前主体做布尔并(fuse)后登记为新主体,并返回该特征的结果对象。 _register_added_solid(session, node, solid) # 4. 小齿数根切风险:不阻断执行,附加 info 级诊断供完成报告如实披露。 diagnostics: list[RuntimeDiagnostic] = [] if spec.teeth_count < 17: diagnostics.append(RuntimeDiagnostic( code="undercut_risk", message=( f"Gear with {spec.teeth_count} teeth and a 20 degree pressure angle is undercut-prone; " "standard involute geometry is generated without profile shift" ), feature_id=node.feature_id, )) return session.result(node, diagnostics=diagnostics) @atomic_executor("gear_add") def _gear_executor(node: FeaturePlanNode, session: "ExecutionSession", sketch: dict[str, Any] | None) -> FeatureResult: # 齿轮特征(gear_add)不需要草图平面,丢弃该参数后执行。 del sketch return _execute_gear(node, session) def _execute_rack(node: FeaturePlanNode, session: "ExecutionSession") -> FeatureResult: # 齿条特征(rack_add)执行入口:按规格生成直线齿条并入当前主体。 # 1. 解析并校验模数/齿数/厚度/压力角与放置轴,非法输入抛出带具体原因的 ValueError。 spec = RackSpec.from_feature(node.params) # 2. 由适配器门面生成沿 spec.axis 放置的齿条实体(齿沿轴方向伸出)。 solid = session.adapter.rack_solid(spec) # 3. 与当前主体做布尔并(fuse)后登记为新主体,并返回该特征的结果对象。 _register_added_solid(session, node, solid) return session.result(node) @atomic_executor("rack_add") def _rack_executor(node: FeaturePlanNode, session: "ExecutionSession", sketch: dict[str, Any] | None) -> FeatureResult: # 齿条特征(rack_add)不需要草图平面,丢弃该参数后执行。 del sketch return _execute_rack(node, session)