[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
|
|
@ -1,15 +1,13 @@
|
|||
from typing import Self, cast, TYPE_CHECKING
|
||||
from typing import Self
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
import numpy
|
||||
from numpy.typing import NDArray
|
||||
|
||||
from ..error import MasqueError
|
||||
from .positionable import Positionable
|
||||
from .repeatable import Repeatable
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .positionable import Positionable
|
||||
|
||||
|
||||
class Mirrorable(metaclass=ABCMeta):
|
||||
"""
|
||||
|
|
@ -48,7 +46,7 @@ class Mirrorable(metaclass=ABCMeta):
|
|||
return self
|
||||
|
||||
|
||||
class Flippable(metaclass=ABCMeta):
|
||||
class Flippable(Positionable, metaclass=ABCMeta):
|
||||
"""
|
||||
Trait class for entities which can be mirrored relative to an external line.
|
||||
"""
|
||||
|
|
@ -85,22 +83,19 @@ class Flippable(metaclass=ABCMeta):
|
|||
pass
|
||||
|
||||
|
||||
class FlippableImpl(Flippable, Repeatable, metaclass=ABCMeta):
|
||||
class FlippableImpl(Flippable, Mirrorable, Repeatable, metaclass=ABCMeta):
|
||||
"""
|
||||
Implementation of `Flippable` for objects which are `Mirrorable`, `Positionable`,
|
||||
and `Repeatable`.
|
||||
"""
|
||||
__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:
|
||||
axis, pivot = self._check_flip_args(axis=axis, x=x, y=y)
|
||||
cast('Positionable', self).translate(-pivot)
|
||||
cast('Mirrorable', self).mirror(axis)
|
||||
self.translate(-pivot)
|
||||
self.mirror(axis)
|
||||
if self.repetition is not None:
|
||||
self.repetition.mirror(axis)
|
||||
self.offset[1 - axis] *= -1
|
||||
cast('Positionable', self).translate(+pivot)
|
||||
self.translate(+pivot)
|
||||
return self
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Self, cast, Any, TYPE_CHECKING
|
||||
from typing import Self
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
import numpy
|
||||
|
|
@ -8,8 +8,7 @@ from numpy.typing import ArrayLike
|
|||
from ..error import MasqueError
|
||||
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
|
||||
|
||||
|
|
@ -81,7 +80,7 @@ class RotatableImpl(Rotatable, metaclass=ABCMeta):
|
|||
return self
|
||||
|
||||
|
||||
class Pivotable(metaclass=ABCMeta):
|
||||
class Pivotable(Positionable, metaclass=ABCMeta):
|
||||
"""
|
||||
Trait class for entites which can be rotated around a point.
|
||||
This requires that they are `Positionable` but not necessarily `Rotatable` themselves.
|
||||
|
|
@ -103,20 +102,18 @@ class Pivotable(metaclass=ABCMeta):
|
|||
pass
|
||||
|
||||
|
||||
class PivotableImpl(Pivotable, metaclass=ABCMeta):
|
||||
class PivotableImpl(Pivotable, Rotatable, metaclass=ABCMeta):
|
||||
"""
|
||||
Implementation of `Pivotable` for objects which are `Rotatable`
|
||||
and `Positionable`.
|
||||
"""
|
||||
__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:
|
||||
pivot = numpy.asarray(pivot, dtype=float)
|
||||
cast('Positionable', self).translate(-pivot)
|
||||
cast('Rotatable', self).rotate(rotation)
|
||||
self.translate(-pivot)
|
||||
self.rotate(rotation)
|
||||
self.offset = numpy.dot(rotation_matrix_2d(rotation), self.offset)
|
||||
cast('Positionable', self).translate(+pivot)
|
||||
self.translate(+pivot)
|
||||
return self
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue