Compare commits
6 Commits
8d91fb4915
...
7c5c1c26c8
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c5c1c26c8 | |||
| fcd3d9663d | |||
| 2b7b1cd6e2 | |||
| dfd61b3a39 | |||
| 3a1a4b9126 | |||
| 8a0c985e36 |
@ -80,6 +80,7 @@ from .builder import (
|
|||||||
SimpleTool as SimpleTool,
|
SimpleTool as SimpleTool,
|
||||||
AutoTool as AutoTool,
|
AutoTool as AutoTool,
|
||||||
PathTool as PathTool,
|
PathTool as PathTool,
|
||||||
|
PortPather as PortPather,
|
||||||
)
|
)
|
||||||
from .utils import (
|
from .utils import (
|
||||||
ports2data as ports2data,
|
ports2data as ports2data,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
from .builder import Builder as Builder
|
from .builder import Builder as Builder
|
||||||
from .pather import Pather as Pather
|
from .pather import Pather as Pather
|
||||||
from .renderpather import RenderPather as RenderPather
|
from .renderpather import RenderPather as RenderPather
|
||||||
|
from .pather_mixin import PortPather as PortPather
|
||||||
from .utils import ell as ell
|
from .utils import ell as ell
|
||||||
from .tools import (
|
from .tools import (
|
||||||
Tool as Tool,
|
Tool as Tool,
|
||||||
|
|||||||
@ -67,7 +67,7 @@ class Builder(PortList):
|
|||||||
|
|
||||||
- `my_device.plug(wire, {'myport': 'A'})` places port 'A' of `wire` at 'myport'
|
- `my_device.plug(wire, {'myport': 'A'})` places port 'A' of `wire` at 'myport'
|
||||||
of `my_device`. If `wire` has only two ports (e.g. 'A' and 'B'), no `map_out`,
|
of `my_device`. If `wire` has only two ports (e.g. 'A' and 'B'), no `map_out`,
|
||||||
argument is provided, and the `inherit_name` argument is not explicitly
|
argument is provided, and the `thru` argument is not explicitly
|
||||||
set to `False`, the unconnected port of `wire` is automatically renamed to
|
set to `False`, the unconnected port of `wire` is automatically renamed to
|
||||||
'myport'. This allows easy extension of existing ports without changing
|
'myport'. This allows easy extension of existing ports without changing
|
||||||
their names or having to provide `map_out` each time `plug` is called.
|
their names or having to provide `map_out` each time `plug` is called.
|
||||||
@ -223,7 +223,7 @@ class Builder(PortList):
|
|||||||
map_out: dict[str, str | None] | None = None,
|
map_out: dict[str, str | None] | None = None,
|
||||||
*,
|
*,
|
||||||
mirrored: bool = False,
|
mirrored: bool = False,
|
||||||
inherit_name: bool = True,
|
thru: bool | str = True,
|
||||||
set_rotation: bool | None = None,
|
set_rotation: bool | None = None,
|
||||||
append: bool = False,
|
append: bool = False,
|
||||||
ok_connections: Iterable[tuple[str, str]] = (),
|
ok_connections: Iterable[tuple[str, str]] = (),
|
||||||
@ -246,11 +246,15 @@ class Builder(PortList):
|
|||||||
new names for ports in `other`.
|
new names for ports in `other`.
|
||||||
mirrored: Enables mirroring `other` across the x axis prior to
|
mirrored: Enables mirroring `other` across the x axis prior to
|
||||||
connecting any ports.
|
connecting any ports.
|
||||||
inherit_name: If `True`, and `map_in` specifies only a single port,
|
thru: If map_in specifies only a single port, `thru` provides a mechainsm
|
||||||
and `map_out` is `None`, and `other` has only two ports total,
|
to avoid repeating the port name. Eg, for `map_in={'myport': 'A'}`,
|
||||||
then automatically renames the output port of `other` to the
|
- If True (default), and `other` has only two ports total, and map_out
|
||||||
name of the port from `self` that appears in `map_in`. This
|
doesn't specify a name for the other port, its name is set to the key
|
||||||
makes it easy to extend a device with simple 2-port devices
|
in `map_in`, i.e. 'myport'.
|
||||||
|
- If a string, `map_out[thru]` is set to the key in `map_in` (i.e. 'myport').
|
||||||
|
An error is raised if that entry already exists.
|
||||||
|
|
||||||
|
This makes it easy to extend a pattern with simple 2-port devices
|
||||||
(e.g. wires) without providing `map_out` each time `plug` is
|
(e.g. wires) without providing `map_out` each time `plug` is
|
||||||
called. See "Examples" above for more info. Default `True`.
|
called. See "Examples" above for more info. Default `True`.
|
||||||
set_rotation: If the necessary rotation cannot be determined from
|
set_rotation: If the necessary rotation cannot be determined from
|
||||||
@ -296,7 +300,7 @@ class Builder(PortList):
|
|||||||
map_in = map_in,
|
map_in = map_in,
|
||||||
map_out = map_out,
|
map_out = map_out,
|
||||||
mirrored = mirrored,
|
mirrored = mirrored,
|
||||||
inherit_name = inherit_name,
|
thru = thru,
|
||||||
set_rotation = set_rotation,
|
set_rotation = set_rotation,
|
||||||
append = append,
|
append = append,
|
||||||
ok_connections = ok_connections,
|
ok_connections = ok_connections,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from typing import Self
|
from typing import Self, TYPE_CHECKING
|
||||||
from collections.abc import Sequence, Iterator
|
from collections.abc import Sequence, Iterator
|
||||||
import logging
|
import logging
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
@ -11,11 +11,15 @@ from numpy.typing import ArrayLike
|
|||||||
from ..pattern import Pattern
|
from ..pattern import Pattern
|
||||||
from ..library import ILibrary
|
from ..library import ILibrary
|
||||||
from ..error import PortError, BuildError
|
from ..error import PortError, BuildError
|
||||||
from ..utils import rotation_matrix_2d, SupportsBool
|
from ..utils import SupportsBool
|
||||||
#from ..abstract import Abstract
|
from ..abstract import Abstract
|
||||||
from .tools import Tool
|
from .tools import Tool
|
||||||
from .utils import ell
|
from .utils import ell
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from .pather import Pather
|
||||||
|
from .renderpather import RenderPather
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -435,3 +439,88 @@ class PatherMixin(metaclass=ABCMeta):
|
|||||||
"""
|
"""
|
||||||
self.pattern.flatten(self.library)
|
self.pattern.flatten(self.library)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PortPather:
|
||||||
|
"""
|
||||||
|
Single-port state manager
|
||||||
|
|
||||||
|
This class provides a convenient way to perform multiple pathing operations on a
|
||||||
|
port without needing to repeatedly pass its name.
|
||||||
|
"""
|
||||||
|
port: str
|
||||||
|
pather: 'Pather | RenderPather'
|
||||||
|
|
||||||
|
def __init__(self, port: str, pather: 'Pather | RenderPather') -> None:
|
||||||
|
self.port = port
|
||||||
|
self.pather = pather
|
||||||
|
|
||||||
|
#
|
||||||
|
# Delegate to pather
|
||||||
|
#
|
||||||
|
def retool(self, tool: Tool) -> Self:
|
||||||
|
self.pather.retool(tool, keys=[self.port])
|
||||||
|
return self
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def toolctx(self, tool: Tool) -> Iterator[Self]:
|
||||||
|
with self.pather.toolctx(tool, keys=[self.port]):
|
||||||
|
yield self
|
||||||
|
|
||||||
|
def path(self, *args, **kwargs) -> Self:
|
||||||
|
self.pather.path(self.port, *args, **kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def pathS(self, *args, **kwargs) -> Self:
|
||||||
|
self.pather.pathS(self.port, *args, **kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def path_to(self, *args, **kwargs) -> Self:
|
||||||
|
self.pather.path_to(self.port, *args, **kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def path_into(self, *args, **kwargs) -> Self:
|
||||||
|
self.pather.path_into(self.port, *args, **kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def path_from(self, *args, **kwargs) -> Self:
|
||||||
|
self.pather.path_into(args[0], self.port, *args[1:], **kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def mpath(self, *args, **kwargs) -> Self:
|
||||||
|
self.pather.mpath([self.port], *args, **kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def plug(
|
||||||
|
self,
|
||||||
|
other: Abstract | str,
|
||||||
|
other_port: str,
|
||||||
|
*args,
|
||||||
|
**kwargs,
|
||||||
|
) -> Self:
|
||||||
|
self.pather.plug(other, {self.port: other_port}, *args, **kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def plugged(self, other_port: str) -> Self:
|
||||||
|
self.pather.plugged({self.port: other_port})
|
||||||
|
return self
|
||||||
|
|
||||||
|
#
|
||||||
|
# Delegate to port
|
||||||
|
#
|
||||||
|
def set_ptype(self, ptype: str) -> Self:
|
||||||
|
self.pather[self.port].set_ptype(ptype)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def mirror(self, *args, **kwargs) -> Self:
|
||||||
|
self.pather[self.port].mirror(*args, **kwargs)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def rotate(self, rotation: float) -> Self:
|
||||||
|
self.pather[self.port].rotate(rotation)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def set_rotation(self, rotation: float | None) -> Self:
|
||||||
|
self.pather[self.port].set_rotation(rotation)
|
||||||
|
return self
|
||||||
|
|||||||
@ -193,7 +193,7 @@ class RenderPather(PortList, PatherMixin):
|
|||||||
map_out: dict[str, str | None] | None = None,
|
map_out: dict[str, str | None] | None = None,
|
||||||
*,
|
*,
|
||||||
mirrored: bool = False,
|
mirrored: bool = False,
|
||||||
inherit_name: bool = True,
|
thru: bool | str = True,
|
||||||
set_rotation: bool | None = None,
|
set_rotation: bool | None = None,
|
||||||
append: bool = False,
|
append: bool = False,
|
||||||
) -> Self:
|
) -> Self:
|
||||||
@ -210,11 +210,15 @@ class RenderPather(PortList, PatherMixin):
|
|||||||
new names for ports in `other`.
|
new names for ports in `other`.
|
||||||
mirrored: Enables mirroring `other` across the x axis prior to
|
mirrored: Enables mirroring `other` across the x axis prior to
|
||||||
connecting any ports.
|
connecting any ports.
|
||||||
inherit_name: If `True`, and `map_in` specifies only a single port,
|
thru: If map_in specifies only a single port, `thru` provides a mechainsm
|
||||||
and `map_out` is `None`, and `other` has only two ports total,
|
to avoid repeating the port name. Eg, for `map_in={'myport': 'A'}`,
|
||||||
then automatically renames the output port of `other` to the
|
- If True (default), and `other` has only two ports total, and map_out
|
||||||
name of the port from `self` that appears in `map_in`. This
|
doesn't specify a name for the other port, its name is set to the key
|
||||||
makes it easy to extend a device with simple 2-port devices
|
in `map_in`, i.e. 'myport'.
|
||||||
|
- If a string, `map_out[thru]` is set to the key in `map_in` (i.e. 'myport').
|
||||||
|
An error is raised if that entry already exists.
|
||||||
|
|
||||||
|
This makes it easy to extend a pattern with simple 2-port devices
|
||||||
(e.g. wires) without providing `map_out` each time `plug` is
|
(e.g. wires) without providing `map_out` each time `plug` is
|
||||||
called. See "Examples" above for more info. Default `True`.
|
called. See "Examples" above for more info. Default `True`.
|
||||||
set_rotation: If the necessary rotation cannot be determined from
|
set_rotation: If the necessary rotation cannot be determined from
|
||||||
@ -265,7 +269,7 @@ class RenderPather(PortList, PatherMixin):
|
|||||||
map_in = map_in,
|
map_in = map_in,
|
||||||
map_out = map_out,
|
map_out = map_out,
|
||||||
mirrored = mirrored,
|
mirrored = mirrored,
|
||||||
inherit_name=inherit_name,
|
thru = thru,
|
||||||
set_rotation = set_rotation,
|
set_rotation = set_rotation,
|
||||||
append = append,
|
append = append,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1202,7 +1202,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
# map_out: dict[str, str | None] | None,
|
# map_out: dict[str, str | None] | None,
|
||||||
# *,
|
# *,
|
||||||
# mirrored: bool,
|
# mirrored: bool,
|
||||||
# inherit_name: bool,
|
# thru: bool | str,
|
||||||
# set_rotation: bool | None,
|
# set_rotation: bool | None,
|
||||||
# append: Literal[False],
|
# append: Literal[False],
|
||||||
# ) -> Self:
|
# ) -> Self:
|
||||||
@ -1216,7 +1216,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
# map_out: dict[str, str | None] | None,
|
# map_out: dict[str, str | None] | None,
|
||||||
# *,
|
# *,
|
||||||
# mirrored: bool,
|
# mirrored: bool,
|
||||||
# inherit_name: bool,
|
# thru: bool | str,
|
||||||
# set_rotation: bool | None,
|
# set_rotation: bool | None,
|
||||||
# append: bool,
|
# append: bool,
|
||||||
# ) -> Self:
|
# ) -> Self:
|
||||||
@ -1229,7 +1229,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
map_out: dict[str, str | None] | None = None,
|
map_out: dict[str, str | None] | None = None,
|
||||||
*,
|
*,
|
||||||
mirrored: bool = False,
|
mirrored: bool = False,
|
||||||
inherit_name: bool = True,
|
thru: bool | str = True,
|
||||||
set_rotation: bool | None = None,
|
set_rotation: bool | None = None,
|
||||||
append: bool = False,
|
append: bool = False,
|
||||||
ok_connections: Iterable[tuple[str, str]] = (),
|
ok_connections: Iterable[tuple[str, str]] = (),
|
||||||
@ -1250,7 +1250,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
- `my_pat.plug(wire, {'myport': 'A'})` places port 'A' of `wire` at 'myport'
|
- `my_pat.plug(wire, {'myport': 'A'})` places port 'A' of `wire` at 'myport'
|
||||||
of `my_pat`.
|
of `my_pat`.
|
||||||
If `wire` has only two ports (e.g. 'A' and 'B'), no `map_out` argument is
|
If `wire` has only two ports (e.g. 'A' and 'B'), no `map_out` argument is
|
||||||
provided, and the `inherit_name` argument is not explicitly set to `False`,
|
provided, and the `thru` argument is not explicitly set to `False`,
|
||||||
the unconnected port of `wire` is automatically renamed to 'myport'. This
|
the unconnected port of `wire` is automatically renamed to 'myport'. This
|
||||||
allows easy extension of existing ports without changing their names or
|
allows easy extension of existing ports without changing their names or
|
||||||
having to provide `map_out` each time `plug` is called.
|
having to provide `map_out` each time `plug` is called.
|
||||||
@ -1263,11 +1263,15 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
new names for ports in `other`.
|
new names for ports in `other`.
|
||||||
mirrored: Enables mirroring `other` across the x axis prior to connecting
|
mirrored: Enables mirroring `other` across the x axis prior to connecting
|
||||||
any ports.
|
any ports.
|
||||||
inherit_name: If `True`, and `map_in` specifies only a single port,
|
thru: If map_in specifies only a single port, `thru` provides a mechainsm
|
||||||
and `map_out` is `None`, and `other` has only two ports total,
|
to avoid repeating the port name. Eg, for `map_in={'myport': 'A'}`,
|
||||||
then automatically renames the output port of `other` to the
|
- If True (default), and `other` has only two ports total, and map_out
|
||||||
name of the port from `self` that appears in `map_in`. This
|
doesn't specify a name for the other port, its name is set to the key
|
||||||
makes it easy to extend a pattern with simple 2-port devices
|
in `map_in`, i.e. 'myport'.
|
||||||
|
- If a string, `map_out[thru]` is set to the key in `map_in` (i.e. 'myport').
|
||||||
|
An error is raised if that entry already exists.
|
||||||
|
|
||||||
|
This makes it easy to extend a pattern with simple 2-port devices
|
||||||
(e.g. wires) without providing `map_out` each time `plug` is
|
(e.g. wires) without providing `map_out` each time `plug` is
|
||||||
called. See "Examples" above for more info. Default `True`.
|
called. See "Examples" above for more info. Default `True`.
|
||||||
set_rotation: If the necessary rotation cannot be determined from
|
set_rotation: If the necessary rotation cannot be determined from
|
||||||
@ -1295,18 +1299,25 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
`PortError` if the specified port mapping is not achieveable (the ports
|
`PortError` if the specified port mapping is not achieveable (the ports
|
||||||
do not line up)
|
do not line up)
|
||||||
"""
|
"""
|
||||||
# If asked to inherit a name, check that all conditions are met
|
|
||||||
if (inherit_name
|
|
||||||
and not map_out
|
|
||||||
and len(map_in) == 1
|
|
||||||
and len(other.ports) == 2):
|
|
||||||
out_port_name = next(iter(set(other.ports.keys()) - set(map_in.values())))
|
|
||||||
map_out = {out_port_name: next(iter(map_in.keys()))}
|
|
||||||
|
|
||||||
if map_out is None:
|
if map_out is None:
|
||||||
map_out = {}
|
map_out = {}
|
||||||
map_out = copy.deepcopy(map_out)
|
map_out = copy.deepcopy(map_out)
|
||||||
|
|
||||||
|
# If asked to inherit a name, check that all conditions are met
|
||||||
|
if isinstance(thru, str):
|
||||||
|
if not len(map_in) == 1:
|
||||||
|
raise PatternError(f'Got {thru=} but have multiple map_in entries; don\'t know which one to use')
|
||||||
|
if thru in map_out:
|
||||||
|
raise PatternError(f'Got {thru=} but tha port already exists in map_out')
|
||||||
|
map_out[thru] = next(iter(map_in.keys()))
|
||||||
|
elif (bool(thru)
|
||||||
|
and len(map_in) == 1
|
||||||
|
and not map_out
|
||||||
|
and len(other.ports) == 2
|
||||||
|
):
|
||||||
|
out_port_name = next(iter(set(other.ports.keys()) - set(map_in.values())))
|
||||||
|
map_out = {out_port_name: next(iter(map_in.keys()))}
|
||||||
|
|
||||||
self.check_ports(other.ports.keys(), map_in, map_out)
|
self.check_ports(other.ports.keys(), map_in, map_out)
|
||||||
translation, rotation, pivot = self.find_transform(
|
translation, rotation, pivot = self.find_transform(
|
||||||
other,
|
other,
|
||||||
|
|||||||
@ -56,6 +56,7 @@ dxf = ["ezdxf~=1.0.2"]
|
|||||||
svg = ["svgwrite"]
|
svg = ["svgwrite"]
|
||||||
visualize = ["matplotlib"]
|
visualize = ["matplotlib"]
|
||||||
text = ["matplotlib", "freetype-py"]
|
text = ["matplotlib", "freetype-py"]
|
||||||
|
manhatanize_slow = ["float_raster"]
|
||||||
|
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user