use Self type
This commit is contained in:
parent
1463535676
commit
4482ede3a7
@ -1,4 +1,4 @@
|
|||||||
from typing import TypeVar
|
from typing import Self
|
||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -17,9 +17,6 @@ from .utils import rotation_matrix_2d, normalize_mirror
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
AA = TypeVar('AA', bound='Abstract')
|
|
||||||
|
|
||||||
|
|
||||||
class Abstract(PortList):
|
class Abstract(PortList):
|
||||||
__slots__ = ('name', '_ports')
|
__slots__ = ('name', '_ports')
|
||||||
|
|
||||||
@ -71,7 +68,7 @@ class Abstract(PortList):
|
|||||||
s += ']>'
|
s += ']>'
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def translate_ports(self: AA, offset: ArrayLike) -> AA:
|
def translate_ports(self, offset: ArrayLike) -> Self:
|
||||||
"""
|
"""
|
||||||
Translates all ports by the given offset.
|
Translates all ports by the given offset.
|
||||||
|
|
||||||
@ -85,7 +82,7 @@ class Abstract(PortList):
|
|||||||
port.translate(offset)
|
port.translate(offset)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def scale_by(self: AA, c: float) -> AA:
|
def scale_by(self, c: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Scale this Abstract by the given value
|
Scale this Abstract by the given value
|
||||||
(all port offsets are scaled)
|
(all port offsets are scaled)
|
||||||
@ -100,7 +97,7 @@ class Abstract(PortList):
|
|||||||
port.offset *= c
|
port.offset *= c
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def rotate_around(self: AA, pivot: ArrayLike, rotation: float) -> AA:
|
def rotate_around(self, pivot: ArrayLike, rotation: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Rotate the Abstract around the a location.
|
Rotate the Abstract around the a location.
|
||||||
|
|
||||||
@ -118,7 +115,7 @@ class Abstract(PortList):
|
|||||||
self.translate_ports(+pivot)
|
self.translate_ports(+pivot)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def rotate_port_offsets(self: AA, rotation: float) -> AA:
|
def rotate_port_offsets(self, rotation: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Rotate the offsets of all ports around (0, 0)
|
Rotate the offsets of all ports around (0, 0)
|
||||||
|
|
||||||
@ -132,7 +129,7 @@ class Abstract(PortList):
|
|||||||
port.offset = rotation_matrix_2d(rotation) @ port.offset
|
port.offset = rotation_matrix_2d(rotation) @ port.offset
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def rotate_ports(self: AA, rotation: float) -> AA:
|
def rotate_ports(self, rotation: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Rotate each port around its offset (i.e. in place)
|
Rotate each port around its offset (i.e. in place)
|
||||||
|
|
||||||
@ -146,7 +143,7 @@ class Abstract(PortList):
|
|||||||
port.rotate(rotation)
|
port.rotate(rotation)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def mirror_port_offsets(self: AA, across_axis: int) -> AA:
|
def mirror_port_offsets(self, across_axis: int) -> Self:
|
||||||
"""
|
"""
|
||||||
Mirror the offsets of all shapes, labels, and refs across an axis
|
Mirror the offsets of all shapes, labels, and refs across an axis
|
||||||
|
|
||||||
@ -161,7 +158,7 @@ class Abstract(PortList):
|
|||||||
port.offset[across_axis - 1] *= -1
|
port.offset[across_axis - 1] *= -1
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def mirror_ports(self: AA, across_axis: int) -> AA:
|
def mirror_ports(self, across_axis: int) -> Self:
|
||||||
"""
|
"""
|
||||||
Mirror each port's rotation across an axis, relative to its
|
Mirror each port's rotation across an axis, relative to its
|
||||||
offset
|
offset
|
||||||
@ -177,7 +174,7 @@ class Abstract(PortList):
|
|||||||
port.mirror(across_axis)
|
port.mirror(across_axis)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def mirror(self: AA, across_axis: int) -> AA:
|
def mirror(self, across_axis: int) -> Self:
|
||||||
"""
|
"""
|
||||||
Mirror the Pattern across an axis
|
Mirror the Pattern across an axis
|
||||||
|
|
||||||
@ -192,7 +189,7 @@ class Abstract(PortList):
|
|||||||
self.mirror_port_offsets(across_axis)
|
self.mirror_port_offsets(across_axis)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def apply_ref_transform(self: AA, ref: Ref) -> AA:
|
def apply_ref_transform(self, ref: Ref) -> Self:
|
||||||
"""
|
"""
|
||||||
Apply the transform from a `Ref` to the ports of this `Abstract`.
|
Apply the transform from a `Ref` to the ports of this `Abstract`.
|
||||||
This changes the port locations to where they would be in the Ref's parent pattern.
|
This changes the port locations to where they would be in the Ref's parent pattern.
|
||||||
@ -211,7 +208,7 @@ class Abstract(PortList):
|
|||||||
self.translate_ports(ref.offset)
|
self.translate_ports(ref.offset)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def undo_ref_transform(self: AA, ref: Ref) -> AA:
|
def undo_ref_transform(self, ref: Ref) -> Self:
|
||||||
"""
|
"""
|
||||||
Apply the inverse transform from a `Ref` to the ports of this `Abstract`.
|
Apply the inverse transform from a `Ref` to the ports of this `Abstract`.
|
||||||
This changes the port locations to where they would be in the Ref's target (from the parent).
|
This changes the port locations to where they would be in the Ref's target (from the parent).
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import TypeVar, Sequence, MutableMapping, Mapping
|
from typing import Self, Sequence, MutableMapping, Mapping
|
||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -20,10 +20,6 @@ from .utils import ell
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
BB = TypeVar('BB', bound='Builder')
|
|
||||||
PP = TypeVar('PP', bound='Pather')
|
|
||||||
|
|
||||||
|
|
||||||
class Builder(PortList):
|
class Builder(PortList):
|
||||||
"""
|
"""
|
||||||
TODO DOCUMENT Builder
|
TODO DOCUMENT Builder
|
||||||
@ -239,7 +235,7 @@ class Builder(PortList):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def plug(
|
def plug(
|
||||||
self: BB,
|
self,
|
||||||
other: Abstract | str | NamedPattern,
|
other: Abstract | str | NamedPattern,
|
||||||
map_in: dict[str, str],
|
map_in: dict[str, str],
|
||||||
map_out: dict[str, str | None] | None = None,
|
map_out: dict[str, str | None] | None = None,
|
||||||
@ -247,7 +243,7 @@ class Builder(PortList):
|
|||||||
mirrored: tuple[bool, bool] = (False, False),
|
mirrored: tuple[bool, bool] = (False, False),
|
||||||
inherit_name: bool = True,
|
inherit_name: bool = True,
|
||||||
set_rotation: bool | None = None,
|
set_rotation: bool | None = None,
|
||||||
) -> BB:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Instantiate a device `library[name]` into the current device, connecting
|
Instantiate a device `library[name]` into the current device, connecting
|
||||||
the ports specified by `map_in` and renaming the unconnected
|
the ports specified by `map_in` and renaming the unconnected
|
||||||
@ -340,7 +336,7 @@ class Builder(PortList):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def place(
|
def place(
|
||||||
self: BB,
|
self,
|
||||||
other: Abstract | str | NamedPattern,
|
other: Abstract | str | NamedPattern,
|
||||||
*,
|
*,
|
||||||
offset: ArrayLike = (0, 0),
|
offset: ArrayLike = (0, 0),
|
||||||
@ -349,7 +345,7 @@ class Builder(PortList):
|
|||||||
mirrored: tuple[bool, bool] = (False, False),
|
mirrored: tuple[bool, bool] = (False, False),
|
||||||
port_map: dict[str, str | None] | None = None,
|
port_map: dict[str, str | None] | None = None,
|
||||||
skip_port_check: bool = False,
|
skip_port_check: bool = False,
|
||||||
) -> BB:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Instantiate the device `other` into the current device, adding its
|
Instantiate the device `other` into the current device, adding its
|
||||||
ports to those of the current device (but not connecting any ports).
|
ports to those of the current device (but not connecting any ports).
|
||||||
@ -422,7 +418,7 @@ class Builder(PortList):
|
|||||||
self.pattern.refs.append(sp)
|
self.pattern.refs.append(sp)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def translate(self: BB, offset: ArrayLike) -> BB:
|
def translate(self, offset: ArrayLike) -> Self:
|
||||||
"""
|
"""
|
||||||
Translate the pattern and all ports.
|
Translate the pattern and all ports.
|
||||||
|
|
||||||
@ -437,7 +433,7 @@ class Builder(PortList):
|
|||||||
port.translate(offset)
|
port.translate(offset)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def rotate_around(self: BB, pivot: ArrayLike, angle: float) -> BB:
|
def rotate_around(self, pivot: ArrayLike, angle: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Rotate the pattern and all ports.
|
Rotate the pattern and all ports.
|
||||||
|
|
||||||
@ -453,7 +449,7 @@ class Builder(PortList):
|
|||||||
port.rotate_around(pivot, angle)
|
port.rotate_around(pivot, angle)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def mirror(self: BB, axis: int) -> BB:
|
def mirror(self, axis: int) -> Self:
|
||||||
"""
|
"""
|
||||||
Mirror the pattern and all ports across the specified axis.
|
Mirror the pattern and all ports across the specified axis.
|
||||||
|
|
||||||
@ -468,7 +464,7 @@ class Builder(PortList):
|
|||||||
p.mirror(axis)
|
p.mirror(axis)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def set_dead(self: BB) -> BB:
|
def set_dead(self) -> Self:
|
||||||
"""
|
"""
|
||||||
Disallows further changes through `plug()` or `place()`.
|
Disallows further changes through `plug()` or `place()`.
|
||||||
This is meant for debugging:
|
This is meant for debugging:
|
||||||
@ -673,10 +669,10 @@ class Pather(Builder):
|
|||||||
return s
|
return s
|
||||||
|
|
||||||
def retool(
|
def retool(
|
||||||
self: PP,
|
self,
|
||||||
tool: Tool,
|
tool: Tool,
|
||||||
keys: str | Sequence[str | None] | None = None,
|
keys: str | Sequence[str | None] | None = None,
|
||||||
) -> PP:
|
) -> Self:
|
||||||
if keys is None or isinstance(keys, str):
|
if keys is None or isinstance(keys, str):
|
||||||
self.tools[keys] = tool
|
self.tools[keys] = tool
|
||||||
else:
|
else:
|
||||||
@ -685,7 +681,7 @@ class Pather(Builder):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def path(
|
def path(
|
||||||
self: PP,
|
self,
|
||||||
portspec: str,
|
portspec: str,
|
||||||
ccw: SupportsBool | None,
|
ccw: SupportsBool | None,
|
||||||
length: float,
|
length: float,
|
||||||
@ -693,7 +689,7 @@ class Pather(Builder):
|
|||||||
tool_port_names: Sequence[str] = ('A', 'B'),
|
tool_port_names: Sequence[str] = ('A', 'B'),
|
||||||
base_name: str = '_path',
|
base_name: str = '_path',
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> PP:
|
) -> Self:
|
||||||
if self._dead:
|
if self._dead:
|
||||||
logger.error('Skipping path() since device is dead')
|
logger.error('Skipping path() since device is dead')
|
||||||
return self
|
return self
|
||||||
@ -706,7 +702,7 @@ class Pather(Builder):
|
|||||||
return self.plug(Abstract(name, pat.ports), {portspec: tool_port_names[0]})
|
return self.plug(Abstract(name, pat.ports), {portspec: tool_port_names[0]})
|
||||||
|
|
||||||
def path_to(
|
def path_to(
|
||||||
self: PP,
|
self,
|
||||||
portspec: str,
|
portspec: str,
|
||||||
ccw: SupportsBool | None,
|
ccw: SupportsBool | None,
|
||||||
position: float,
|
position: float,
|
||||||
@ -714,7 +710,7 @@ class Pather(Builder):
|
|||||||
tool_port_names: Sequence[str] = ('A', 'B'),
|
tool_port_names: Sequence[str] = ('A', 'B'),
|
||||||
base_name: str = '_pathto',
|
base_name: str = '_pathto',
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> PP:
|
) -> Self:
|
||||||
if self._dead:
|
if self._dead:
|
||||||
logger.error('Skipping path_to() since device is dead')
|
logger.error('Skipping path_to() since device is dead')
|
||||||
return self
|
return self
|
||||||
@ -740,7 +736,7 @@ class Pather(Builder):
|
|||||||
return self.path(portspec, ccw, length, tool_port_names=tool_port_names, base_name=base_name, **kwargs)
|
return self.path(portspec, ccw, length, tool_port_names=tool_port_names, base_name=base_name, **kwargs)
|
||||||
|
|
||||||
def mpath(
|
def mpath(
|
||||||
self: PP,
|
self,
|
||||||
portspec: str | Sequence[str],
|
portspec: str | Sequence[str],
|
||||||
ccw: SupportsBool | None,
|
ccw: SupportsBool | None,
|
||||||
*,
|
*,
|
||||||
@ -750,7 +746,7 @@ class Pather(Builder):
|
|||||||
force_container: bool = False,
|
force_container: bool = False,
|
||||||
base_name: str = '_mpath',
|
base_name: str = '_mpath',
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> PP:
|
) -> Self:
|
||||||
if self._dead:
|
if self._dead:
|
||||||
logger.error('Skipping mpath() since device is dead')
|
logger.error('Skipping mpath() since device is dead')
|
||||||
return self
|
return self
|
||||||
@ -790,7 +786,7 @@ class Pather(Builder):
|
|||||||
|
|
||||||
# TODO def path_join() and def bus_join()?
|
# TODO def path_join() and def bus_join()?
|
||||||
|
|
||||||
def flatten(self: PP) -> PP:
|
def flatten(self) -> Self:
|
||||||
"""
|
"""
|
||||||
Flatten the contained pattern, using the contained library to resolve references.
|
Flatten the contained pattern, using the contained library to resolve references.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import TypeVar, Sequence, MutableMapping, Mapping
|
from typing import Self, Sequence, MutableMapping, Mapping
|
||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -17,9 +17,6 @@ from .utils import ell
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
BB = TypeVar('BB', bound='FlatBuilder')
|
|
||||||
|
|
||||||
|
|
||||||
class FlatBuilder(PortList):
|
class FlatBuilder(PortList):
|
||||||
"""
|
"""
|
||||||
TODO DOCUMENT FlatBuilder
|
TODO DOCUMENT FlatBuilder
|
||||||
@ -173,7 +170,7 @@ class FlatBuilder(PortList):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def plug(
|
def plug(
|
||||||
self: BB,
|
self,
|
||||||
other: Pattern,
|
other: Pattern,
|
||||||
map_in: dict[str, str],
|
map_in: dict[str, str],
|
||||||
map_out: dict[str, str | None] | None = None,
|
map_out: dict[str, str | None] | None = None,
|
||||||
@ -181,7 +178,7 @@ class FlatBuilder(PortList):
|
|||||||
mirrored: tuple[bool, bool] = (False, False),
|
mirrored: tuple[bool, bool] = (False, False),
|
||||||
inherit_name: bool = True,
|
inherit_name: bool = True,
|
||||||
set_rotation: bool | None = None,
|
set_rotation: bool | None = None,
|
||||||
) -> BB:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Instantiate another pattern into the current device, connecting
|
Instantiate another pattern into the current device, connecting
|
||||||
the ports specified by `map_in` and renaming the unconnected
|
the ports specified by `map_in` and renaming the unconnected
|
||||||
@ -269,7 +266,7 @@ class FlatBuilder(PortList):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def place(
|
def place(
|
||||||
self: BB,
|
self,
|
||||||
other: Pattern,
|
other: Pattern,
|
||||||
*,
|
*,
|
||||||
offset: ArrayLike = (0, 0),
|
offset: ArrayLike = (0, 0),
|
||||||
@ -278,7 +275,7 @@ class FlatBuilder(PortList):
|
|||||||
mirrored: tuple[bool, bool] = (False, False),
|
mirrored: tuple[bool, bool] = (False, False),
|
||||||
port_map: dict[str, str | None] | None = None,
|
port_map: dict[str, str | None] | None = None,
|
||||||
skip_port_check: bool = False,
|
skip_port_check: bool = False,
|
||||||
) -> BB:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Instantiate the device `other` into the current device, adding its
|
Instantiate the device `other` into the current device, adding its
|
||||||
ports to those of the current device (but not connecting any ports).
|
ports to those of the current device (but not connecting any ports).
|
||||||
@ -348,7 +345,7 @@ class FlatBuilder(PortList):
|
|||||||
self.pattern.append(other_copy)
|
self.pattern.append(other_copy)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def translate(self: BB, offset: ArrayLike) -> BB:
|
def translate(self, offset: ArrayLike) -> Self:
|
||||||
"""
|
"""
|
||||||
Translate the pattern and all ports.
|
Translate the pattern and all ports.
|
||||||
|
|
||||||
@ -363,7 +360,7 @@ class FlatBuilder(PortList):
|
|||||||
port.translate(offset)
|
port.translate(offset)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def rotate_around(self: BB, pivot: ArrayLike, angle: float) -> BB:
|
def rotate_around(self, pivot: ArrayLike, angle: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Rotate the pattern and all ports.
|
Rotate the pattern and all ports.
|
||||||
|
|
||||||
@ -379,7 +376,7 @@ class FlatBuilder(PortList):
|
|||||||
port.rotate_around(pivot, angle)
|
port.rotate_around(pivot, angle)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def mirror(self: BB, axis: int) -> BB:
|
def mirror(self, axis: int) -> Self:
|
||||||
"""
|
"""
|
||||||
Mirror the pattern and all ports across the specified axis.
|
Mirror the pattern and all ports across the specified axis.
|
||||||
|
|
||||||
@ -394,7 +391,7 @@ class FlatBuilder(PortList):
|
|||||||
p.mirror(axis)
|
p.mirror(axis)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def set_dead(self: BB) -> BB:
|
def set_dead(self) -> Self:
|
||||||
"""
|
"""
|
||||||
Disallows further changes through `plug()` or `place()`.
|
Disallows further changes through `plug()` or `place()`.
|
||||||
This is meant for debugging:
|
This is meant for debugging:
|
||||||
@ -417,10 +414,10 @@ class FlatBuilder(PortList):
|
|||||||
return s
|
return s
|
||||||
|
|
||||||
def retool(
|
def retool(
|
||||||
self: BB,
|
self,
|
||||||
tool: Tool,
|
tool: Tool,
|
||||||
keys: str | Sequence[str | None] | None = None,
|
keys: str | Sequence[str | None] | None = None,
|
||||||
) -> BB:
|
) -> Self:
|
||||||
if keys is None or isinstance(keys, str):
|
if keys is None or isinstance(keys, str):
|
||||||
self.tools[keys] = tool
|
self.tools[keys] = tool
|
||||||
else:
|
else:
|
||||||
@ -429,7 +426,7 @@ class FlatBuilder(PortList):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def path(
|
def path(
|
||||||
self: BB,
|
self,
|
||||||
portspec: str,
|
portspec: str,
|
||||||
ccw: SupportsBool | None,
|
ccw: SupportsBool | None,
|
||||||
length: float,
|
length: float,
|
||||||
@ -437,7 +434,7 @@ class FlatBuilder(PortList):
|
|||||||
tool_port_names: Sequence[str] = ('A', 'B'),
|
tool_port_names: Sequence[str] = ('A', 'B'),
|
||||||
base_name: str = '_path',
|
base_name: str = '_path',
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> BB:
|
) -> Self:
|
||||||
if self._dead:
|
if self._dead:
|
||||||
logger.error('Skipping path() since device is dead')
|
logger.error('Skipping path() since device is dead')
|
||||||
return self
|
return self
|
||||||
@ -448,7 +445,7 @@ class FlatBuilder(PortList):
|
|||||||
return self.plug(pat, {portspec: tool_port_names[0]})
|
return self.plug(pat, {portspec: tool_port_names[0]})
|
||||||
|
|
||||||
def path_to(
|
def path_to(
|
||||||
self: BB,
|
self,
|
||||||
portspec: str,
|
portspec: str,
|
||||||
ccw: SupportsBool | None,
|
ccw: SupportsBool | None,
|
||||||
position: float,
|
position: float,
|
||||||
@ -456,7 +453,7 @@ class FlatBuilder(PortList):
|
|||||||
tool_port_names: Sequence[str] = ('A', 'B'),
|
tool_port_names: Sequence[str] = ('A', 'B'),
|
||||||
base_name: str = '_pathto',
|
base_name: str = '_pathto',
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> BB:
|
) -> Self:
|
||||||
if self._dead:
|
if self._dead:
|
||||||
logger.error('Skipping path_to() since device is dead')
|
logger.error('Skipping path_to() since device is dead')
|
||||||
return self
|
return self
|
||||||
@ -482,7 +479,7 @@ class FlatBuilder(PortList):
|
|||||||
return self.path(portspec, ccw, length, tool_port_names=tool_port_names, base_name=base_name, **kwargs)
|
return self.path(portspec, ccw, length, tool_port_names=tool_port_names, base_name=base_name, **kwargs)
|
||||||
|
|
||||||
def mpath(
|
def mpath(
|
||||||
self: BB,
|
self,
|
||||||
portspec: str | Sequence[str],
|
portspec: str | Sequence[str],
|
||||||
ccw: SupportsBool | None,
|
ccw: SupportsBool | None,
|
||||||
*,
|
*,
|
||||||
@ -492,7 +489,7 @@ class FlatBuilder(PortList):
|
|||||||
force_container: bool = False,
|
force_container: bool = False,
|
||||||
base_name: str = '_mpath',
|
base_name: str = '_mpath',
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> BB:
|
) -> Self:
|
||||||
if self._dead:
|
if self._dead:
|
||||||
logger.error('Skipping mpath() since device is dead')
|
logger.error('Skipping mpath() since device is dead')
|
||||||
return self
|
return self
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import TypeVar
|
from typing import Self
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
@ -10,9 +10,6 @@ from .traits import PositionableImpl, LayerableImpl, Copyable, Pivotable, Repeat
|
|||||||
from .traits import AnnotatableImpl
|
from .traits import AnnotatableImpl
|
||||||
|
|
||||||
|
|
||||||
L = TypeVar('L', bound='Label')
|
|
||||||
|
|
||||||
|
|
||||||
class Label(PositionableImpl, LayerableImpl, RepeatableImpl, AnnotatableImpl,
|
class Label(PositionableImpl, LayerableImpl, RepeatableImpl, AnnotatableImpl,
|
||||||
Pivotable, Copyable, metaclass=AutoSlots):
|
Pivotable, Copyable, metaclass=AutoSlots):
|
||||||
"""
|
"""
|
||||||
@ -53,7 +50,7 @@ class Label(PositionableImpl, LayerableImpl, RepeatableImpl, AnnotatableImpl,
|
|||||||
self.repetition = repetition
|
self.repetition = repetition
|
||||||
self.annotations = annotations if annotations is not None else {}
|
self.annotations = annotations if annotations is not None else {}
|
||||||
|
|
||||||
def __copy__(self: L) -> L:
|
def __copy__(self) -> Self:
|
||||||
return type(self)(
|
return type(self)(
|
||||||
string=self.string,
|
string=self.string,
|
||||||
offset=self.offset.copy(),
|
offset=self.offset.copy(),
|
||||||
@ -61,13 +58,13 @@ class Label(PositionableImpl, LayerableImpl, RepeatableImpl, AnnotatableImpl,
|
|||||||
repetition=self.repetition,
|
repetition=self.repetition,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __deepcopy__(self: L, memo: dict | None = None) -> L:
|
def __deepcopy__(self, memo: dict | None = None) -> Self:
|
||||||
memo = {} if memo is None else memo
|
memo = {} if memo is None else memo
|
||||||
new = copy.copy(self)
|
new = copy.copy(self)
|
||||||
new._offset = self._offset.copy()
|
new._offset = self._offset.copy()
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def rotate_around(self: L, pivot: ArrayLike, rotation: float) -> L:
|
def rotate_around(self, pivot: ArrayLike, rotation: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Rotate the label around a point.
|
Rotate the label around a point.
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ Library classes for managing unique name->pattern mappings and
|
|||||||
# TODO documentn all library classes
|
# TODO documentn all library classes
|
||||||
# TODO toplevel documentation of library, classes, and abstracts
|
# TODO toplevel documentation of library, classes, and abstracts
|
||||||
"""
|
"""
|
||||||
from typing import Callable, TypeVar, Type, TYPE_CHECKING, cast
|
from typing import Callable, Self, Type, TYPE_CHECKING, cast
|
||||||
from typing import Iterator, Mapping, MutableMapping, Sequence
|
from typing import Iterator, Mapping, MutableMapping, Sequence
|
||||||
import logging
|
import logging
|
||||||
import base64
|
import base64
|
||||||
@ -33,9 +33,6 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
visitor_function_t = Callable[..., 'Pattern']
|
visitor_function_t = Callable[..., 'Pattern']
|
||||||
L = TypeVar('L', bound='Library')
|
|
||||||
ML = TypeVar('ML', bound='MutableLibrary')
|
|
||||||
LL = TypeVar('LL', bound='LazyLibrary')
|
|
||||||
|
|
||||||
|
|
||||||
def _rename_patterns(lib: 'Library', name: str) -> str:
|
def _rename_patterns(lib: 'Library', name: str) -> str:
|
||||||
@ -163,10 +160,10 @@ class Library(Mapping[str, 'Pattern'], metaclass=ABCMeta):
|
|||||||
return new
|
return new
|
||||||
|
|
||||||
def polygonize(
|
def polygonize(
|
||||||
self: L,
|
self,
|
||||||
num_vertices: int | None = None,
|
num_vertices: int | None = None,
|
||||||
max_arclen: float | None = None,
|
max_arclen: float | None = None,
|
||||||
) -> L:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Calls `.polygonize(...)` on each pattern in this library.
|
Calls `.polygonize(...)` on each pattern in this library.
|
||||||
Arguments are passed on to `shape.to_polygons(...)`.
|
Arguments are passed on to `shape.to_polygons(...)`.
|
||||||
@ -186,10 +183,10 @@ class Library(Mapping[str, 'Pattern'], metaclass=ABCMeta):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def manhattanize(
|
def manhattanize(
|
||||||
self: L,
|
self,
|
||||||
grid_x: ArrayLike,
|
grid_x: ArrayLike,
|
||||||
grid_y: ArrayLike,
|
grid_y: ArrayLike,
|
||||||
) -> L:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Calls `.manhattanize(grid_x, grid_y)` on each pattern in this library.
|
Calls `.manhattanize(grid_x, grid_y)` on each pattern in this library.
|
||||||
|
|
||||||
@ -324,7 +321,7 @@ class Library(Mapping[str, 'Pattern'], metaclass=ABCMeta):
|
|||||||
return toplevel
|
return toplevel
|
||||||
|
|
||||||
def dfs(
|
def dfs(
|
||||||
self: L,
|
self,
|
||||||
pattern: 'Pattern',
|
pattern: 'Pattern',
|
||||||
visit_before: visitor_function_t | None = None,
|
visit_before: visitor_function_t | None = None,
|
||||||
visit_after: visitor_function_t | None = None,
|
visit_after: visitor_function_t | None = None,
|
||||||
@ -332,7 +329,7 @@ class Library(Mapping[str, 'Pattern'], metaclass=ABCMeta):
|
|||||||
hierarchy: tuple[str | None, ...] = (None,),
|
hierarchy: tuple[str | None, ...] = (None,),
|
||||||
transform: ArrayLike | bool | None = False,
|
transform: ArrayLike | bool | None = False,
|
||||||
memo: dict | None = None,
|
memo: dict | None = None,
|
||||||
) -> L:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Convenience function.
|
Convenience function.
|
||||||
Performs a depth-first traversal of a pattern and its referenced patterns.
|
Performs a depth-first traversal of a pattern and its referenced patterns.
|
||||||
@ -454,11 +451,11 @@ class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta)
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def rename(
|
def rename(
|
||||||
self: ML,
|
self,
|
||||||
old_name: str,
|
old_name: str,
|
||||||
new_name: str,
|
new_name: str,
|
||||||
move_references: bool = False,
|
move_references: bool = False,
|
||||||
) -> ML:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Rename a pattern.
|
Rename a pattern.
|
||||||
|
|
||||||
@ -476,7 +473,7 @@ class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta)
|
|||||||
self.move_references(old_name, new_name)
|
self.move_references(old_name, new_name)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def move_references(self: ML, old_target: str, new_target: str) -> ML:
|
def move_references(self, old_target: str, new_target: str) -> Self:
|
||||||
"""
|
"""
|
||||||
Change all references pointing at `old_target` into references pointing at `new_target`.
|
Change all references pointing at `old_target` into references pointing at `new_target`.
|
||||||
|
|
||||||
@ -601,12 +598,12 @@ class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta)
|
|||||||
return rename_map.get(name, name)
|
return rename_map.get(name, name)
|
||||||
|
|
||||||
def dedup(
|
def dedup(
|
||||||
self: ML,
|
self,
|
||||||
norm_value: int = int(1e6),
|
norm_value: int = int(1e6),
|
||||||
exclude_types: tuple[Type] = (Polygon,),
|
exclude_types: tuple[Type] = (Polygon,),
|
||||||
label2name: Callable[[tuple], str] | None = None,
|
label2name: Callable[[tuple], str] | None = None,
|
||||||
threshold: int = 2,
|
threshold: int = 2,
|
||||||
) -> ML:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Iterates through all `Pattern`s. Within each `Pattern`, it iterates
|
Iterates through all `Pattern`s. Within each `Pattern`, it iterates
|
||||||
over all shapes, calling `.normalized_form(norm_value)` on them to retrieve a scale-,
|
over all shapes, calling `.normalized_form(norm_value)` on them to retrieve a scale-,
|
||||||
@ -706,9 +703,9 @@ class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta)
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def wrap_repeated_shapes(
|
def wrap_repeated_shapes(
|
||||||
self: ML,
|
self,
|
||||||
name_func: Callable[['Pattern', Shape | Label], str] | None = None,
|
name_func: Callable[['Pattern', Shape | Label], str] | None = None,
|
||||||
) -> ML:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Wraps all shapes and labels with a non-`None` `repetition` attribute
|
Wraps all shapes and labels with a non-`None` `repetition` attribute
|
||||||
into a `Ref`/`Pattern` combination, and applies the `repetition`
|
into a `Ref`/`Pattern` combination, and applies the `repetition`
|
||||||
@ -755,9 +752,9 @@ class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta)
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def subtree(
|
def subtree(
|
||||||
self: ML,
|
self,
|
||||||
tops: str | Sequence[str],
|
tops: str | Sequence[str],
|
||||||
) -> ML:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Return a new `Library`, containing only the specified patterns and the patterns they
|
Return a new `Library`, containing only the specified patterns and the patterns they
|
||||||
reference (recursively).
|
reference (recursively).
|
||||||
@ -797,10 +794,10 @@ class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta)
|
|||||||
return trimmed
|
return trimmed
|
||||||
|
|
||||||
def delete(
|
def delete(
|
||||||
self: ML,
|
self,
|
||||||
key: str,
|
key: str,
|
||||||
delete_refs: bool = True,
|
delete_refs: bool = True,
|
||||||
) -> ML:
|
) -> Self:
|
||||||
# TODO doc delete()
|
# TODO doc delete()
|
||||||
del self[key]
|
del self[key]
|
||||||
if delete_refs:
|
if delete_refs:
|
||||||
@ -961,11 +958,11 @@ class LazyLibrary(MutableLibrary):
|
|||||||
return '<LazyLibrary with keys\n' + pformat(list(self.keys())) + '>'
|
return '<LazyLibrary with keys\n' + pformat(list(self.keys())) + '>'
|
||||||
|
|
||||||
def rename(
|
def rename(
|
||||||
self: LL,
|
self,
|
||||||
old_name: str,
|
old_name: str,
|
||||||
new_name: str,
|
new_name: str,
|
||||||
move_references: bool = False,
|
move_references: bool = False,
|
||||||
) -> LL:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Rename a pattern.
|
Rename a pattern.
|
||||||
|
|
||||||
@ -989,7 +986,7 @@ class LazyLibrary(MutableLibrary):
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def move_references(self: LL, old_target: str, new_target: str) -> LL:
|
def move_references(self, old_target: str, new_target: str) -> Self:
|
||||||
"""
|
"""
|
||||||
Change all references pointing at `old_target` into references pointing at `new_target`.
|
Change all references pointing at `old_target` into references pointing at `new_target`.
|
||||||
|
|
||||||
@ -1007,7 +1004,7 @@ class LazyLibrary(MutableLibrary):
|
|||||||
ref.target = new_target
|
ref.target = new_target
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def precache(self: LL) -> LL:
|
def precache(self) -> Self:
|
||||||
"""
|
"""
|
||||||
Force all patterns into the cache
|
Force all patterns into the cache
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
Base object representing a lithography mask.
|
Base object representing a lithography mask.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Callable, Sequence, cast, Mapping, TypeVar, Any
|
from typing import Callable, Sequence, cast, Mapping, Self, Any
|
||||||
import copy
|
import copy
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
@ -20,9 +20,6 @@ from .traits import AnnotatableImpl, Scalable, Mirrorable, Rotatable, Positionab
|
|||||||
from .ports import Port, PortList
|
from .ports import Port, PortList
|
||||||
|
|
||||||
|
|
||||||
P = TypeVar('P', bound='Pattern')
|
|
||||||
|
|
||||||
|
|
||||||
class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
||||||
"""
|
"""
|
||||||
2D layout consisting of some set of shapes, labels, and references to other Pattern objects
|
2D layout consisting of some set of shapes, labels, and references to other Pattern objects
|
||||||
@ -128,7 +125,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
)
|
)
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def append(self: P, other_pattern: 'Pattern') -> P:
|
def append(self, other_pattern: 'Pattern') -> Self:
|
||||||
"""
|
"""
|
||||||
Appends all shapes, labels and refs from other_pattern to self's shapes,
|
Appends all shapes, labels and refs from other_pattern to self's shapes,
|
||||||
labels, and supbatterns.
|
labels, and supbatterns.
|
||||||
@ -212,10 +209,10 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
return pat
|
return pat
|
||||||
|
|
||||||
def polygonize(
|
def polygonize(
|
||||||
self: P,
|
self,
|
||||||
num_points: int | None = None,
|
num_points: int | None = None,
|
||||||
max_arclen: float | None = None,
|
max_arclen: float | None = None,
|
||||||
) -> P:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Calls `.to_polygons(...)` on all the shapes in this Pattern, replacing them with the returned polygons.
|
Calls `.to_polygons(...)` on all the shapes in this Pattern, replacing them with the returned polygons.
|
||||||
Arguments are passed directly to `shape.to_polygons(...)`.
|
Arguments are passed directly to `shape.to_polygons(...)`.
|
||||||
@ -237,10 +234,10 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def manhattanize(
|
def manhattanize(
|
||||||
self: P,
|
self,
|
||||||
grid_x: ArrayLike,
|
grid_x: ArrayLike,
|
||||||
grid_y: ArrayLike,
|
grid_y: ArrayLike,
|
||||||
) -> P:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Calls `.polygonize()` on the pattern, then calls `.manhattanize()` on all the
|
Calls `.polygonize()` on the pattern, then calls `.manhattanize()` on all the
|
||||||
resulting shapes, replacing them with the returned Manhattan polygons.
|
resulting shapes, replacing them with the returned Manhattan polygons.
|
||||||
@ -345,7 +342,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
assert bounds is not None
|
assert bounds is not None
|
||||||
return bounds
|
return bounds
|
||||||
|
|
||||||
def translate_elements(self: P, offset: ArrayLike) -> P:
|
def translate_elements(self, offset: ArrayLike) -> Self:
|
||||||
"""
|
"""
|
||||||
Translates all shapes, label, refs, and ports by the given offset.
|
Translates all shapes, label, refs, and ports by the given offset.
|
||||||
|
|
||||||
@ -359,7 +356,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
cast(Positionable, entry).translate(offset)
|
cast(Positionable, entry).translate(offset)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def scale_elements(self: P, c: float) -> P:
|
def scale_elements(self, c: float) -> Self:
|
||||||
""""
|
""""
|
||||||
Scales all shapes and refs by the given value.
|
Scales all shapes and refs by the given value.
|
||||||
|
|
||||||
@ -373,7 +370,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
cast(Scalable, entry).scale_by(c)
|
cast(Scalable, entry).scale_by(c)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def scale_by(self: P, c: float) -> P:
|
def scale_by(self, c: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Scale this Pattern by the given value
|
Scale this Pattern by the given value
|
||||||
(all shapes and refs and their offsets are scaled,
|
(all shapes and refs and their offsets are scaled,
|
||||||
@ -404,7 +401,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
port.offset *= c
|
port.offset *= c
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def rotate_around(self: P, pivot: ArrayLike, rotation: float) -> P:
|
def rotate_around(self, pivot: ArrayLike, rotation: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Rotate the Pattern around the a location.
|
Rotate the Pattern around the a location.
|
||||||
|
|
||||||
@ -422,7 +419,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
self.translate_elements(+pivot)
|
self.translate_elements(+pivot)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def rotate_element_centers(self: P, rotation: float) -> P:
|
def rotate_element_centers(self, rotation: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Rotate the offsets of all shapes, labels, refs, and ports around (0, 0)
|
Rotate the offsets of all shapes, labels, refs, and ports around (0, 0)
|
||||||
|
|
||||||
@ -437,7 +434,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
cast(Positionable, entry).offset = numpy.dot(rotation_matrix_2d(rotation), old_offset)
|
cast(Positionable, entry).offset = numpy.dot(rotation_matrix_2d(rotation), old_offset)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def rotate_elements(self: P, rotation: float) -> P:
|
def rotate_elements(self, rotation: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Rotate each shape, ref, and port around its origin (offset)
|
Rotate each shape, ref, and port around its origin (offset)
|
||||||
|
|
||||||
@ -451,7 +448,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
cast(Rotatable, entry).rotate(rotation)
|
cast(Rotatable, entry).rotate(rotation)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def mirror_element_centers(self: P, across_axis: int) -> P:
|
def mirror_element_centers(self, across_axis: int) -> Self:
|
||||||
"""
|
"""
|
||||||
Mirror the offsets of all shapes, labels, and refs across an axis
|
Mirror the offsets of all shapes, labels, and refs across an axis
|
||||||
|
|
||||||
@ -466,7 +463,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
cast(Positionable, entry).offset[across_axis - 1] *= -1
|
cast(Positionable, entry).offset[across_axis - 1] *= -1
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def mirror_elements(self: P, across_axis: int) -> P:
|
def mirror_elements(self, across_axis: int) -> Self:
|
||||||
"""
|
"""
|
||||||
Mirror each shape, ref, and pattern across an axis, relative
|
Mirror each shape, ref, and pattern across an axis, relative
|
||||||
to its offset
|
to its offset
|
||||||
@ -482,7 +479,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
cast(Mirrorable, entry).mirror(across_axis)
|
cast(Mirrorable, entry).mirror(across_axis)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def mirror(self: P, across_axis: int) -> P:
|
def mirror(self, across_axis: int) -> Self:
|
||||||
"""
|
"""
|
||||||
Mirror the Pattern across an axis
|
Mirror the Pattern across an axis
|
||||||
|
|
||||||
@ -497,7 +494,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
self.mirror_element_centers(across_axis)
|
self.mirror_element_centers(across_axis)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def copy(self: P) -> P:
|
def copy(self) -> Self:
|
||||||
"""
|
"""
|
||||||
Return a copy of the Pattern, deep-copying shapes and copying refs
|
Return a copy of the Pattern, deep-copying shapes and copying refs
|
||||||
entries, but not deep-copying any referenced patterns.
|
entries, but not deep-copying any referenced patterns.
|
||||||
@ -509,7 +506,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
"""
|
"""
|
||||||
return copy.copy(self)
|
return copy.copy(self)
|
||||||
|
|
||||||
def deepcopy(self: P) -> P:
|
def deepcopy(self) -> Self:
|
||||||
"""
|
"""
|
||||||
Convenience method for `copy.deepcopy(pattern)`
|
Convenience method for `copy.deepcopy(pattern)`
|
||||||
|
|
||||||
@ -528,7 +525,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
and len(self.shapes) == 0
|
and len(self.shapes) == 0
|
||||||
and len(self.labels) == 0)
|
and len(self.labels) == 0)
|
||||||
|
|
||||||
def ref(self: P, *args: Any, **kwargs: Any) -> P:
|
def ref(self, *args: Any, **kwargs: Any) -> Self:
|
||||||
"""
|
"""
|
||||||
Convenience function which constructs a `Ref` object and adds it
|
Convenience function which constructs a `Ref` object and adds it
|
||||||
to this pattern.
|
to this pattern.
|
||||||
@ -543,7 +540,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
self.refs.append(Ref(*args, **kwargs))
|
self.refs.append(Ref(*args, **kwargs))
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def rect(self: P, *args: Any, **kwargs: Any) -> P:
|
def rect(self, *args: Any, **kwargs: Any) -> Self:
|
||||||
"""
|
"""
|
||||||
Convenience function which calls `Polygon.rect` to construct a
|
Convenience function which calls `Polygon.rect` to construct a
|
||||||
rectangle and adds it to this pattern.
|
rectangle and adds it to this pattern.
|
||||||
@ -559,8 +556,8 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def flatten(
|
def flatten(
|
||||||
self: P,
|
self,
|
||||||
library: Mapping[str, P],
|
library: Mapping[str, 'Pattern'],
|
||||||
flatten_ports: bool = False, # TODO document
|
flatten_ports: bool = False, # TODO document
|
||||||
) -> 'Pattern':
|
) -> 'Pattern':
|
||||||
"""
|
"""
|
||||||
@ -573,7 +570,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
Returns:
|
Returns:
|
||||||
self
|
self
|
||||||
"""
|
"""
|
||||||
flattened: dict[str | None, P | None] = {}
|
flattened: dict[str | None, 'Pattern' | None] = {}
|
||||||
|
|
||||||
# TODO both Library and Pattern have flatten()... pattern is in-place?
|
# TODO both Library and Pattern have flatten()... pattern is in-place?
|
||||||
def flatten_single(name: str | None) -> None:
|
def flatten_single(name: str | None) -> None:
|
||||||
@ -609,8 +606,8 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def visualize(
|
def visualize(
|
||||||
self: P,
|
self,
|
||||||
library: Mapping[str, P] | None = None,
|
library: Mapping[str, 'Pattern'] | None = None,
|
||||||
offset: ArrayLike = (0., 0.),
|
offset: ArrayLike = (0., 0.),
|
||||||
line_color: str = 'k',
|
line_color: str = 'k',
|
||||||
fill_color: str = 'none',
|
fill_color: str = 'none',
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import Iterable, KeysView, ValuesView, overload, TypeVar
|
from typing import Iterable, KeysView, ValuesView, overload, Self
|
||||||
import warnings
|
import warnings
|
||||||
import traceback
|
import traceback
|
||||||
import logging
|
import logging
|
||||||
@ -17,11 +17,6 @@ from .error import PortError
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
P = TypeVar('P', bound='Port')
|
|
||||||
PL = TypeVar('PL', bound='PortList')
|
|
||||||
PL2 = TypeVar('PL2', bound='PortList')
|
|
||||||
|
|
||||||
|
|
||||||
class Port(PositionableImpl, Rotatable, PivotableImpl, Copyable, Mirrorable):
|
class Port(PositionableImpl, Rotatable, PivotableImpl, Copyable, Mirrorable):
|
||||||
"""
|
"""
|
||||||
A point at which a `Device` can be snapped to another `Device`.
|
A point at which a `Device` can be snapped to another `Device`.
|
||||||
@ -76,24 +71,24 @@ class Port(PositionableImpl, Rotatable, PivotableImpl, Copyable, Mirrorable):
|
|||||||
def get_bounds(self):
|
def get_bounds(self):
|
||||||
return numpy.vstack((self.offset, self.offset))
|
return numpy.vstack((self.offset, self.offset))
|
||||||
|
|
||||||
def set_ptype(self: P, ptype: str) -> P:
|
def set_ptype(self, ptype: str) -> Self:
|
||||||
""" Chainable setter for `ptype` """
|
""" Chainable setter for `ptype` """
|
||||||
self.ptype = ptype
|
self.ptype = ptype
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def mirror(self: P, axis: int) -> P:
|
def mirror(self, axis: int) -> Self:
|
||||||
self.offset[1 - axis] *= -1
|
self.offset[1 - axis] *= -1
|
||||||
if self.rotation is not None:
|
if self.rotation is not None:
|
||||||
self.rotation *= -1
|
self.rotation *= -1
|
||||||
self.rotation += axis * pi
|
self.rotation += axis * pi
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def rotate(self: P, rotation: float) -> P:
|
def rotate(self, rotation: float) -> Self:
|
||||||
if self.rotation is not None:
|
if self.rotation is not None:
|
||||||
self.rotation += rotation
|
self.rotation += rotation
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def set_rotation(self: P, rotation: float | None) -> P:
|
def set_rotation(self, rotation: float | None) -> Self:
|
||||||
self.rotation = rotation
|
self.rotation = rotation
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@ -148,10 +143,10 @@ class PortList(metaclass=ABCMeta):
|
|||||||
# and because you can just grab .ports and use that instead
|
# and because you can just grab .ports and use that instead
|
||||||
|
|
||||||
def rename_ports(
|
def rename_ports(
|
||||||
self: PL,
|
self,
|
||||||
mapping: dict[str, str | None],
|
mapping: dict[str, str | None],
|
||||||
overwrite: bool = False,
|
overwrite: bool = False,
|
||||||
) -> PL:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Renames ports as specified by `mapping`.
|
Renames ports as specified by `mapping`.
|
||||||
Ports can be explicitly deleted by mapping them to `None`.
|
Ports can be explicitly deleted by mapping them to `None`.
|
||||||
@ -179,12 +174,12 @@ class PortList(metaclass=ABCMeta):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def add_port_pair(
|
def add_port_pair(
|
||||||
self: PL,
|
self,
|
||||||
offset: ArrayLike = (0, 0),
|
offset: ArrayLike = (0, 0),
|
||||||
rotation: float = 0.0,
|
rotation: float = 0.0,
|
||||||
names: tuple[str, str] = ('A', 'B'),
|
names: tuple[str, str] = ('A', 'B'),
|
||||||
ptype: str = 'unk',
|
ptype: str = 'unk',
|
||||||
) -> PL:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Add a pair of ports with opposing directions at the specified location.
|
Add a pair of ports with opposing directions at the specified location.
|
||||||
|
|
||||||
@ -207,11 +202,11 @@ class PortList(metaclass=ABCMeta):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def check_ports(
|
def check_ports(
|
||||||
self: PL,
|
self,
|
||||||
other_names: Iterable[str],
|
other_names: Iterable[str],
|
||||||
map_in: dict[str, str] | None = None,
|
map_in: dict[str, str] | None = None,
|
||||||
map_out: dict[str, str | None] | None = None,
|
map_out: dict[str, str | None] | None = None,
|
||||||
) -> PL:
|
) -> Self:
|
||||||
"""
|
"""
|
||||||
Given the provided port mappings, check that:
|
Given the provided port mappings, check that:
|
||||||
- All of the ports specified in the mappings exist
|
- All of the ports specified in the mappings exist
|
||||||
@ -276,8 +271,8 @@ class PortList(metaclass=ABCMeta):
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def find_transform(
|
def find_transform(
|
||||||
self: PL,
|
self,
|
||||||
other: PL2,
|
other: 'PortList',
|
||||||
map_in: dict[str, str],
|
map_in: dict[str, str],
|
||||||
*,
|
*,
|
||||||
mirrored: tuple[bool, bool] = (False, False),
|
mirrored: tuple[bool, bool] = (False, False),
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"""
|
"""
|
||||||
#TODO more top-level documentation
|
#TODO more top-level documentation
|
||||||
|
|
||||||
from typing import Sequence, Mapping, TYPE_CHECKING, Any, TypeVar, cast
|
from typing import Sequence, Mapping, TYPE_CHECKING, Any, Self, cast
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
@ -24,9 +24,6 @@ if TYPE_CHECKING:
|
|||||||
from . import Pattern, NamedPattern
|
from . import Pattern, NamedPattern
|
||||||
|
|
||||||
|
|
||||||
R = TypeVar('R', bound='Ref')
|
|
||||||
|
|
||||||
|
|
||||||
class Ref(
|
class Ref(
|
||||||
PositionableImpl, RotatableImpl, ScalableImpl, Mirrorable,
|
PositionableImpl, RotatableImpl, ScalableImpl, Mirrorable,
|
||||||
PivotableImpl, Copyable, RepeatableImpl, AnnotatableImpl,
|
PivotableImpl, Copyable, RepeatableImpl, AnnotatableImpl,
|
||||||
@ -164,13 +161,13 @@ class Ref(
|
|||||||
|
|
||||||
return pattern
|
return pattern
|
||||||
|
|
||||||
def rotate(self: R, rotation: float) -> R:
|
def rotate(self, rotation: float) -> Self:
|
||||||
self.rotation += rotation
|
self.rotation += rotation
|
||||||
if self.repetition is not None:
|
if self.repetition is not None:
|
||||||
self.repetition.rotate(rotation)
|
self.repetition.rotate(rotation)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def mirror(self: R, axis: int) -> R:
|
def mirror(self, axis: int) -> Self:
|
||||||
self.mirrored[axis] = not self.mirrored[axis]
|
self.mirrored[axis] = not self.mirrored[axis]
|
||||||
self.rotation *= -1
|
self.rotation *= -1
|
||||||
if self.repetition is not None:
|
if self.repetition is not None:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import Callable, TypeVar, TYPE_CHECKING
|
from typing import Callable, Self, TYPE_CHECKING
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
@ -26,9 +26,6 @@ normalized_shape_tuple = tuple[
|
|||||||
DEFAULT_POLY_NUM_VERTICES = 24
|
DEFAULT_POLY_NUM_VERTICES = 24
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar('T', bound='Shape')
|
|
||||||
|
|
||||||
|
|
||||||
class Shape(PositionableImpl, LayerableImpl, Rotatable, Mirrorable, Copyable, Scalable,
|
class Shape(PositionableImpl, LayerableImpl, Rotatable, Mirrorable, Copyable, Scalable,
|
||||||
PivotableImpl, RepeatableImpl, AnnotatableImpl, metaclass=ABCMeta):
|
PivotableImpl, RepeatableImpl, AnnotatableImpl, metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
@ -68,7 +65,7 @@ class Shape(PositionableImpl, LayerableImpl, Rotatable, Mirrorable, Copyable, Sc
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def normalized_form(self: T, norm_value: int) -> normalized_shape_tuple:
|
def normalized_form(self, norm_value: int) -> normalized_shape_tuple:
|
||||||
"""
|
"""
|
||||||
Writes the shape in a standardized notation, with offset, scale, and rotation
|
Writes the shape in a standardized notation, with offset, scale, and rotation
|
||||||
information separated out from the remaining values.
|
information separated out from the remaining values.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import TypeVar
|
from typing import Self
|
||||||
#from types import MappingProxyType
|
#from types import MappingProxyType
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
@ -9,10 +9,6 @@ from ..error import MasqueError
|
|||||||
_empty_slots = () # Workaround to get mypy to ignore intentionally empty slots for superclass
|
_empty_slots = () # Workaround to get mypy to ignore intentionally empty slots for superclass
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar('T', bound='Annotatable')
|
|
||||||
I = TypeVar('I', bound='AnnotatableImpl')
|
|
||||||
|
|
||||||
|
|
||||||
class Annotatable(metaclass=ABCMeta):
|
class Annotatable(metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Abstract class for all annotatable entities
|
Abstract class for all annotatable entities
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
from typing import TypeVar
|
from typing import Self
|
||||||
from abc import ABCMeta
|
from abc import ABCMeta
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar('T', bound='Copyable')
|
|
||||||
|
|
||||||
|
|
||||||
class Copyable(metaclass=ABCMeta):
|
class Copyable(metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Abstract class which adds .copy() and .deepcopy()
|
Abstract class which adds .copy() and .deepcopy()
|
||||||
@ -15,7 +12,7 @@ class Copyable(metaclass=ABCMeta):
|
|||||||
'''
|
'''
|
||||||
---- Non-abstract methods
|
---- Non-abstract methods
|
||||||
'''
|
'''
|
||||||
def copy(self: T) -> T:
|
def copy(self) -> Self:
|
||||||
"""
|
"""
|
||||||
Return a shallow copy of the object.
|
Return a shallow copy of the object.
|
||||||
|
|
||||||
@ -24,7 +21,7 @@ class Copyable(metaclass=ABCMeta):
|
|||||||
"""
|
"""
|
||||||
return copy.copy(self)
|
return copy.copy(self)
|
||||||
|
|
||||||
def deepcopy(self: T) -> T:
|
def deepcopy(self) -> Self:
|
||||||
"""
|
"""
|
||||||
Return a deep copy of the object.
|
Return a deep copy of the object.
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import TypeVar
|
from typing import Self
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
from ..utils import layer_t
|
from ..utils import layer_t
|
||||||
@ -7,10 +7,6 @@ from ..utils import layer_t
|
|||||||
_empty_slots = () # Workaround to get mypy to ignore intentionally empty slots for superclass
|
_empty_slots = () # Workaround to get mypy to ignore intentionally empty slots for superclass
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar('T', bound='Layerable')
|
|
||||||
I = TypeVar('I', bound='LayerableImpl')
|
|
||||||
|
|
||||||
|
|
||||||
class Layerable(metaclass=ABCMeta):
|
class Layerable(metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Abstract class for all layerable entities
|
Abstract class for all layerable entities
|
||||||
@ -36,7 +32,7 @@ class Layerable(metaclass=ABCMeta):
|
|||||||
---- Methods
|
---- Methods
|
||||||
'''
|
'''
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def set_layer(self: T, layer: layer_t) -> T:
|
def set_layer(self, layer: layer_t) -> Self:
|
||||||
"""
|
"""
|
||||||
Set the layer
|
Set the layer
|
||||||
|
|
||||||
@ -72,6 +68,6 @@ class LayerableImpl(Layerable, metaclass=ABCMeta):
|
|||||||
'''
|
'''
|
||||||
---- Non-abstract methods
|
---- Non-abstract methods
|
||||||
'''
|
'''
|
||||||
def set_layer(self: I, layer: layer_t) -> I:
|
def set_layer(self, layer: layer_t) -> Self:
|
||||||
self.layer = layer
|
self.layer = layer
|
||||||
return self
|
return self
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
from typing import TypeVar
|
from typing import Self
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar('T', bound='Mirrorable')
|
|
||||||
#I = TypeVar('I', bound='MirrorableImpl')
|
|
||||||
|
|
||||||
|
|
||||||
class Mirrorable(metaclass=ABCMeta):
|
class Mirrorable(metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Abstract class for all mirrorable entities
|
Abstract class for all mirrorable entities
|
||||||
@ -16,7 +12,7 @@ class Mirrorable(metaclass=ABCMeta):
|
|||||||
---- Abstract methods
|
---- Abstract methods
|
||||||
'''
|
'''
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def mirror(self: T, axis: int) -> T:
|
def mirror(self, axis: int) -> Self:
|
||||||
"""
|
"""
|
||||||
Mirror the entity across an axis.
|
Mirror the entity across an axis.
|
||||||
|
|
||||||
@ -28,7 +24,7 @@ class Mirrorable(metaclass=ABCMeta):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def mirror2d(self: T, axes: tuple[bool, bool]) -> T:
|
def mirror2d(self, axes: tuple[bool, bool]) -> Self:
|
||||||
"""
|
"""
|
||||||
Optionally mirror the entity across both axes
|
Optionally mirror the entity across both axes
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# TODO top-level comment about how traits should set __slots__ = (), and how to use AutoSlots
|
# TODO top-level comment about how traits should set __slots__ = (), and how to use AutoSlots
|
||||||
|
|
||||||
from typing import TypeVar, Any
|
from typing import Self, Any
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
@ -12,10 +12,6 @@ from ..error import MasqueError
|
|||||||
_empty_slots = () # Workaround to get mypy to ignore intentionally empty slots for superclass
|
_empty_slots = () # Workaround to get mypy to ignore intentionally empty slots for superclass
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar('T', bound='Positionable')
|
|
||||||
I = TypeVar('I', bound='PositionableImpl')
|
|
||||||
|
|
||||||
|
|
||||||
class Positionable(metaclass=ABCMeta):
|
class Positionable(metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Abstract class for all positionable entities
|
Abstract class for all positionable entities
|
||||||
@ -39,7 +35,7 @@ class Positionable(metaclass=ABCMeta):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def set_offset(self: T, offset: ArrayLike) -> T:
|
def set_offset(self, offset: ArrayLike) -> Self:
|
||||||
"""
|
"""
|
||||||
Set the offset
|
Set the offset
|
||||||
|
|
||||||
@ -52,7 +48,7 @@ class Positionable(metaclass=ABCMeta):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def translate(self: T, offset: ArrayLike) -> T:
|
def translate(self, offset: ArrayLike) -> Self:
|
||||||
"""
|
"""
|
||||||
Translate the entity by the given offset
|
Translate the entity by the given offset
|
||||||
|
|
||||||
@ -116,10 +112,10 @@ class PositionableImpl(Positionable, metaclass=ABCMeta):
|
|||||||
'''
|
'''
|
||||||
---- Methods
|
---- Methods
|
||||||
'''
|
'''
|
||||||
def set_offset(self: I, offset: ArrayLike) -> I:
|
def set_offset(self, offset: ArrayLike) -> Self:
|
||||||
self.offset = offset
|
self.offset = offset
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def translate(self: I, offset: ArrayLike) -> I:
|
def translate(self, offset: ArrayLike) -> Self:
|
||||||
self._offset += offset # type: ignore # NDArray += ArrayLike should be fine??
|
self._offset += offset # type: ignore # NDArray += ArrayLike should be fine??
|
||||||
return self
|
return self
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import TypeVar, TYPE_CHECKING
|
from typing import Self, TYPE_CHECKING
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
from ..error import MasqueError
|
from ..error import MasqueError
|
||||||
@ -11,10 +11,6 @@ if TYPE_CHECKING:
|
|||||||
from ..repetition import Repetition
|
from ..repetition import Repetition
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar('T', bound='Repeatable')
|
|
||||||
I = TypeVar('I', bound='RepeatableImpl')
|
|
||||||
|
|
||||||
|
|
||||||
class Repeatable(metaclass=ABCMeta):
|
class Repeatable(metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Abstract class for all repeatable entities
|
Abstract class for all repeatable entities
|
||||||
@ -41,7 +37,7 @@ class Repeatable(metaclass=ABCMeta):
|
|||||||
---- Methods
|
---- Methods
|
||||||
'''
|
'''
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def set_repetition(self: T, repetition: 'Repetition' | None) -> T:
|
def set_repetition(self, repetition: 'Repetition' | None) -> Self:
|
||||||
"""
|
"""
|
||||||
Set the repetition
|
Set the repetition
|
||||||
|
|
||||||
@ -80,6 +76,6 @@ class RepeatableImpl(Repeatable, metaclass=ABCMeta):
|
|||||||
'''
|
'''
|
||||||
---- Non-abstract methods
|
---- Non-abstract methods
|
||||||
'''
|
'''
|
||||||
def set_repetition(self: I, repetition: 'Repetition' | None) -> I:
|
def set_repetition(self, repetition: 'Repetition' | None) -> Self:
|
||||||
self.repetition = repetition
|
self.repetition = repetition
|
||||||
return self
|
return self
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import TypeVar, cast, Any
|
from typing import Self, cast, Any
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
@ -13,12 +13,6 @@ from ..utils import rotation_matrix_2d
|
|||||||
_empty_slots = () # Workaround to get mypy to ignore intentionally empty slots for superclass
|
_empty_slots = () # Workaround to get mypy to ignore intentionally empty slots for superclass
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar('T', bound='Rotatable')
|
|
||||||
I = TypeVar('I', bound='RotatableImpl')
|
|
||||||
P = TypeVar('P', bound='Pivotable')
|
|
||||||
J = TypeVar('J', bound='PivotableImpl')
|
|
||||||
|
|
||||||
|
|
||||||
class Rotatable(metaclass=ABCMeta):
|
class Rotatable(metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Abstract class for all rotatable entities
|
Abstract class for all rotatable entities
|
||||||
@ -29,7 +23,7 @@ class Rotatable(metaclass=ABCMeta):
|
|||||||
---- Abstract methods
|
---- Abstract methods
|
||||||
'''
|
'''
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def rotate(self: T, val: float) -> T:
|
def rotate(self, val: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Rotate the shape around its origin (0, 0), ignoring its offset.
|
Rotate the shape around its origin (0, 0), ignoring its offset.
|
||||||
|
|
||||||
@ -68,11 +62,11 @@ class RotatableImpl(Rotatable, metaclass=ABCMeta):
|
|||||||
'''
|
'''
|
||||||
---- Methods
|
---- Methods
|
||||||
'''
|
'''
|
||||||
def rotate(self: I, rotation: float) -> I:
|
def rotate(self, rotation: float) -> Self:
|
||||||
self.rotation += rotation
|
self.rotation += rotation
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def set_rotation(self: I, rotation: float) -> I:
|
def set_rotation(self, rotation: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Set the rotation to a value
|
Set the rotation to a value
|
||||||
|
|
||||||
@ -94,7 +88,7 @@ class Pivotable(metaclass=ABCMeta):
|
|||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def rotate_around(self: P, pivot: ArrayLike, rotation: float) -> P:
|
def rotate_around(self, pivot: ArrayLike, rotation: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Rotate the object around a point.
|
Rotate the object around a point.
|
||||||
|
|
||||||
@ -117,7 +111,7 @@ class PivotableImpl(Pivotable, metaclass=ABCMeta):
|
|||||||
offset: Any # TODO see if we can get around defining `offset` in PivotableImpl
|
offset: Any # TODO see if we can get around defining `offset` in PivotableImpl
|
||||||
""" `[x_offset, y_offset]` """
|
""" `[x_offset, y_offset]` """
|
||||||
|
|
||||||
def rotate_around(self: J, pivot: ArrayLike, rotation: float) -> J:
|
def rotate_around(self, pivot: ArrayLike, rotation: float) -> Self:
|
||||||
pivot = numpy.array(pivot, dtype=float)
|
pivot = numpy.array(pivot, dtype=float)
|
||||||
cast(Positionable, self).translate(-pivot)
|
cast(Positionable, self).translate(-pivot)
|
||||||
cast(Rotatable, self).rotate(rotation)
|
cast(Rotatable, self).rotate(rotation)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import TypeVar
|
from typing import Self
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
from ..error import MasqueError
|
from ..error import MasqueError
|
||||||
@ -8,10 +8,6 @@ from ..utils import is_scalar
|
|||||||
_empty_slots = () # Workaround to get mypy to ignore intentionally empty slots for superclass
|
_empty_slots = () # Workaround to get mypy to ignore intentionally empty slots for superclass
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar('T', bound='Scalable')
|
|
||||||
I = TypeVar('I', bound='ScalableImpl')
|
|
||||||
|
|
||||||
|
|
||||||
class Scalable(metaclass=ABCMeta):
|
class Scalable(metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Abstract class for all scalable entities
|
Abstract class for all scalable entities
|
||||||
@ -22,7 +18,7 @@ class Scalable(metaclass=ABCMeta):
|
|||||||
---- Abstract methods
|
---- Abstract methods
|
||||||
'''
|
'''
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def scale_by(self: T, c: float) -> T:
|
def scale_by(self, c: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Scale the entity by a factor
|
Scale the entity by a factor
|
||||||
|
|
||||||
@ -62,11 +58,11 @@ class ScalableImpl(Scalable, metaclass=ABCMeta):
|
|||||||
'''
|
'''
|
||||||
---- Methods
|
---- Methods
|
||||||
'''
|
'''
|
||||||
def scale_by(self: I, c: float) -> I:
|
def scale_by(self, c: float) -> Self:
|
||||||
self.scale *= c
|
self.scale *= c
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def set_scale(self: I, scale: float) -> I:
|
def set_scale(self, scale: float) -> Self:
|
||||||
"""
|
"""
|
||||||
Set the sclae to a value
|
Set the sclae to a value
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user