[Pather / RenderPather / Tool] Rename path->trace in more locations

This commit is contained in:
jan 2026-03-07 00:33:18 -08:00
commit 84f37195ad
4 changed files with 71 additions and 77 deletions

View file

@ -28,7 +28,7 @@ class Pather(Builder, PatherMixin):
single-use patterns (e.g. wires or waveguides) and bundles / buses of such patterns.
`Pather` is mostly concerned with calculating how long each wire should be. It calls
out to `Tool.path` functions provided by subclasses of `Tool` to build the actual patterns.
out to `Tool.traceL` functions provided by subclasses of `Tool` to build the actual patterns.
`Tool`s are assigned on a per-port basis and stored in `.tools`; a key of `None` represents
a "default" `Tool` used for all ports which do not have a port-specific `Tool` assigned.
@ -63,7 +63,10 @@ class Pather(Builder, PatherMixin):
Examples: Adding to a pattern
=============================
- `pather.path('my_port', ccw=True, distance)` creates a "wire" for which the output
- `pather.straight('my_port', distance)` creates a straight wire with a length
of `distance` and `plug`s it into `'my_port'`.
- `pather.bend('my_port', ccw=True, distance)` creates a "wire" for which the output
port is `distance` units away along the axis of `'my_port'` and rotated 90 degrees
counterclockwise (since `ccw=True`) relative to `'my_port'`. The wire is `plug`ged
into the existing `'my_port'`, causing the port to move to the wire's output.
@ -72,22 +75,15 @@ class Pather(Builder, PatherMixin):
there may be a significant width to the bend that is used to accomplish the 90 degree
turn. However, an error is raised if `distance` is too small to fit the bend.
- `pather.path('my_port', ccw=None, distance)` creates a straight wire with a length
of `distance` and `plug`s it into `'my_port'`.
- `pather.path_to('my_port', ccw=False, position)` creates a wire which starts at
- `pather.trace_to('my_port', ccw=False, x=position)` creates a wire which starts at
`'my_port'` and has its output at the specified `position`, pointing 90 degrees
clockwise relative to the input. Again, the off-axis position or distance to the
output is not specified, so `position` takes the form of a single coordinate. To
ease debugging, position may be specified as `x=position` or `y=position` and an
error will be raised if the wrong coordinate is given.
output is not specified, so `position` takes the form of a single coordinate.
- `pather.mpath(['A', 'B', 'C'], ..., spacing=spacing)` is a superset of `path`
and `path_to` which can act on multiple ports simultaneously. Each port's wire is
generated using its own `Tool` (or the default tool if left unspecified).
The output ports are spaced out by `spacing` along the input ports' axis, unless
`ccw=None` is specified (i.e. no bends) in which case they all end at the same
destination coordinate.
- `pather.trace(['A', 'B', 'C'], ccw=True, spacing=spacing, xmax=position)` acts
on multiple ports simultaneously. Each port's wire is generated using its own
`Tool` (or the default tool if left unspecified).
The output ports are spaced out by `spacing` along the input ports' axis.
- `pather.plug(wire, {'myport': 'A'})` places port 'A' of `wire` at 'myport'
of `pather.pattern`. If `wire` has only two ports (e.g. 'A' and 'B'), no `map_out`,
@ -141,8 +137,8 @@ class Pather(Builder, PatherMixin):
in which case it is interpreted as a name in `library`.
Default `None` (no ports).
tools: A mapping of {port: tool} which specifies what `Tool` should be used
to generate waveguide or wire segments when `path`/`path_to`/`mpath`
are called. Relies on `Tool.path` implementations.
to generate waveguide or wire segments when `trace`/`trace_to`/etc.
are called. Relies on `Tool.traceL` implementations.
name: If specified, `library[name]` is set to `self.pattern`.
"""
self._dead = False
@ -213,7 +209,7 @@ class Pather(Builder, PatherMixin):
and to which the new one should be added (if named). If not provided,
`source.library` must exist and will be used.
tools: `Tool`s which will be used by the pather for generating new wires
or waveguides (via `path`/`path_to`/`mpath`).
or waveguides (via `trace`/`trace_to`).
in_prefix: Prepended to port names for newly-created ports with
reversed directions compared to the current device.
out_prefix: Prepended to port names for ports which are directly
@ -255,7 +251,7 @@ class Pather(Builder, PatherMixin):
return s
def _pathU(
def _traceU(
self,
portspec: str,
jog: float,
@ -281,21 +277,21 @@ class Pather(Builder, PatherMixin):
self
"""
if self._dead:
logger.warning('Skipping geometry for _pathU() since device is dead')
logger.warning('Skipping geometry for _traceU() since device is dead')
tool_port_names = ('A', 'B')
tool = self.tools.get(portspec, self.tools[None])
in_ptype = self.pattern[portspec].ptype
try:
tree = tool.pathU(jog, length=length, in_ptype=in_ptype, port_names=tool_port_names, **kwargs)
tree = tool.traceU(jog, length=length, in_ptype=in_ptype, port_names=tool_port_names, **kwargs)
except (BuildError, NotImplementedError):
if self._uturn_fallback(tool, portspec, jog, length, in_ptype, plug_into, **kwargs):
return self
if not self._dead:
raise
logger.warning("Tool pathU failed for dead pather. Using dummy extension.")
logger.warning("Tool traceU failed for dead pather. Using dummy extension.")
# Fallback for dead pather: manually update the port instead of plugging
port = self.pattern[portspec]
port_rot = port.rotation
@ -321,7 +317,7 @@ class Pather(Builder, PatherMixin):
PortList.plugged(self, connections)
return self
def _path(
def _traceL(
self,
portspec: str,
ccw: SupportsBool | None,
@ -362,18 +358,18 @@ class Pather(Builder, PatherMixin):
LibraryError if no valid name could be picked for the pattern.
"""
if self._dead:
logger.warning('Skipping geometry for _path() since device is dead')
logger.warning('Skipping geometry for _traceL() since device is dead')
tool_port_names = ('A', 'B')
tool = self.tools.get(portspec, self.tools[None])
in_ptype = self.pattern[portspec].ptype
try:
tree = tool.path(ccw, length, in_ptype=in_ptype, port_names=tool_port_names, **kwargs)
tree = tool.traceL(ccw, length, in_ptype=in_ptype, port_names=tool_port_names, **kwargs)
except (BuildError, NotImplementedError):
if not self._dead:
raise
logger.warning("Tool path failed for dead pather. Using dummy extension.")
logger.warning("Tool traceL failed for dead pather. Using dummy extension.")
# Fallback for dead pather: manually update the port instead of plugging
port = self.pattern[portspec]
port_rot = port.rotation
@ -401,7 +397,7 @@ class Pather(Builder, PatherMixin):
self.plug(tname, {portspec: tool_port_names[0], **output})
return self
def _pathS(
def _traceS(
self,
portspec: str,
length: float,
@ -440,29 +436,29 @@ class Pather(Builder, PatherMixin):
LibraryError if no valid name could be picked for the pattern.
"""
if self._dead:
logger.warning('Skipping geometry for _pathS() since device is dead')
logger.warning('Skipping geometry for _traceS() since device is dead')
tool_port_names = ('A', 'B')
tool = self.tools.get(portspec, self.tools[None])
in_ptype = self.pattern[portspec].ptype
try:
tree = tool.pathS(length, jog, in_ptype=in_ptype, port_names=tool_port_names, **kwargs)
tree = tool.traceS(length, jog, in_ptype=in_ptype, port_names=tool_port_names, **kwargs)
except NotImplementedError:
# Fall back to drawing two L-bends
ccw0 = jog > 0
kwargs_no_out = kwargs | {'out_ptype': None}
try:
t_tree0 = tool.path( ccw0, length / 2, port_names=tool_port_names, in_ptype=in_ptype, **kwargs_no_out)
t_tree0 = tool.traceL( ccw0, length / 2, port_names=tool_port_names, in_ptype=in_ptype, **kwargs_no_out)
t_pat0 = t_tree0.top_pattern()
(_, jog0), _ = t_pat0[tool_port_names[0]].measure_travel(t_pat0[tool_port_names[1]])
t_tree1 = tool.path(not ccw0, abs(jog - jog0), port_names=tool_port_names, in_ptype=t_pat0[tool_port_names[1]].ptype, **kwargs)
t_tree1 = tool.traceL(not ccw0, abs(jog - jog0), port_names=tool_port_names, in_ptype=t_pat0[tool_port_names[1]].ptype, **kwargs)
t_pat1 = t_tree1.top_pattern()
(_, jog1), _ = t_pat1[tool_port_names[0]].measure_travel(t_pat1[tool_port_names[1]])
kwargs_plug = kwargs | {'plug_into': plug_into}
self._path(portspec, ccw0, length - abs(jog1), **kwargs_no_out)
self._path(portspec, not ccw0, abs(jog - jog0), **kwargs_plug)
self._traceL(portspec, ccw0, length - abs(jog1), **kwargs_no_out)
self._traceL(portspec, not ccw0, abs(jog - jog0), **kwargs_plug)
except (BuildError, NotImplementedError):
if not self._dead:
raise
@ -475,7 +471,7 @@ class Pather(Builder, PatherMixin):
# Fall through to dummy extension below
if self._dead:
logger.warning("Tool pathS failed for dead pather. Using dummy extension.")
logger.warning("Tool traceS failed for dead pather. Using dummy extension.")
# Fallback for dead pather: manually update the port instead of plugging
port = self.pattern[portspec]
port_rot = port.rotation

View file

@ -74,14 +74,14 @@ class PatherMixin(PortList, metaclass=ABCMeta):
raise BuildError('length is only allowed with a single port in trace()')
if bounds:
raise BuildError('length and bounds are mutually exclusive in trace()')
return self._path(portspec[0], ccw, length)
return self._traceL(portspec[0], ccw, length)
if 'each' in bounds:
each = bounds.pop('each')
if bounds:
raise BuildError('each and other bounds are mutually exclusive in trace()')
for port in portspec:
self._path(port, ccw, each)
self._traceL(port, ccw, each)
return self
# Bundle routing (formerly mpath logic)
@ -106,7 +106,7 @@ class PatherMixin(PortList, metaclass=ABCMeta):
extensions = ell(ports, ccw, spacing=spacing, bound=bound, bound_type=bound_type, set_rotation=set_rotation)
for port_name, ext_len in extensions.items():
self._path(port_name, ccw, ext_len, **bounds)
self._traceL(port_name, ccw, ext_len, **bounds)
return self
def trace_to(
@ -180,7 +180,7 @@ class PatherMixin(PortList, metaclass=ABCMeta):
if 'length' in bounds and bounds['length'] is not None:
raise BuildError('Cannot specify both relative length and absolute position in trace_to()')
return self._path(port_name, ccw, length, **other_bounds)
return self._traceL(port_name, ccw, length, **other_bounds)
# Bundle routing (delegate to trace which handles ell)
return self.trace(portspec, ccw, spacing=spacing, **bounds)
@ -211,7 +211,7 @@ class PatherMixin(PortList, metaclass=ABCMeta):
if l_actual is None:
# TODO: use bounds to determine length?
raise BuildError('jog() currently requires a length')
self._pathS(port, l_actual, offset, **bounds)
self._traceS(port, l_actual, offset, **bounds)
return self
def uturn(self, portspec: str | Sequence[str], offset: float, length: float | None = None, **bounds) -> Self:
@ -224,7 +224,7 @@ class PatherMixin(PortList, metaclass=ABCMeta):
if l_actual is None:
# TODO: use bounds to determine length?
l_actual = 0
self._pathU(port, offset, length=l_actual, **bounds)
self._traceU(port, offset, length=l_actual, **bounds)
return self
def trace_into(
@ -360,15 +360,15 @@ class PatherMixin(PortList, metaclass=ABCMeta):
L2 = abs(jog) - R
kwargs_plug = kwargs | {'plug_into': plug_into}
self._path(portspec, ccw, L1, **kwargs_no_out)
self._path(portspec, ccw, L2, **kwargs_plug)
self._traceL(portspec, ccw, L1, **kwargs_no_out)
self._traceL(portspec, ccw, L2, **kwargs_plug)
except (BuildError, NotImplementedError):
return False
else:
return True
@abstractmethod
def _path(
def _traceL(
self,
portspec: str,
ccw: SupportsBool | None,
@ -380,7 +380,7 @@ class PatherMixin(PortList, metaclass=ABCMeta):
pass
@abstractmethod
def _pathS(
def _traceS(
self,
portspec: str,
length: float,
@ -392,7 +392,7 @@ class PatherMixin(PortList, metaclass=ABCMeta):
pass
@abstractmethod
def _pathU(
def _traceU(
self,
portspec: str,
jog: float,
@ -406,17 +406,17 @@ class PatherMixin(PortList, metaclass=ABCMeta):
def path(self, *args, **kwargs) -> Self:
import warnings
warnings.warn("path() is deprecated; use trace(), straight(), or bend() instead", DeprecationWarning, stacklevel=2)
return self._path(*args, **kwargs)
return self._traceL(*args, **kwargs)
def pathS(self, *args, **kwargs) -> Self:
import warnings
warnings.warn("pathS() is deprecated; use jog() instead", DeprecationWarning, stacklevel=2)
return self._pathS(*args, **kwargs)
return self._traceS(*args, **kwargs)
def pathU(self, *args, **kwargs) -> Self:
import warnings
warnings.warn("pathU() is deprecated; use uturn() instead", DeprecationWarning, stacklevel=2)
return self._pathU(*args, **kwargs)
return self._traceU(*args, **kwargs)
@abstractmethod
def plug(
@ -762,4 +762,3 @@ class PortPather:
del self.pather.pattern.ports[name]
self.ports = [pp for pp in self.ports if pp != name]
return self

View file

@ -377,7 +377,7 @@ class RenderPather(PatherMixin):
PortList.plugged(self, connections)
return self
def _pathU(
def _traceU(
self,
portspec: str,
jog: float,
@ -403,7 +403,7 @@ class RenderPather(PatherMixin):
self
"""
if self._dead:
logger.warning('Skipping geometry for _pathU() since device is dead')
logger.warning('Skipping geometry for _traceU() since device is dead')
port = self.pattern[portspec]
in_ptype = port.ptype
@ -437,7 +437,7 @@ class RenderPather(PatherMixin):
self.plugged({portspec: plug_into})
return self
def _path(
def _traceL(
self,
portspec: str,
ccw: SupportsBool | None,
@ -480,7 +480,7 @@ class RenderPather(PatherMixin):
LibraryError if no valid name could be picked for the pattern.
"""
if self._dead:
logger.warning('Skipping geometry for _path() since device is dead')
logger.warning('Skipping geometry for _traceL() since device is dead')
port = self.pattern[portspec]
in_ptype = port.ptype
@ -520,7 +520,7 @@ class RenderPather(PatherMixin):
return self
def _pathS(
def _traceS(
self,
portspec: str,
length: float,
@ -564,7 +564,7 @@ class RenderPather(PatherMixin):
LibraryError if no valid name could be picked for the pattern.
"""
if self._dead:
logger.warning('Skipping geometry for _pathS() since device is dead')
logger.warning('Skipping geometry for _traceS() since device is dead')
port = self.pattern[portspec]
in_ptype = port.ptype
@ -587,8 +587,8 @@ class RenderPather(PatherMixin):
jog1 = Port((0, 0), 0).measure_travel(t_port1)[0][1]
kwargs_plug = kwargs | {'plug_into': plug_into}
self._path(portspec, ccw0, length - abs(jog1), **kwargs_no_out)
self._path(portspec, not ccw0, abs(jog - jog0), **kwargs_plug)
self._traceL(portspec, ccw0, length - abs(jog1), **kwargs_no_out)
self._traceL(portspec, not ccw0, abs(jog - jog0), **kwargs_plug)
except (BuildError, NotImplementedError):
if not self._dead:
raise
@ -803,4 +803,3 @@ class RenderPather(PatherMixin):
def rect(self, *args, **kwargs) -> Self:
self.pattern.rect(*args, **kwargs)
return self

View file

@ -93,7 +93,7 @@ class Tool:
unimplemented (e.g. in cases where they don't make sense or the required components
are impractical or unavailable).
"""
def path(
def traceL(
self,
ccw: SupportsBool | None,
length: float,
@ -136,9 +136,9 @@ class Tool:
Raises:
BuildError if an impossible or unsupported geometry is requested.
"""
raise NotImplementedError(f'path() not implemented for {type(self)}')
raise NotImplementedError(f'traceL() not implemented for {type(self)}')
def pathS(
def traceS(
self,
length: float,
jog: float,
@ -178,7 +178,7 @@ class Tool:
Raises:
BuildError if an impossible or unsupported geometry is requested.
"""
raise NotImplementedError(f'path() not implemented for {type(self)}')
raise NotImplementedError(f'traceS() not implemented for {type(self)}')
def planL(
self,
@ -260,7 +260,7 @@ class Tool:
"""
raise NotImplementedError(f'planS() not implemented for {type(self)}')
def pathU(
def traceU(
self,
jog: float,
*,
@ -298,7 +298,7 @@ class Tool:
Raises:
BuildError if an impossible or unsupported geometry is requested.
"""
raise NotImplementedError(f'pathU() not implemented for {type(self)}')
raise NotImplementedError(f'traceU() not implemented for {type(self)}')
def planU(
self,
@ -467,7 +467,7 @@ class SimpleTool(Tool, metaclass=ABCMeta):
pat.plug(bend, {port_names[1]: inport}, mirrored=mirrored)
return tree
def path(
def traceL(
self,
ccw: SupportsBool | None,
length: float,
@ -484,7 +484,7 @@ class SimpleTool(Tool, metaclass=ABCMeta):
out_ptype = out_ptype,
)
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'path')
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'traceL')
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, straight_kwargs=kwargs)
return tree
@ -497,7 +497,7 @@ class SimpleTool(Tool, metaclass=ABCMeta):
**kwargs,
) -> ILibrary:
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'path')
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'traceL')
pat.add_port_pair(names=(port_names[0], port_names[1]))
for step in batch:
@ -774,7 +774,7 @@ class AutoTool(Tool, metaclass=ABCMeta):
pat.plug(data.out_transition.abstract, {port_names[1]: data.out_transition.our_port_name})
return tree
def path(
def traceL(
self,
ccw: SupportsBool | None,
length: float,
@ -791,7 +791,7 @@ class AutoTool(Tool, metaclass=ABCMeta):
out_ptype = out_ptype,
)
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'path')
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'traceL')
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, straight_kwargs=kwargs)
return tree
@ -930,7 +930,7 @@ class AutoTool(Tool, metaclass=ABCMeta):
pat.plug(data.out_transition.abstract, {port_names[1]: data.out_transition.our_port_name})
return tree
def pathS(
def traceS(
self,
length: float,
jog: float,
@ -946,7 +946,7 @@ class AutoTool(Tool, metaclass=ABCMeta):
in_ptype = in_ptype,
out_ptype = out_ptype,
)
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'pathS')
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'traceS')
pat.add_port_pair(names=port_names, ptype='unk' if in_ptype is None else in_ptype)
self._renderS(data=data, tree=tree, port_names=port_names, gen_kwargs=kwargs)
return tree
@ -1036,7 +1036,7 @@ class AutoTool(Tool, metaclass=ABCMeta):
self._renderL(data.ldata1, tree, port_names, gen_kwargs)
return tree
def pathU(
def traceU(
self,
jog: float,
*,
@ -1053,7 +1053,7 @@ class AutoTool(Tool, metaclass=ABCMeta):
out_ptype = out_ptype,
**kwargs,
)
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'pathU')
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'traceU')
pat.add_port_pair(names=port_names, ptype='unk' if in_ptype is None else in_ptype)
self._renderU(data=data, tree=tree, port_names=port_names, gen_kwargs=kwargs)
return tree
@ -1066,7 +1066,7 @@ class AutoTool(Tool, metaclass=ABCMeta):
**kwargs,
) -> ILibrary:
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'path')
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'traceL')
pat.add_port_pair(names=(port_names[0], port_names[1]))
for step in batch:
@ -1107,7 +1107,7 @@ class PathTool(Tool, metaclass=ABCMeta):
# self.width = width
# self.ptype: str
def path(
def traceL(
self,
ccw: SupportsBool | None,
length: float,
@ -1124,7 +1124,7 @@ class PathTool(Tool, metaclass=ABCMeta):
out_ptype=out_ptype,
)
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'path')
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'traceL')
pat.path(layer=self.layer, width=self.width, vertices=[(0, 0), (length, 0)])
if ccw is None:
@ -1219,7 +1219,7 @@ class PathTool(Tool, metaclass=ABCMeta):
# If the path ends in a bend, we need to add the final vertex
path_vertices.append(local_batch[-1].end_port.offset)
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'path')
tree, pat = Library.mktree(SINGLE_USE_PREFIX + 'traceL')
pat.path(layer=self.layer, width=self.width, vertices=path_vertices)
pat.ports = {
port_names[0]: local_batch[0].start_port.copy().rotate(pi),