various fixes

This commit is contained in:
Jan Petykiewicz 2020-08-12 21:43:46 -07:00
parent b98553a770
commit d14182998b
6 changed files with 33 additions and 26 deletions

View File

@ -170,8 +170,8 @@ class Grid(LockableImpl, Repetition, metaclass=AutoSlots):
@property @property
def displacements(self) -> numpy.ndarray: def displacements(self) -> numpy.ndarray:
aa, bb = numpy.meshgrid(numpy.arange(self.a_count), numpy.arange(self.b_count), indexing='ij') aa, bb = numpy.meshgrid(numpy.arange(self.a_count), numpy.arange(self.b_count), indexing='ij')
return (aa.flat[:, None] * self.a_vector[None, :] + return (aa.flatten()[:, None] * self.a_vector[None, :] +
bb.flat[:, None] * self.b_vector[None, :]) bb.flatten()[:, None] * self.b_vector[None, :])
def rotate(self, rotation: float) -> 'Grid': def rotate(self, rotation: float) -> 'Grid':
""" """

View File

@ -31,16 +31,17 @@ class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable
""" """
Abstract class specifying functions common to all shapes. Abstract class specifying functions common to all shapes.
""" """
__slots__ = () # Children should use AutoSlots
identifier: Tuple identifier: Tuple
""" An arbitrary identifier for the shape, usually empty but used by `Pattern.flatten()` """ """ An arbitrary identifier for the shape, usually empty but used by `Pattern.flatten()` """
# def __copy__(self) -> 'Shape': def __copy__(self) -> 'Shape':
# cls = self.__class__ cls = self.__class__
# new = cls.__new__(cls) new = cls.__new__(cls)
# for name in Shape.__slots__ + self.__slots__: for name in self.__slots__:
# object.__setattr__(new, name, getattr(self, name)) object.__setattr__(new, name, getattr(self, name))
# return new return new
''' '''
--- Abstract methods --- Abstract methods

View File

@ -22,7 +22,7 @@ if TYPE_CHECKING:
class SubPattern(PositionableImpl, DoseableImpl, RotatableImpl, ScalableImpl, Mirrorable, class SubPattern(PositionableImpl, DoseableImpl, RotatableImpl, ScalableImpl, Mirrorable,
Pivotable, Copyable, RepeatableImpl, LockableImpl, metaclass=AutoSlots): PivotableImpl, Copyable, RepeatableImpl, LockableImpl, metaclass=AutoSlots):
""" """
SubPattern provides basic support for nesting Pattern objects within each other, by adding SubPattern provides basic support for nesting Pattern objects within each other, by adding
offset, rotation, scaling, and associated methods. offset, rotation, scaling, and associated methods.
@ -83,6 +83,7 @@ class SubPattern(PositionableImpl, DoseableImpl, RotatableImpl, ScalableImpl, Mi
dose=self.dose, dose=self.dose,
scale=self.scale, scale=self.scale,
mirrored=self.mirrored.copy(), mirrored=self.mirrored.copy(),
repetition=copy.deepcopy(self.repetition),
locked=self.locked) locked=self.locked)
return new return new
@ -90,6 +91,7 @@ class SubPattern(PositionableImpl, DoseableImpl, RotatableImpl, ScalableImpl, Mi
memo = {} if memo is None else memo memo = {} if memo is None else memo
new = copy.copy(self).unlock() new = copy.copy(self).unlock()
new.pattern = copy.deepcopy(self.pattern, memo) new.pattern = copy.deepcopy(self.pattern, memo)
new.repetition = copy.deepcopy(self.repetition, memo)
new.locked = self.locked new.locked = self.locked
return new return new
@ -140,18 +142,17 @@ class SubPattern(PositionableImpl, DoseableImpl, RotatableImpl, ScalableImpl, Mi
return pattern return pattern
def rotate(self, rotation: float) -> 'SubPattern':
self.rotation += rotation
if self.repetition is not None:
self.repetition.rotate(rotation)
return self
def mirror(self, axis: int) -> 'SubPattern': def mirror(self, axis: int) -> 'SubPattern':
"""
Mirror the subpattern across an axis.
Args:
axis: Axis to mirror across.
Returns:
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:
self.repetiton.mirror(axis)
return self return self
def get_bounds(self) -> Optional[numpy.ndarray]: def get_bounds(self) -> Optional[numpy.ndarray]:

View File

@ -94,7 +94,7 @@ class PositionableImpl(Positionable, metaclass=ABCMeta):
@offset.setter @offset.setter
def offset(self, val: vector2): def offset(self, val: vector2):
if not isinstance(val, numpy.ndarray): if not isinstance(val, numpy.ndarray) or val.dtype != numpy.float64:
val = numpy.array(val, dtype=float) val = numpy.array(val, dtype=float)
if val.size != 2: if val.size != 2:
@ -109,7 +109,6 @@ class PositionableImpl(Positionable, metaclass=ABCMeta):
self.offset = offset self.offset = offset
return self return self
def translate(self: I, offset: vector2) -> I: def translate(self: I, offset: vector2) -> I:
self._offset += offset self._offset += offset
return self return self

View File

@ -109,6 +109,7 @@ class PivotableImpl(Pivotable, metaclass=ABCMeta):
""" """
__slots__ = () __slots__ = ()
@abstractmethod
def rotate_around(self: J, pivot: vector2, rotation: float) -> J: def rotate_around(self: J, pivot: vector2, rotation: float) -> J:
pivot = numpy.array(pivot, dtype=float) pivot = numpy.array(pivot, dtype=float)
self.translate(-pivot) self.translate(-pivot)

View File

@ -148,11 +148,16 @@ class AutoSlots(ABCMeta):
can be used to generate a full `__slots__` for the concrete class. can be used to generate a full `__slots__` for the concrete class.
""" """
def __new__(cls, name, bases, dctn): def __new__(cls, name, bases, dctn):
slots = tuple(dctn.get('__slots__', tuple())) parents = set()
for base in bases: for base in bases:
if not hasattr(base, '__annotations__'): parents |= set(base.mro())
slots = tuple(dctn.get('__slots__', tuple()))
for parent in parents:
if not hasattr(parent, '__annotations__'):
continue continue
slots += tuple(getattr(base, '__annotations__').keys()) slots += tuple(getattr(parent, '__annotations__').keys())
dctn['__slots__'] = slots dctn['__slots__'] = slots
return super().__new__(cls, name, bases, dctn) return super().__new__(cls, name, bases, dctn)