[AutoTool/SimpleTool/BasicTool] Rename BasicTool->SimpleTool and remove transition handling. Export AutoTool and SimpleTool at top level.

This commit is contained in:
Jan Petykiewicz 2025-11-13 00:39:41 -08:00
parent 2bf44f334a
commit 639850ab29
3 changed files with 78 additions and 119 deletions

View File

@ -77,7 +77,8 @@ from .builder import (
Pather as Pather, Pather as Pather,
RenderPather as RenderPather, RenderPather as RenderPather,
RenderStep as RenderStep, RenderStep as RenderStep,
BasicTool as BasicTool, SimpleTool as SimpleTool,
AutoTool as AutoTool,
PathTool as PathTool, PathTool as PathTool,
) )
from .utils import ( from .utils import (

View File

@ -5,6 +5,7 @@ from .utils import ell as ell
from .tools import ( from .tools import (
Tool as Tool, Tool as Tool,
RenderStep as RenderStep, RenderStep as RenderStep,
BasicTool as BasicTool, SimpleTool as SimpleTool,
AutoTool as AutoTool,
PathTool as PathTool, PathTool as PathTool,
) )

View File

@ -223,7 +223,7 @@ class Tool:
self, self,
batch: Sequence[RenderStep], batch: Sequence[RenderStep],
*, *,
port_names: Sequence[str] = ('A', 'B'), # noqa: ARG002 (unused) port_names: tuple[str, str] = ('A', 'B'), # noqa: ARG002 (unused)
**kwargs, # noqa: ARG002 (unused) **kwargs, # noqa: ARG002 (unused)
) -> ILibrary: ) -> ILibrary:
""" """
@ -245,7 +245,7 @@ abstract_tuple_t = tuple[Abstract, str, str]
@dataclass @dataclass
class BasicTool(Tool, metaclass=ABCMeta): class SimpleTool(Tool, metaclass=ABCMeta):
""" """
A simple tool which relies on a single pre-rendered `bend` pattern, a function A simple tool which relies on a single pre-rendered `bend` pattern, a function
for generating straight paths, and a table of pre-rendered `transitions` for converting for generating straight paths, and a table of pre-rendered `transitions` for converting
@ -257,9 +257,6 @@ class BasicTool(Tool, metaclass=ABCMeta):
bend: abstract_tuple_t # Assumed to be clockwise bend: abstract_tuple_t # Assumed to be clockwise
""" `clockwise_bend_abstract, in_port_name, out_port_name` """ """ `clockwise_bend_abstract, in_port_name, out_port_name` """
transitions: dict[str, abstract_tuple_t]
""" `{ptype: (transition_abstract`, ptype_port_name, other_port_name), ...}` """
default_out_ptype: str default_out_ptype: str
""" Default value for out_ptype """ """ Default value for out_ptype """
@ -267,59 +264,18 @@ class BasicTool(Tool, metaclass=ABCMeta):
class LData: class LData:
""" Data for planL """ """ Data for planL """
straight_length: float straight_length: float
straight_kwargs: dict[str, Any]
ccw: SupportsBool | None ccw: SupportsBool | None
in_transition: abstract_tuple_t | None
out_transition: abstract_tuple_t | None
def path(
self,
ccw: SupportsBool | None,
length: float,
*,
in_ptype: str | None = None,
out_ptype: str | None = None,
port_names: tuple[str, str] = ('A', 'B'),
**kwargs,
) -> Library:
_out_port, data = self.planL(
ccw,
length,
in_ptype=in_ptype,
out_ptype=out_ptype,
)
gen_straight, sport_in, sport_out = self.straight
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'path')
pat.add_port_pair(names=port_names, ptype='unk' if in_ptype is None else in_ptype)
if data.in_transition:
ipat, iport_theirs, _iport_ours = data.in_transition
pat.plug(ipat, {port_names[1]: iport_theirs})
if not numpy.isclose(data.straight_length, 0):
straight_pat_or_tree = gen_straight(data.straight_length, **kwargs)
if isinstance(straight_pat_or_tree, Pattern):
straight = tree <= {SINGLE_USE_PREFIX + 'straight': straight_pat_or_tree}
else:
straight = tree <= straight_pat_or_tree
pat.plug(straight, {port_names[1]: sport_in})
if data.ccw is not None:
bend, bport_in, bport_out = self.bend
pat.plug(bend, {port_names[1]: bport_in}, mirrored=bool(ccw))
if data.out_transition:
opat, oport_theirs, oport_ours = data.out_transition
pat.plug(opat, {port_names[1]: oport_ours})
return tree
def planL( def planL(
self, self,
ccw: SupportsBool | None, ccw: SupportsBool | None,
length: float, length: float,
*, *,
in_ptype: str | None = None, in_ptype: str | None = None, # noqa: ARG002 (unused)
out_ptype: str | None = None, out_ptype: str | None = None, # noqa: ARG002 (unused)
**kwargs, # noqa: ARG002 (unused) **kwargs, # noqa: ARG002 (unused)
) -> tuple[Port, LData]: ) -> tuple[Port, LData]:
# TODO check all the math for L-shaped bends
if ccw is not None: if ccw is not None:
bend, bport_in, bport_out = self.bend bend, bport_in, bport_out = self.bend
@ -342,74 +298,38 @@ class BasicTool(Tool, metaclass=ABCMeta):
bend_dxy = numpy.zeros(2) bend_dxy = numpy.zeros(2)
bend_angle = pi bend_angle = pi
in_transition = self.transitions.get('unk' if in_ptype is None else in_ptype, None) if ccw is not None:
if in_transition is not None:
ipat, iport_theirs, iport_ours = in_transition
irot = ipat.ports[iport_theirs].rotation
assert irot is not None
itrans_dxy = rotation_matrix_2d(-irot) @ (
ipat.ports[iport_ours].offset
- ipat.ports[iport_theirs].offset
)
else:
itrans_dxy = numpy.zeros(2)
out_transition = self.transitions.get('unk' if out_ptype is None else out_ptype, None)
if out_transition is not None:
opat, oport_theirs, oport_ours = out_transition
orot = opat.ports[oport_ours].rotation
assert orot is not None
otrans_dxy = rotation_matrix_2d(-orot + bend_angle) @ (
opat.ports[oport_theirs].offset
- opat.ports[oport_ours].offset
)
else:
otrans_dxy = numpy.zeros(2)
if out_transition is not None:
out_ptype_actual = opat.ports[oport_theirs].ptype
elif ccw is not None:
out_ptype_actual = bend.ports[bport_out].ptype out_ptype_actual = bend.ports[bport_out].ptype
else: else:
out_ptype_actual = self.default_out_ptype out_ptype_actual = self.default_out_ptype
straight_length = length - bend_dxy[0] - itrans_dxy[0] - otrans_dxy[0] straight_length = length - bend_dxy[0]
bend_run = bend_dxy[1] + itrans_dxy[1] + otrans_dxy[1] bend_run = bend_dxy[1]
if straight_length < 0: if straight_length < 0:
raise BuildError( raise BuildError(
f'Asked to draw path with total length {length:,g}, shorter than required bends and transitions:\n' f'Asked to draw path with total length {length:,g}, shorter than required bends ({bend_dxy[0]:,})'
f'bend: {bend_dxy[0]:,g} in_trans: {itrans_dxy[0]:,g} out_trans: {otrans_dxy[0]:,g}'
) )
data = self.LData(straight_length, ccw, in_transition, out_transition) data = self.LData(straight_length, kwargs, ccw)
out_port = Port((length, bend_run), rotation=bend_angle, ptype=out_ptype_actual) out_port = Port((length, bend_run), rotation=bend_angle, ptype=out_ptype_actual)
return out_port, data return out_port, data
def render( def _renderL(
self, self,
batch: Sequence[RenderStep], data: LData,
*, tree: ILibrary,
port_names: Sequence[str] = ('A', 'B'), port_names: tuple[str, str],
append: bool = True, append: bool,
**kwargs, straight_kwargs: dict[str, Any],
) -> ILibrary: ) -> ILibrary:
"""
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'path') Render an L step into a preexisting tree
pat.add_port_pair(names=(port_names[0], port_names[1])) """
pat = tree.top_pattern()
gen_straight, sport_in, _sport_out = self.straight gen_straight, sport_in, _sport_out = self.straight
for step in batch:
data = step.data
assert step.tool == self
if step.opcode == 'L':
if data.in_transition:
ipat, iport_theirs, _iport_ours = data.in_transition
pat.plug(ipat, {port_names[1]: iport_theirs})
if not numpy.isclose(data.straight_length, 0): if not numpy.isclose(data.straight_length, 0):
straight_pat_or_tree = gen_straight(data.straight_length, **kwargs) straight_pat_or_tree = gen_straight(data.straight_length, **(straight_kwargs | data.straight_kwargs))
pmap = {port_names[1]: sport_in} pmap = {port_names[1]: sport_in}
if isinstance(straight_pat_or_tree, Pattern): if isinstance(straight_pat_or_tree, Pattern):
straight_pat = straight_pat_or_tree straight_pat = straight_pat_or_tree
@ -430,11 +350,47 @@ class BasicTool(Tool, metaclass=ABCMeta):
if data.ccw is not None: if data.ccw is not None:
bend, bport_in, bport_out = self.bend bend, bport_in, bport_out = self.bend
pat.plug(bend, {port_names[1]: bport_in}, mirrored=bool(data.ccw)) pat.plug(bend, {port_names[1]: bport_in}, mirrored=bool(data.ccw))
if data.out_transition:
opat, oport_theirs, oport_ours = data.out_transition
pat.plug(opat, {port_names[1]: oport_ours})
return tree return tree
def path(
self,
ccw: SupportsBool | None,
length: float,
*,
in_ptype: str | None = None,
out_ptype: str | None = None,
port_names: tuple[str, str] = ('A', 'B'),
**kwargs,
) -> Library:
_out_port, data = self.planL(
ccw,
length,
in_ptype = in_ptype,
out_ptype = out_ptype,
)
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'path')
pat.add_port_pair(names=port_names, ptype='unk' if in_ptype is None else in_ptype)
self._renderL(data=data, tree=tree, port_names=port_names, append=False, straight_kwargs=kwargs)
return tree
def render(
self,
batch: Sequence[RenderStep],
*,
port_names: tuple[str, str] = ('A', 'B'),
append: bool = True,
**kwargs,
) -> ILibrary:
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'path')
pat.add_port_pair(names=(port_names[0], port_names[1]))
for step in batch:
assert step.tool == self
if step.opcode == 'L':
self._renderL(data=step.data, tree=tree, port_names=port_names, append=append, straight_kwargs=kwargs)
return tree
@dataclass @dataclass
class AutoTool(Tool, metaclass=ABCMeta): class AutoTool(Tool, metaclass=ABCMeta):
@ -646,6 +602,7 @@ class AutoTool(Tool, metaclass=ABCMeta):
if data.b_transition: if data.b_transition:
pat.plug(data.b_transition.abstract, {port_names[1]: data.b_transition.our_port_name}) pat.plug(data.b_transition.abstract, {port_names[1]: data.b_transition.our_port_name})
if data.ccw is not None: if data.ccw is not None:
assert data.bend is not None
pat.plug(data.bend.abstract, {port_names[1]: data.bend.in_port_name}, mirrored=bool(data.ccw) == data.bend.clockwise) pat.plug(data.bend.abstract, {port_names[1]: data.bend.in_port_name}, mirrored=bool(data.ccw) == data.bend.clockwise)
if data.out_transition: if data.out_transition:
pat.plug(data.out_transition.abstract, {port_names[1]: data.out_transition.our_port_name}) pat.plug(data.out_transition.abstract, {port_names[1]: data.out_transition.our_port_name})
@ -677,7 +634,7 @@ class AutoTool(Tool, metaclass=ABCMeta):
self, self,
batch: Sequence[RenderStep], batch: Sequence[RenderStep],
*, *,
port_names: Sequence[str] = ('A', 'B'), port_names: tuple[str, str] = ('A', 'B'),
append: bool = True, append: bool = True,
**kwargs, **kwargs,
) -> ILibrary: ) -> ILibrary:
@ -793,7 +750,7 @@ class PathTool(Tool, metaclass=ABCMeta):
self, self,
batch: Sequence[RenderStep], batch: Sequence[RenderStep],
*, *,
port_names: Sequence[str] = ('A', 'B'), port_names: tuple[str, str] = ('A', 'B'),
**kwargs, # noqa: ARG002 (unused) **kwargs, # noqa: ARG002 (unused)
) -> ILibrary: ) -> ILibrary: