import abc
import numpy as np
[docs]
class Layout:
"""
Container class for all types of partition data. The layout swaps the data of the
partition with temporary layout associated data, and tries out experimental changes
to the partition data, if the layout process fails, the original partition data is
reinstated.
"""
def __init__(self, data, owner=None, children=None, frozen=False):
if children is None:
children = []
self._data = data
self._owner = owner
self._children = children
self._frozen = frozen
@property
def data(self):
return self._data
@property
def children(self):
return self._children
[docs]
def copy(self):
return Layout(
data=self._data.copy(),
owner=self._owner,
children=self._children,
frozen=self._frozen,
)
[docs]
def accept(self):
self.swap()
def __getattr__(self, attr):
if attr.startswith("propose_"):
f = getattr(self._owner, attr[8:])
def swapped_execute(*args, **kwargs):
self.swap()
f(*args, **kwargs)
self.swap()
return swapped_execute
super().__getattribute__(attr)
[docs]
def swap(self):
if self._owner is not None:
old = getattr(self._owner, "_data", None)
self._owner._data = self._data
self._data = old
for child in self._children:
child.swap()
[docs]
class PartitionData(abc.ABC):
"""
The partition data is a class that stores the description of a partition for a
partition. This allows the Partition interface to define mutating operations such as
translate, rotate, scale; for a dry-run we only have to swap out the actual data with
temporary data, and the mutation is prevented.
"""
[docs]
@abc.abstractmethod
def copy(self):
pass
[docs]
class RhomboidData(PartitionData):
def __init__(self, ldc, mdc):
# Least dominant corner
self.ldc = np.array(ldc, dtype=float, copy=False)
# Most dominant corner
self.mdc = np.array(mdc, dtype=float, copy=False)
def __repr__(self):
return f"{self.__class__.__name__}({self.ldc}, {self.mdc})"
[docs]
def copy(self):
"""
Copy this boundary to a new instance.
"""
return self.__class__(self.ldc.copy(), self.mdc.copy())
@property
def x(self):
return self.ldc[0]
@x.setter
def x(self, value):
self.mdc[0] += value - self.ldc[0]
self.ldc[0] = value
@property
def y(self):
return self.ldc[1]
@y.setter
def y(self, value):
self.mdc[1] += value - self.ldc[1]
self.ldc[1] = value
@property
def z(self):
return self.ldc[2]
@z.setter
def z(self, value):
self.mdc[2] += value - self.ldc[2]
self.ldc[2] = value
@property
def dimensions(self):
return self.mdc - self.ldc
@property
def width(self):
return self.mdc[0] - self.ldc[0]
@width.setter
def width(self, value):
self.mdc[0] = self.ldc[0] + value
@property
def height(self):
return self.mdc[2] - self.ldc[2]
@height.setter
def height(self, value):
self.mdc[2] = self.ldc[2] + value
@property
def depth(self):
return self.mdc[1] - self.ldc[1]
@depth.setter
def depth(self, value):
self.mdc[1] = self.ldc[1] + value
[docs]
def box_layout(ldc, mdc):
return Layout(RhomboidData(ldc, mdc), frozen=True)