[traits] Formalize Flippable and Pivotable depending on Positionable

This commit is contained in:
Jan Petykiewicz 2026-02-15 14:34:10 -08:00
commit 48f7569c1f
5 changed files with 26 additions and 34 deletions

View file

@ -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