[AutoTool] Use more dataclasses to clarify internal code
This commit is contained in:
parent
a62deb211c
commit
fe440b0c53
@ -443,28 +443,69 @@ class AutoTool(Tool, metaclass=ABCMeta):
|
|||||||
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
|
||||||
from non-native ptypes.
|
from non-native ptypes.
|
||||||
"""
|
"""
|
||||||
straights: list[tuple[str, Callable[[float], Pattern] | Callable[[float], Library], str, str, tuple[float, float]]]
|
|
||||||
# TODO add min length?
|
|
||||||
|
|
||||||
bends: list[abstract_tuple_t] # Assumed to be clockwise
|
@dataclass(frozen=True, slots=True)
|
||||||
""" `clockwise_bend_abstract, in_port_name, out_port_name` """
|
class Straight:
|
||||||
|
""" Description of a straight-path generator """
|
||||||
|
ptype: str
|
||||||
|
fn: Callable[[float], Pattern] | Callable[[float], Library]
|
||||||
|
in_port_name: str
|
||||||
|
out_port_name: str
|
||||||
|
length_range: tuple[float, float] = (0, numpy.inf)
|
||||||
|
|
||||||
transitions: dict[tuple[str, str], abstract_tuple_t]
|
@dataclass(frozen=True, slots=True)
|
||||||
""" `{(external_ptype, internal_ptype): (transition_abstract`, ptype_port_name, other_port_name), ...}` """
|
class Bend:
|
||||||
|
""" Description of a pre-rendered bend """
|
||||||
|
abstract: Abstract
|
||||||
|
in_port_name: str
|
||||||
|
out_port_name: str
|
||||||
|
clockwise: bool = True
|
||||||
|
|
||||||
default_out_ptype: str
|
@property
|
||||||
""" Default value for out_ptype """
|
def in_port(self) -> Port:
|
||||||
|
return self.abstract.ports[self.in_port_name]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def out_port(self) -> Port:
|
||||||
|
return self.abstract.ports[self.out_port_name]
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class Transition:
|
||||||
|
""" Description of a pre-rendered transition """
|
||||||
|
abstract: Abstract
|
||||||
|
our_port_name: str
|
||||||
|
their_port_name: str
|
||||||
|
|
||||||
|
@property
|
||||||
|
def our_port(self) -> Port:
|
||||||
|
return self.abstract.ports[self.our_port_name]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def their_port(self) -> Port:
|
||||||
|
return self.abstract.ports[self.their_port_name]
|
||||||
|
|
||||||
@dataclass(frozen=True, slots=True)
|
@dataclass(frozen=True, slots=True)
|
||||||
class LData:
|
class LData:
|
||||||
""" Data for planL """
|
""" Data for planL """
|
||||||
straight_length: float
|
straight_length: float
|
||||||
straight_tuple: tuple[str, Callable[[float], Pattern] | Callable[[float], Library], str, str]
|
straight: 'AutoTool.Straight'
|
||||||
ccw: SupportsBool | None
|
ccw: SupportsBool | None
|
||||||
bend_tuple: abstract_tuple_t | None
|
bend: 'AutoTool.Bend | None'
|
||||||
in_transition: abstract_tuple_t | None
|
in_transition: 'AutoTool.Transition | None'
|
||||||
b_transition: abstract_tuple_t | None
|
b_transition: 'AutoTool.Transition | None'
|
||||||
out_transition: abstract_tuple_t | None
|
out_transition: 'AutoTool.Transition | None'
|
||||||
|
|
||||||
|
straights: list[Straight]
|
||||||
|
""" List of straight-generators to choose from, in order of priority """
|
||||||
|
|
||||||
|
bends: list[Bend]
|
||||||
|
""" List of bends to choose from, in order of priority. """
|
||||||
|
|
||||||
|
transitions: dict[tuple[str, str], Transition]
|
||||||
|
""" `{(external_ptype, internal_ptype): Transition, ...}` """
|
||||||
|
|
||||||
|
default_out_ptype: str
|
||||||
|
""" Default value for out_ptype """
|
||||||
|
|
||||||
def path(
|
def path(
|
||||||
self,
|
self,
|
||||||
@ -483,45 +524,36 @@ class AutoTool(Tool, metaclass=ABCMeta):
|
|||||||
out_ptype = out_ptype,
|
out_ptype = out_ptype,
|
||||||
)
|
)
|
||||||
|
|
||||||
stype, gen_straight, sport_in, sport_out = data.straight_tuple
|
|
||||||
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'path')
|
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)
|
pat.add_port_pair(names=port_names, ptype='unk' if in_ptype is None else in_ptype)
|
||||||
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 = data.straight.fn(data.straight_length, **kwargs)
|
||||||
if isinstance(straight_pat_or_tree, Pattern):
|
if isinstance(straight_pat_or_tree, Pattern):
|
||||||
straight = tree <= {SINGLE_USE_PREFIX + 'straight': straight_pat_or_tree}
|
straight = tree <= {SINGLE_USE_PREFIX + 'straight': straight_pat_or_tree}
|
||||||
else:
|
else:
|
||||||
straight = tree <= straight_pat_or_tree
|
straight = tree <= straight_pat_or_tree
|
||||||
pat.plug(straight, {port_names[1]: sport_in})
|
pat.plug(straight, {port_names[1]: data.straight.in_port_name})
|
||||||
if data.b_transition:
|
if data.b_transition:
|
||||||
btpat, btport_bend, btport_straight = data.b_transition
|
pat.plug(data.b_transition.abstract, {port_names[1]: data.b_transition.our_port_name})
|
||||||
pat.plug(btpat, {port_names[1]: btport_straight})
|
|
||||||
if data.ccw is not None:
|
if data.ccw is not None:
|
||||||
assert data.bend_tuple is not None
|
assert data.bend is not None
|
||||||
bend, bport_in, bport_out = data.bend_tuple
|
pat.plug(data.bend.abstract, {port_names[1]: data.bend.in_port_name}, mirrored=bool(data.ccw) == data.bend.clockwise)
|
||||||
pat.plug(bend, {port_names[1]: bport_in}, mirrored=bool(data.ccw))
|
|
||||||
if data.out_transition:
|
if data.out_transition:
|
||||||
opat, oport_theirs, oport_ours = data.out_transition
|
pat.plug(data.out_transition.abstract, {port_names[1]: data.out_transition.our_port_name})
|
||||||
pat.plug(opat, {port_names[1]: oport_ours})
|
|
||||||
|
|
||||||
return tree
|
return tree
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _bend2dxy(bend_tuple: abstract_tuple_t, ccw: SupportsBool | None) -> tuple[NDArray[numpy.float64], float]:
|
def _bend2dxy(bend: Bend, ccw: SupportsBool | None) -> tuple[NDArray[numpy.float64], float]:
|
||||||
if ccw is None:
|
if ccw is None:
|
||||||
return numpy.zeros(2), pi
|
return numpy.zeros(2), pi
|
||||||
bend, bport_in, bport_out = bend_tuple
|
|
||||||
|
|
||||||
angle_in = bend.ports[bport_in].rotation
|
angle_in = bend.in_port.rotation
|
||||||
angle_out = bend.ports[bport_out].rotation
|
angle_out = bend.out_port.rotation
|
||||||
assert angle_in is not None
|
assert angle_in is not None
|
||||||
assert angle_out is not None
|
assert angle_out is not None
|
||||||
|
|
||||||
bend_dxy = rotation_matrix_2d(-angle_in) @ (
|
bend_dxy = rotation_matrix_2d(-angle_in) @ (bend.out_port.offset - bend.in_port.offset)
|
||||||
bend.ports[bport_out].offset
|
|
||||||
- bend.ports[bport_in].offset
|
|
||||||
)
|
|
||||||
|
|
||||||
bend_angle = angle_out - angle_in
|
bend_angle = angle_out - angle_in
|
||||||
|
|
||||||
if bool(ccw):
|
if bool(ccw):
|
||||||
@ -530,30 +562,21 @@ class AutoTool(Tool, metaclass=ABCMeta):
|
|||||||
return bend_dxy, bend_angle
|
return bend_dxy, bend_angle
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _itransition2dxy(in_transition: abstract_tuple_t | None) -> NDArray[numpy.float64]:
|
def _itransition2dxy(in_transition: Transition | None) -> NDArray[numpy.float64]:
|
||||||
if in_transition is None:
|
if in_transition is None:
|
||||||
return numpy.zeros(2)
|
return numpy.zeros(2)
|
||||||
ipat, iport_theirs, iport_ours = in_transition
|
irot = in_transition.our_port.rotation
|
||||||
irot = ipat.ports[iport_theirs].rotation
|
|
||||||
assert irot is not None
|
assert irot is not None
|
||||||
itrans_dxy = rotation_matrix_2d(-irot) @ (
|
itrans_dxy = rotation_matrix_2d(-irot) @ (in_transition.our_port.offset - in_transition.their_port.offset)
|
||||||
ipat.ports[iport_ours].offset
|
|
||||||
- ipat.ports[iport_theirs].offset
|
|
||||||
)
|
|
||||||
return itrans_dxy
|
return itrans_dxy
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _otransition2dxy(out_transition: abstract_tuple_t | None, bend_angle: float) -> NDArray[numpy.float64]:
|
def _otransition2dxy(out_transition: Transition | None, bend_angle: float) -> NDArray[numpy.float64]:
|
||||||
if out_transition is None:
|
if out_transition is None:
|
||||||
return numpy.zeros(2)
|
return numpy.zeros(2)
|
||||||
opat, oport_theirs, oport_ours = out_transition
|
orot = out_transition.our_port.rotation
|
||||||
orot = opat.ports[oport_ours].rotation
|
|
||||||
assert orot is not None
|
assert orot is not None
|
||||||
|
otrans_dxy = rotation_matrix_2d(-orot + bend_angle) @ (out_transition.their_port.offset - out_transition.our_port.offset)
|
||||||
otrans_dxy = rotation_matrix_2d(-orot + bend_angle) @ (
|
|
||||||
opat.ports[oport_theirs].offset
|
|
||||||
- opat.ports[oport_ours].offset
|
|
||||||
)
|
|
||||||
return otrans_dxy
|
return otrans_dxy
|
||||||
|
|
||||||
def planL(
|
def planL(
|
||||||
@ -565,31 +588,31 @@ class AutoTool(Tool, metaclass=ABCMeta):
|
|||||||
out_ptype: str | None = None,
|
out_ptype: str | None = None,
|
||||||
**kwargs, # noqa: ARG002 (unused)
|
**kwargs, # noqa: ARG002 (unused)
|
||||||
) -> tuple[Port, LData]:
|
) -> tuple[Port, LData]:
|
||||||
# TODO check all the math for L-shaped bends
|
|
||||||
|
|
||||||
success = False
|
success = False
|
||||||
for straight_tuple in self.straights:
|
for straight in self.straights:
|
||||||
stype = straight_tuple[0]
|
for bend in self.bends:
|
||||||
straight_bounds = straight_tuple[-1]
|
bend_dxy, bend_angle = self._bend2dxy(bend, ccw)
|
||||||
for bend_tuple in self.bends:
|
|
||||||
bend_dxy, bend_angle = self._bend2dxy(bend_tuple, ccw)
|
|
||||||
btypei = bend_tuple[0][bend_tuple[1]].ptype
|
|
||||||
btypeo = bend_tuple[0][bend_tuple[1]].ptype
|
|
||||||
|
|
||||||
in_transition = self.transitions.get(('unk' if in_ptype is None else in_ptype, stype), None)
|
in_ptype_pair = ('unk' if in_ptype is None else in_ptype, straight.ptype)
|
||||||
|
in_transition = self.transitions.get(in_ptype_pair, None)
|
||||||
itrans_dxy = self._itransition2dxy(in_transition)
|
itrans_dxy = self._itransition2dxy(in_transition)
|
||||||
|
|
||||||
out_transition = self.transitions.get(('unk' if out_ptype is None else out_ptype, stype if ccw is None else btypeo), None)
|
out_ptype_pair = (
|
||||||
|
'unk' if out_ptype is None else out_ptype,
|
||||||
|
straight.ptype if ccw is None else bend.out_port.ptype
|
||||||
|
)
|
||||||
|
out_transition = self.transitions.get(out_ptype_pair, None)
|
||||||
otrans_dxy = self._otransition2dxy(out_transition, bend_angle)
|
otrans_dxy = self._otransition2dxy(out_transition, bend_angle)
|
||||||
|
|
||||||
b_transition = None
|
b_transition = None
|
||||||
if ccw is not None and btypei != stype:
|
if ccw is not None and bend.out_port.ptype != straight.ptype:
|
||||||
b_transition = self.transitions.get((btypei, stype), None)
|
b_transition = self.transitions.get((bend.out_port.ptype, straight.ptype), None)
|
||||||
btrans_dxy = self._itransition2dxy(b_transition)
|
btrans_dxy = self._itransition2dxy(b_transition)
|
||||||
|
|
||||||
straight_length = length - bend_dxy[0] - itrans_dxy[0] - btrans_dxy[0] - otrans_dxy[0]
|
straight_length = length - bend_dxy[0] - itrans_dxy[0] - btrans_dxy[0] - otrans_dxy[0]
|
||||||
bend_run = bend_dxy[1] + itrans_dxy[1] + btrans_dxy[1] + otrans_dxy[1]
|
bend_run = bend_dxy[1] + itrans_dxy[1] + btrans_dxy[1] + otrans_dxy[1]
|
||||||
success = straight_bounds[0] <= straight_length < straight_bounds[1]
|
success = straight.length_range[0] <= straight_length < straight.length_range[1]
|
||||||
if success:
|
if success:
|
||||||
break
|
break
|
||||||
if success:
|
if success:
|
||||||
@ -603,15 +626,13 @@ class AutoTool(Tool, metaclass=ABCMeta):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if out_transition is not None:
|
if out_transition is not None:
|
||||||
opat, oport_theirs, _ = out_transition
|
out_ptype_actual = out_transition.their_port.ptype
|
||||||
out_ptype_actual = opat.ports[oport_theirs].ptype
|
|
||||||
elif ccw is not None:
|
elif ccw is not None:
|
||||||
bend, _, bport_out = bend_tuple
|
out_ptype_actual = bend.out_port.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
|
||||||
|
|
||||||
data = self.LData(straight_length, straight_tuple, ccw, bend_tuple, in_transition, b_transition, out_transition)
|
data = self.LData(straight_length, straight, ccw, bend, in_transition, b_transition, out_transition)
|
||||||
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
|
||||||
|
|
||||||
@ -629,16 +650,14 @@ class AutoTool(Tool, metaclass=ABCMeta):
|
|||||||
|
|
||||||
for step in batch:
|
for step in batch:
|
||||||
data = step.data
|
data = step.data
|
||||||
_stype, gen_straight, sport_in, _sport_out, _length_bounds = data.straight_tuple
|
|
||||||
assert step.tool == self
|
assert step.tool == self
|
||||||
|
|
||||||
if step.opcode == 'L':
|
if step.opcode == 'L':
|
||||||
if data.in_transition:
|
if data.in_transition:
|
||||||
ipat, iport_theirs, _iport_ours = data.in_transition
|
pat.plug(data.in_transition.abstract, {port_names[1]: data.in_transition.their_port_name})
|
||||||
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 = data.straight.fn(data.straight_length, **kwargs)
|
||||||
pmap = {port_names[1]: sport_in}
|
pmap = {port_names[1]: data.straight.in_port_name}
|
||||||
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
|
||||||
if append:
|
if append:
|
||||||
@ -656,14 +675,11 @@ class AutoTool(Tool, metaclass=ABCMeta):
|
|||||||
straight = tree <= straight_pat_or_tree
|
straight = tree <= straight_pat_or_tree
|
||||||
pat.plug(straight, pmap)
|
pat.plug(straight, pmap)
|
||||||
if data.b_transition:
|
if data.b_transition:
|
||||||
btpat, btport_bend, btport_straight = data.b_transition
|
pat.plug(data.b_transition.abstract, {port_names[1]: data.b_transition.our_port_name})
|
||||||
pat.plug(btpat, {port_names[1]: btport_straight})
|
|
||||||
if data.ccw is not None:
|
if data.ccw is not None:
|
||||||
bend, bport_in, bport_out = data.bend_tuple
|
pat.plug(data.bend.abstract, {port_names[1]: data.bend.in_port_name}, mirrored=bool(data.ccw) == data.bend.clockwise)
|
||||||
pat.plug(bend, {port_names[1]: bport_in}, mirrored=bool(data.ccw))
|
|
||||||
if data.out_transition:
|
if data.out_transition:
|
||||||
opat, oport_theirs, oport_ours = data.out_transition
|
pat.plug(data.out_transition.abstract, {port_names[1]: data.out_transition.our_port_name})
|
||||||
pat.plug(opat, {port_names[1]: oport_ours})
|
|
||||||
return tree
|
return tree
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user