[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
|
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(
|
def _path(
|
||||||
self,
|
self,
|
||||||
portspec: str,
|
portspec: str,
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,19 @@ class PatherMixin(PortList, metaclass=ABCMeta):
|
||||||
self._pathS(port, l_actual, offset, **bounds)
|
self._pathS(port, l_actual, offset, **bounds)
|
||||||
return self
|
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(
|
def trace_into(
|
||||||
self,
|
self,
|
||||||
portspec_src: str,
|
portspec_src: str,
|
||||||
|
|
@ -376,6 +389,18 @@ class PatherMixin(PortList, metaclass=ABCMeta):
|
||||||
) -> Self:
|
) -> Self:
|
||||||
pass
|
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:
|
def path(self, *args, **kwargs) -> Self:
|
||||||
import warnings
|
import warnings
|
||||||
warnings.warn("path() is deprecated; use trace(), straight(), or bend() instead", DeprecationWarning, stacklevel=2)
|
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)
|
warnings.warn("pathS() is deprecated; use jog() instead", DeprecationWarning, stacklevel=2)
|
||||||
return self._pathS(*args, **kwargs)
|
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
|
@abstractmethod
|
||||||
def plug(
|
def plug(
|
||||||
self,
|
self,
|
||||||
|
|
|
||||||
|
|
@ -377,6 +377,66 @@ class RenderPather(PatherMixin):
|
||||||
PortList.plugged(self, connections)
|
PortList.plugged(self, connections)
|
||||||
return self
|
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(
|
def _path(
|
||||||
self,
|
self,
|
||||||
portspec: str,
|
portspec: str,
|
||||||
|
|
|
||||||
|
|
@ -260,6 +260,45 @@ class Tool:
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(f'planS() not implemented for {type(self)}')
|
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(
|
def planU(
|
||||||
self,
|
self,
|
||||||
jog: float,
|
jog: float,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue