various fixes
This commit is contained in:
parent
b98553a770
commit
d14182998b
@ -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':
|
||||||
"""
|
"""
|
||||||
|
@ -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
|
||||||
|
@ -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]:
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user