[Pather/RenderPather/Tool/PortPather] Add U-bends
This commit is contained in:
parent
babbe78daa
commit
69ac25078c
4 changed files with 195 additions and 0 deletions
|
|
@ -255,6 +255,72 @@ class Pather(Builder, PatherMixin):
|
|||
return s
|
||||
|
||||
|
||||
def _pathU(
|
||||
self,
|
||||
portspec: str,
|
||||
jog: float,
|
||||
*,
|
||||
length: float = 0,
|
||||
plug_into: str | None = None,
|
||||
**kwargs,
|
||||
) -> Self:
|
||||
"""
|
||||
Create a U-shaped "wire"/"waveguide" and `plug` it into the port `portspec`, with the aim
|
||||
of traveling exactly `length` distance along the axis of `portspec` and returning to
|
||||
the same orientation with an offset `jog`.
|
||||
|
||||
Args:
|
||||
portspec: The name of the port into which the wire will be plugged.
|
||||
jog: Total manhattan distance perpendicular to the direction of travel.
|
||||
Positive values are to the left of the direction of travel.
|
||||
length: Extra distance to travel along the port's axis. Default 0.
|
||||
plug_into: If not None, attempts to plug the wire's output port into the provided
|
||||
port on `self`.
|
||||
|
||||
Returns:
|
||||
self
|
||||
"""
|
||||
if self._dead:
|
||||
logger.warning('Skipping geometry for _pathU() 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)
|
||||
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.")
|
||||
# Fallback for dead pather: manually update the port instead of plugging
|
||||
port = self.pattern[portspec]
|
||||
port_rot = port.rotation
|
||||
assert port_rot is not None
|
||||
out_port = Port((length, jog), rotation=0, ptype=in_ptype)
|
||||
out_port.rotate_around((0, 0), pi + port_rot)
|
||||
out_port.translate(port.offset)
|
||||
self.pattern.ports[portspec] = out_port
|
||||
self._log_port_update(portspec)
|
||||
if plug_into is not None:
|
||||
self.plugged({portspec: plug_into})
|
||||
return self
|
||||
|
||||
tname = self.library << tree
|
||||
if plug_into is not None:
|
||||
output = {plug_into: tool_port_names[1]}
|
||||
else:
|
||||
output = {}
|
||||
self.plug(tname, {portspec: tool_port_names[0], **output})
|
||||
return self
|
||||
|
||||
def plugged(self, connections: dict[str, str]) -> Self:
|
||||
PortList.plugged(self, connections)
|
||||
return self
|
||||
|
||||
def _path(
|
||||
self,
|
||||
portspec: str,
|
||||
|
|
|
|||
|
|
@ -214,6 +214,19 @@ class PatherMixin(PortList, metaclass=ABCMeta):
|
|||
self._pathS(port, l_actual, offset, **bounds)
|
||||
return self
|
||||
|
||||
def uturn(self, portspec: str | Sequence[str], offset: float, length: float | None = None, **bounds) -> Self:
|
||||
""" 180-degree turn extension. """
|
||||
if isinstance(portspec, str):
|
||||
portspec = [portspec]
|
||||
|
||||
for port in portspec:
|
||||
l_actual = length
|
||||
if l_actual is None:
|
||||
# TODO: use bounds to determine length?
|
||||
l_actual = 0
|
||||
self._pathU(port, offset, length=l_actual, **bounds)
|
||||
return self
|
||||
|
||||
def trace_into(
|
||||
self,
|
||||
portspec_src: str,
|
||||
|
|
@ -376,6 +389,18 @@ class PatherMixin(PortList, metaclass=ABCMeta):
|
|||
) -> Self:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _pathU(
|
||||
self,
|
||||
portspec: str,
|
||||
jog: float,
|
||||
*,
|
||||
length: float = 0,
|
||||
plug_into: str | None = None,
|
||||
**kwargs,
|
||||
) -> Self:
|
||||
pass
|
||||
|
||||
def path(self, *args, **kwargs) -> Self:
|
||||
import warnings
|
||||
warnings.warn("path() is deprecated; use trace(), straight(), or bend() instead", DeprecationWarning, stacklevel=2)
|
||||
|
|
@ -386,6 +411,11 @@ class PatherMixin(PortList, metaclass=ABCMeta):
|
|||
warnings.warn("pathS() is deprecated; use jog() instead", DeprecationWarning, stacklevel=2)
|
||||
return self._pathS(*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)
|
||||
|
||||
@abstractmethod
|
||||
def plug(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -377,6 +377,66 @@ class RenderPather(PatherMixin):
|
|||
PortList.plugged(self, connections)
|
||||
return self
|
||||
|
||||
def _pathU(
|
||||
self,
|
||||
portspec: str,
|
||||
jog: float,
|
||||
*,
|
||||
length: float = 0,
|
||||
plug_into: str | None = None,
|
||||
**kwargs,
|
||||
) -> Self:
|
||||
"""
|
||||
Plan a U-shaped "wire"/"waveguide" extending from the port `portspec`, with the aim
|
||||
of traveling exactly `length` distance and returning to the same orientation
|
||||
with an offset `jog`.
|
||||
|
||||
Args:
|
||||
portspec: The name of the port into which the wire will be plugged.
|
||||
jog: Total manhattan distance perpendicular to the direction of travel.
|
||||
Positive values are to the left of the direction of travel.
|
||||
length: Extra distance to travel along the port's axis. Default 0.
|
||||
plug_into: If not None, attempts to plug the wire's output port into the provided
|
||||
port on `self`.
|
||||
|
||||
Returns:
|
||||
self
|
||||
"""
|
||||
if self._dead:
|
||||
logger.warning('Skipping geometry for _pathU() since device is dead')
|
||||
|
||||
port = self.pattern[portspec]
|
||||
in_ptype = port.ptype
|
||||
port_rot = port.rotation
|
||||
assert port_rot is not None
|
||||
|
||||
tool = self.tools.get(portspec, self.tools[None])
|
||||
|
||||
try:
|
||||
out_port, data = tool.planU(jog, length=length, in_ptype=in_ptype, **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 planning failed for dead pather. Using dummy extension.")
|
||||
out_port = Port((length, jog), rotation=0, ptype=in_ptype)
|
||||
data = None
|
||||
|
||||
if out_port is not None:
|
||||
out_port.rotate_around((0, 0), pi + port_rot)
|
||||
out_port.translate(port.offset)
|
||||
if not self._dead:
|
||||
step = RenderStep('U', tool, port.copy(), out_port.copy(), data)
|
||||
self.paths[portspec].append(step)
|
||||
self.pattern.ports[portspec] = out_port.copy()
|
||||
self._log_port_update(portspec)
|
||||
|
||||
if plug_into is not None:
|
||||
self.plugged({portspec: plug_into})
|
||||
return self
|
||||
|
||||
def _path(
|
||||
self,
|
||||
portspec: str,
|
||||
|
|
|
|||
|
|
@ -260,6 +260,45 @@ class Tool:
|
|||
"""
|
||||
raise NotImplementedError(f'planS() not implemented for {type(self)}')
|
||||
|
||||
def pathU(
|
||||
self,
|
||||
jog: float,
|
||||
*,
|
||||
in_ptype: str | None = None,
|
||||
out_ptype: str | None = None,
|
||||
port_names: tuple[str, str] = ('A', 'B'),
|
||||
**kwargs,
|
||||
) -> Library:
|
||||
"""
|
||||
Create a wire or waveguide that travels exactly `jog` distance along the axis
|
||||
perpendicular to its input port (i.e. a U-bend).
|
||||
|
||||
Used by `Pather` and `RenderPather`.
|
||||
|
||||
The output port must have an orientation identical to the input port.
|
||||
|
||||
The input and output ports should be compatible with `in_ptype` and
|
||||
`out_ptype`, respectively. They should also be named `port_names[0]` and
|
||||
`port_names[1]`, respectively.
|
||||
|
||||
Args:
|
||||
jog: The total offset from the input to output, along the perpendicular axis.
|
||||
A positive number implies a leftwards shift (i.e. counterclockwise bend
|
||||
followed by a clockwise bend)
|
||||
in_ptype: The `ptype` of the port into which this wire's input will be `plug`ged.
|
||||
out_ptype: The `ptype` of the port into which this wire's output will be `plug`ged.
|
||||
port_names: The output pattern will have its input port named `port_names[0]` and
|
||||
its output named `port_names[1]`.
|
||||
kwargs: Custom tool-specific parameters.
|
||||
|
||||
Returns:
|
||||
A pattern tree containing the requested U-shaped wire or waveguide
|
||||
|
||||
Raises:
|
||||
BuildError if an impossible or unsupported geometry is requested.
|
||||
"""
|
||||
raise NotImplementedError(f'pathU() not implemented for {type(self)}')
|
||||
|
||||
def planU(
|
||||
self,
|
||||
jog: float,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue