add path_into()

path_into
Jan Petykiewicz 6 months ago
parent 383b5a0bef
commit f840a18192

@ -15,7 +15,7 @@ from ..library import ILibrary, SINGLE_USE_PREFIX
from ..error import PortError, BuildError from ..error import PortError, BuildError
from ..ports import PortList, Port from ..ports import PortList, Port
from ..abstract import Abstract from ..abstract import Abstract
from ..utils import SupportsBool from ..utils import SupportsBool, rotation_matrix_2d
from .tools import Tool from .tools import Tool
from .utils import ell from .utils import ell
from .builder import Builder from .builder import Builder
@ -431,6 +431,92 @@ class Pather(Builder):
) )
def path_into(
self,
portspec_src: str,
portspec_dst: str,
*,
tool_port_names: tuple[str, str] = ('A', 'B'),
out_ptype: str = 'unk',
plug_destination: bool = True,
**kwargs,
) -> Self:
if self._dead:
logger.error('Skipping path_into() since device is dead')
return self
port_src = self.pattern[portspec_src]
port_dst = self.pattern[portspec_dst]
if port_src.rotation is None:
raise PortError(f'Port {portspec_src} has no rotation and cannot be used for path_into()')
if port_dst.rotation is None:
raise PortError(f'Port {portspec_dst} has no rotation and cannot be used for path_into()')
if not numpy.isclose(port_src.rotation % (pi / 2), 0):
raise BuildError('path_to was asked to route from non-manhattan port')
if not numpy.isclose(port_dst.rotation % (pi / 2), 0):
raise BuildError('path_to was asked to route to non-manhattan port')
src_is_horizontal = numpy.isclose(port_src.rotation % pi, 0)
dst_is_horizontal = numpy.isclose(port_dst.rotation % pi, 0)
xs, ys = port_src.offset
xd, yd = port_dst.offset
angle = (port_dst.rotation - port_src.rotation) % (2 * pi)
kwargs['tool_port_names'] = tool_port_names
src_ne = port_src.rotation % (2 * pi) > (3 * pi /4) # path from src will go north or east
dst_args = {'out_ptype': out_ptype}
if plug_destination:
dst_args['plug_into'] = portspec_dst
def get_jog(ccw: SupportsBool, length: float) -> float:
tool = self.tools.get(portspec_src, self.tools[None])
in_ptype = 'unk' # Could use port_src.ptype, but we're assuming this is after one bend already...
tree2 = tool.path(ccw, y_len, in_ptype=in_ptype, port_names=('A', 'B'), out_ptype=out_ptype, **kwargs)
top2 = tree2.top_pattern()
jog = rotation_matrix_2d(top2['A'].rotation) @ (top2['B'].offset - top2['A'].offset)
return jog[1]
if src_is_horizontal and not dst_is_horizontal:
# single bend should suffice
self.path_to(portspec_src, angle < pi, y=yd, **kwargs)
self.path_to(portspec_src, None, x=xd, **kwargs, **dst_args)
elif dst_is_horizontal and not src_is_horizontal:
# single bend should suffice
self.path_to(portspec_src, angle < pi, x=xd, **kwargs)
self.path_to(portspec_src, None, y=yd, **kwargs, **dst_args)
elif numpy.isclose(angle, 0):
if src_is_horizontal and ys == yd:
# straight connector
self.path_to(portspec_src, None, x=xd, **kwargs, **dst_args)
elif not src_is_horizontal and xs == xd:
# straight connector
self.path_to(portspec_src, None, y=yd, **kwargs, **dst_args)
elif src_is_horizontal:
# figure out how much x our y-segment (2nd) takes up, then path based on that
y_len = numpy.abs(yd - ys)
ccw2 = src_ne != (yd > ys)
jog = get_jog(ccw2, y_len) * numpy.sign(xd - xs)
self.path_to(portspec_src, not ccw2, x=xd - jog, **kwargs)
self.path_to(portspec_src, ccw2, y=yd, **kwargs, **dst_args)
else:
# figure out how much y our x-segment (2nd) takes up, then path based on that
x_len = numpy.abs(xd - xs)
ccw2 = src_ne != (xd < xs)
jog = get_jog(ccw2, x_len) * numpy.sign(yd - ys)
self.path_to(portspec_src, not ccw2, y=yd - jog, **kwargs)
self.path_to(portspec_src, ccw2, x=xd, **kwargs, **dst_args)
elif numpy.isclose(angle, pi):
raise BuildError(f'Don\'t know how to route a U-bend at this time!')
else:
raise BuildError(f'Don\'t know how to route ports with relative angle {angle}')
return self
def mpath( def mpath(
self, self,
portspec: str | Sequence[str], portspec: str | Sequence[str],

Loading…
Cancel
Save