[traits] Formalize Flippable and Pivotable depending on Positionable
This commit is contained in:
parent
8a56679884
commit
48f7569c1f
5 changed files with 26 additions and 34 deletions
|
|
@ -11,7 +11,7 @@ import numpy
|
||||||
from numpy import pi
|
from numpy import pi
|
||||||
from numpy.typing import ArrayLike, NDArray
|
from numpy.typing import ArrayLike, NDArray
|
||||||
|
|
||||||
from .traits import PositionableImpl, Rotatable, PivotableImpl, Copyable, Flippable
|
from .traits import PositionableImpl, PivotableImpl, Copyable, Mirrorable, Flippable
|
||||||
from .utils import rotate_offsets_around, rotation_matrix_2d
|
from .utils import rotate_offsets_around, rotation_matrix_2d
|
||||||
from .error import PortError, format_stacktrace
|
from .error import PortError, format_stacktrace
|
||||||
|
|
||||||
|
|
@ -20,7 +20,7 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@functools.total_ordering
|
@functools.total_ordering
|
||||||
class Port(PositionableImpl, Rotatable, PivotableImpl, Copyable, Flippable):
|
class Port(PivotableImpl, PositionableImpl, Mirrorable, Flippable, Copyable):
|
||||||
"""
|
"""
|
||||||
A point at which a `Device` can be snapped to another `Device`.
|
A point at which a `Device` can be snapped to another `Device`.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ from .utils import annotations_t, rotation_matrix_2d, annotations_eq, annotation
|
||||||
from .repetition import Repetition
|
from .repetition import Repetition
|
||||||
from .traits import (
|
from .traits import (
|
||||||
PositionableImpl, RotatableImpl, ScalableImpl,
|
PositionableImpl, RotatableImpl, ScalableImpl,
|
||||||
Mirrorable, PivotableImpl, Copyable, RepeatableImpl, AnnotatableImpl,
|
PivotableImpl, Copyable, RepeatableImpl, AnnotatableImpl,
|
||||||
Flippable, FlippableImpl,
|
FlippableImpl,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -26,9 +26,9 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
@functools.total_ordering
|
@functools.total_ordering
|
||||||
class Ref(
|
class Ref(
|
||||||
PositionableImpl, RotatableImpl, ScalableImpl, Mirrorable,
|
FlippableImpl, PivotableImpl, RepeatableImpl, AnnotatableImpl,
|
||||||
PivotableImpl, Copyable, RepeatableImpl, AnnotatableImpl,
|
PositionableImpl, RotatableImpl, ScalableImpl,
|
||||||
FlippableImpl, Flippable,
|
Copyable,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
`Ref` provides basic support for nesting Pattern objects within each other.
|
`Ref` provides basic support for nesting Pattern objects within each other.
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import numpy
|
||||||
from numpy.typing import NDArray, ArrayLike
|
from numpy.typing import NDArray, ArrayLike
|
||||||
|
|
||||||
from ..traits import (
|
from ..traits import (
|
||||||
Rotatable, Copyable, Scalable, FlippableImpl,
|
Copyable, Scalable, FlippableImpl,
|
||||||
Positionable, Pivotable, PivotableImpl, RepeatableImpl, AnnotatableImpl,
|
PivotableImpl, RepeatableImpl, AnnotatableImpl,
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
|
@ -26,8 +26,8 @@ normalized_shape_tuple = tuple[
|
||||||
DEFAULT_POLY_NUM_VERTICES = 24
|
DEFAULT_POLY_NUM_VERTICES = 24
|
||||||
|
|
||||||
|
|
||||||
class Shape(Positionable, Rotatable, FlippableImpl, Copyable, Scalable,
|
class Shape(FlippableImpl, PivotableImpl, RepeatableImpl, AnnotatableImpl,
|
||||||
AnnotatableImpl, RepeatableImpl, PivotableImpl, Pivotable,
|
Copyable, Scalable,
|
||||||
metaclass=ABCMeta):
|
metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Class specifying functions common to all shapes.
|
Class specifying functions common to all shapes.
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
from typing import Self, cast, TYPE_CHECKING
|
from typing import Self
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
from numpy.typing import NDArray
|
from numpy.typing import NDArray
|
||||||
|
|
||||||
from ..error import MasqueError
|
from ..error import MasqueError
|
||||||
from .repeatable import Repeatable
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from .positionable import Positionable
|
from .positionable import Positionable
|
||||||
|
from .repeatable import Repeatable
|
||||||
|
|
||||||
|
|
||||||
class Mirrorable(metaclass=ABCMeta):
|
class Mirrorable(metaclass=ABCMeta):
|
||||||
|
|
@ -48,7 +46,7 @@ class Mirrorable(metaclass=ABCMeta):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
class Flippable(metaclass=ABCMeta):
|
class Flippable(Positionable, metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Trait class for entities which can be mirrored relative to an external line.
|
Trait class for entities which can be mirrored relative to an external line.
|
||||||
"""
|
"""
|
||||||
|
|
@ -85,22 +83,19 @@ class Flippable(metaclass=ABCMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FlippableImpl(Flippable, Repeatable, metaclass=ABCMeta):
|
class FlippableImpl(Flippable, Mirrorable, Repeatable, metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Implementation of `Flippable` for objects which are `Mirrorable`, `Positionable`,
|
Implementation of `Flippable` for objects which are `Mirrorable`, `Positionable`,
|
||||||
and `Repeatable`.
|
and `Repeatable`.
|
||||||
"""
|
"""
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
offset: NDArray[numpy.float64]
|
|
||||||
""" `[x_offset, y_offset]` """
|
|
||||||
|
|
||||||
def flip_across(self, axis: int | None = None, *, x: float | None = None, y: float | None = None) -> Self:
|
def flip_across(self, axis: int | None = None, *, x: float | None = None, y: float | None = None) -> Self:
|
||||||
axis, pivot = self._check_flip_args(axis=axis, x=x, y=y)
|
axis, pivot = self._check_flip_args(axis=axis, x=x, y=y)
|
||||||
cast('Positionable', self).translate(-pivot)
|
self.translate(-pivot)
|
||||||
cast('Mirrorable', self).mirror(axis)
|
self.mirror(axis)
|
||||||
if self.repetition is not None:
|
if self.repetition is not None:
|
||||||
self.repetition.mirror(axis)
|
self.repetition.mirror(axis)
|
||||||
self.offset[1 - axis] *= -1
|
self.offset[1 - axis] *= -1
|
||||||
cast('Positionable', self).translate(+pivot)
|
self.translate(+pivot)
|
||||||
return self
|
return self
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import Self, cast, Any, TYPE_CHECKING
|
from typing import Self
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
|
|
@ -8,7 +8,6 @@ from numpy.typing import ArrayLike
|
||||||
from ..error import MasqueError
|
from ..error import MasqueError
|
||||||
from ..utils import rotation_matrix_2d
|
from ..utils import rotation_matrix_2d
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
from .positionable import Positionable
|
from .positionable import Positionable
|
||||||
|
|
||||||
_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
|
||||||
|
|
@ -81,7 +80,7 @@ class RotatableImpl(Rotatable, metaclass=ABCMeta):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
class Pivotable(metaclass=ABCMeta):
|
class Pivotable(Positionable, metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Trait class for entites which can be rotated around a point.
|
Trait class for entites which can be rotated around a point.
|
||||||
This requires that they are `Positionable` but not necessarily `Rotatable` themselves.
|
This requires that they are `Positionable` but not necessarily `Rotatable` themselves.
|
||||||
|
|
@ -103,20 +102,18 @@ class Pivotable(metaclass=ABCMeta):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PivotableImpl(Pivotable, metaclass=ABCMeta):
|
class PivotableImpl(Pivotable, Rotatable, metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Implementation of `Pivotable` for objects which are `Rotatable`
|
Implementation of `Pivotable` for objects which are `Rotatable`
|
||||||
|
and `Positionable`.
|
||||||
"""
|
"""
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
|
|
||||||
offset: Any # TODO see if we can get around defining `offset` in PivotableImpl
|
|
||||||
""" `[x_offset, y_offset]` """
|
|
||||||
|
|
||||||
def rotate_around(self, pivot: ArrayLike, rotation: float) -> Self:
|
def rotate_around(self, pivot: ArrayLike, rotation: float) -> Self:
|
||||||
pivot = numpy.asarray(pivot, dtype=float)
|
pivot = numpy.asarray(pivot, dtype=float)
|
||||||
cast('Positionable', self).translate(-pivot)
|
self.translate(-pivot)
|
||||||
cast('Rotatable', self).rotate(rotation)
|
self.rotate(rotation)
|
||||||
self.offset = numpy.dot(rotation_matrix_2d(rotation), self.offset)
|
self.offset = numpy.dot(rotation_matrix_2d(rotation), self.offset)
|
||||||
cast('Positionable', self).translate(+pivot)
|
self.translate(+pivot)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue