repetition related fixup
This commit is contained in:
parent
bab40474a0
commit
794ebb6b37
@ -299,14 +299,14 @@ def _subpatterns_to_refs(block: Union[ezdxf.layouts.BlockLayout, ezdxf.layouts.M
|
||||
rotated_a = rotation_matrix_2d(-subpat.rotation) @ a
|
||||
rotated_b = rotation_matrix_2d(-subpat.rotation) @ b
|
||||
if rotated_a[1] == 0 and rotated_b[0] == 0:
|
||||
attribs['column_count'] = subpat.a_count
|
||||
attribs['row_count'] = subpat.b_count
|
||||
attribs['column_count'] = rep.a_count
|
||||
attribs['row_count'] = rep.b_count
|
||||
attribs['column_spacing'] = rotated_a[0]
|
||||
attribs['row_spacing'] = rotated_b[1]
|
||||
block.add_blockref(encoded_name, subpat.offset, dxfattribs=attribs)
|
||||
elif rotated_a[0] == 0 and rotated_b[1] == 0:
|
||||
attribs['column_count'] = subpat.b_count
|
||||
attribs['row_count'] = subpat.a_count
|
||||
attribs['column_count'] = rep.b_count
|
||||
attribs['row_count'] = rep.a_count
|
||||
attribs['column_spacing'] = rotated_b[0]
|
||||
attribs['row_spacing'] = rotated_a[1]
|
||||
block.add_blockref(encoded_name, subpat.offset, dxfattribs=attribs)
|
||||
|
@ -365,8 +365,8 @@ def _ref_to_subpat(element: Union[gdsii.elements.SRef,
|
||||
if isinstance(element, gdsii.elements.ARef):
|
||||
a_count = element.cols
|
||||
b_count = element.rows
|
||||
a_vector = (element.xy[1] - offset) / counts[0]
|
||||
b_vector = (element.xy[2] - offset) / counts[1]
|
||||
a_vector = (element.xy[1] - offset) / a_count
|
||||
b_vector = (element.xy[2] - offset) / b_count
|
||||
repetition = Grid(a_vector=a_vector, b_vector=b_vector,
|
||||
a_count=a_count, b_count=b_count)
|
||||
|
||||
@ -389,9 +389,10 @@ def _subpatterns_to_refs(subpatterns: List[SubPattern]
|
||||
|
||||
# Note: GDS mirrors first and rotates second
|
||||
mirror_across_x, extra_angle = normalize_mirror(subpat.mirrored)
|
||||
ref: Union[gdsii.elements.SRef, gdsii.elements.ARef]
|
||||
|
||||
rep = subpat.repetition
|
||||
|
||||
new_refs: List[Union[gdsii.elements.SRef, gdsii.elements.ARef]]
|
||||
ref: Union[gdsii.elements.SRef, gdsii.elements.ARef]
|
||||
if isinstance(rep, Grid):
|
||||
xy = numpy.array(subpat.offset) + [
|
||||
[0, 0],
|
||||
|
@ -469,7 +469,7 @@ def _placement_to_subpat(placement: fatrec.Placement) -> SubPattern:
|
||||
'identifier': (name,),
|
||||
}
|
||||
|
||||
mrep: Repetition
|
||||
mrep: Optional[Repetition]
|
||||
rep = placement.repetition
|
||||
if isinstance(rep, fatamorgana.GridRepetition):
|
||||
mrep = Grid(a_vector=rep.a_vector,
|
||||
@ -477,8 +477,10 @@ def _placement_to_subpat(placement: fatrec.Placement) -> SubPattern:
|
||||
a_count=rep.a_count,
|
||||
b_count=rep.b_count)
|
||||
elif isinstance(rep, fatamorgana.ArbitraryRepetition):
|
||||
mrep = Arbitrary(numpy.cumsum(numpy.column_stack((rep.x_displacements,
|
||||
rep.y_displacements))))
|
||||
displacements = numpy.cumsum(numpy.column_stack((rep.x_displacements,
|
||||
rep.y_displacements)))
|
||||
displacements = numpy.vstack(([0, 0], displacements))
|
||||
mrep = Arbitrary(displacements)
|
||||
elif rep is None:
|
||||
mrep = None
|
||||
|
||||
@ -510,8 +512,10 @@ def _subpatterns_to_refs(subpatterns: List[SubPattern]
|
||||
b_count=numpy.round(rep.b_count).astype(int))
|
||||
elif isinstance(rep, Arbitrary):
|
||||
diffs = numpy.diff(rep.displacements, axis=0)
|
||||
args['repetition'] = fatamorgana.ArbitraryRepetition(
|
||||
numpy.round(diffs).astype(int))
|
||||
diff_ints = numpy.round(diffs).astype(int)
|
||||
args['repetition'] = fatamorgana.ArbitraryRepetition(diff_ints[:, 0], diff_ints[:, 1])
|
||||
args['x'] += rep.displacements[0, 0]
|
||||
args['y'] += rep.displacements[0, 1]
|
||||
else:
|
||||
assert(rep is None)
|
||||
|
||||
|
@ -217,7 +217,7 @@ class Grid(LockableImpl, Repetition, metaclass=AutoSlots):
|
||||
|
||||
corners = ((0, 0), a_extent, b_extent, a_extent + b_extent)
|
||||
xy_min = numpy.min(corners, axis=0)
|
||||
xy_max = numpy.min(corners, axis=0)
|
||||
xy_max = numpy.max(corners, axis=0)
|
||||
return numpy.array((xy_min, xy_max))
|
||||
|
||||
def scale_by(self, c: float) -> 'Grid':
|
||||
@ -298,9 +298,6 @@ class Arbitrary(LockableImpl, Repetition, metaclass=AutoSlots):
|
||||
of the instances.
|
||||
"""
|
||||
|
||||
locked: bool
|
||||
""" If `True`, disallows changes to the object. """
|
||||
|
||||
@property
|
||||
def displacements(self) -> numpy.ndarray:
|
||||
return self._displacements
|
||||
@ -311,6 +308,18 @@ class Arbitrary(LockableImpl, Repetition, metaclass=AutoSlots):
|
||||
val = numpy.sort(val.view([('', val.dtype)] * val.shape[1]), 0).view(val.dtype) # sort rows
|
||||
self._displacements = val
|
||||
|
||||
def __init__(self,
|
||||
displacements: numpy.ndarray,
|
||||
locked: bool = False,):
|
||||
"""
|
||||
Args:
|
||||
displacements: List of vectors (Nx2 ndarray) specifying displacements.
|
||||
locked: Whether the object is locked after initialization.
|
||||
"""
|
||||
object.__setattr__(self, 'locked', False)
|
||||
self.displacements = displacements
|
||||
self.locked = locked
|
||||
|
||||
def lock(self) -> 'Arbitrary':
|
||||
"""
|
||||
Lock the object, disallowing changes.
|
||||
@ -343,3 +352,56 @@ class Arbitrary(LockableImpl, Repetition, metaclass=AutoSlots):
|
||||
if self.locked != other.locked:
|
||||
return False
|
||||
return numpy.array_equal(self.displacements, other.displacements)
|
||||
|
||||
def rotate(self, rotation: float) -> 'Arbitrary':
|
||||
"""
|
||||
Rotate dispacements (around (0, 0))
|
||||
|
||||
Args:
|
||||
rotation: Angle to rotate by (counterclockwise, radians)
|
||||
|
||||
Returns:
|
||||
self
|
||||
"""
|
||||
self.displacements = numpy.dot(rotation_matrix_2d(rotation), self.displacements.T).T
|
||||
return self
|
||||
|
||||
def mirror(self, axis: int) -> 'Arbitrary':
|
||||
"""
|
||||
Mirror the displacements across an axis.
|
||||
|
||||
Args:
|
||||
axis: Axis to mirror across.
|
||||
(0: mirror across x-axis, 1: mirror across y-axis)
|
||||
|
||||
Returns:
|
||||
self
|
||||
"""
|
||||
self.displacements[1-axis] *= -1
|
||||
return self
|
||||
|
||||
def get_bounds(self) -> Optional[numpy.ndarray]:
|
||||
"""
|
||||
Return a `numpy.ndarray` containing `[[x_min, y_min], [x_max, y_max]]`, corresponding to the
|
||||
extent of the `displacements` in each dimension.
|
||||
|
||||
Returns:
|
||||
`[[x_min, y_min], [x_max, y_max]]` or `None`
|
||||
"""
|
||||
xy_min = numpy.min(self.displacements, axis=0)
|
||||
xy_max = numpy.max(self.displacements, axis=0)
|
||||
return numpy.array((xy_min, xy_max))
|
||||
|
||||
def scale_by(self, c: float) -> 'Arbitrary':
|
||||
"""
|
||||
Scale the displacements by a factor
|
||||
|
||||
Args:
|
||||
c: scaling factor
|
||||
|
||||
Returns:
|
||||
self
|
||||
"""
|
||||
self.displacements *= c
|
||||
return self
|
||||
|
||||
|
@ -35,27 +35,12 @@ class SubPattern(PositionableImpl, DoseableImpl, RotatableImpl, ScalableImpl, Mi
|
||||
_pattern: Optional['Pattern']
|
||||
""" The `Pattern` being instanced """
|
||||
|
||||
# _offset: numpy.ndarray
|
||||
# """ (x, y) offset for the instance """
|
||||
|
||||
# _rotation: float
|
||||
# """ rotation for the instance, radians counterclockwise """
|
||||
|
||||
# _dose: float
|
||||
# """ dose factor for the instance """
|
||||
|
||||
# _scale: float
|
||||
# """ scale factor for the instance """
|
||||
|
||||
_mirrored: numpy.ndarray # ndarray[bool]
|
||||
""" Whether to mirror the instance across the x and/or y axes. """
|
||||
|
||||
identifier: Tuple[Any, ...]
|
||||
""" Arbitrary identifier, used internally by some `masque` functions. """
|
||||
|
||||
# locked: bool
|
||||
# """ If `True`, disallows changes to the SubPattern"""
|
||||
|
||||
def __init__(self,
|
||||
pattern: Optional['Pattern'],
|
||||
offset: vector2 = (0.0, 0.0),
|
||||
@ -79,7 +64,6 @@ class SubPattern(PositionableImpl, DoseableImpl, RotatableImpl, ScalableImpl, Mi
|
||||
identifier: Arbitrary tuple, used internally by some `masque` functions.
|
||||
"""
|
||||
LockableImpl.unlock(self)
|
||||
# object.__setattr__(self, 'locked', False)
|
||||
self.identifier = identifier
|
||||
self.pattern = pattern
|
||||
self.offset = offset
|
||||
@ -146,9 +130,9 @@ class SubPattern(PositionableImpl, DoseableImpl, RotatableImpl, ScalableImpl, Mi
|
||||
pattern.translate_elements(self.offset)
|
||||
pattern.scale_element_doses(self.dose)
|
||||
|
||||
if pattern.repetition is not None:
|
||||
combined = type(pat)(name='__repetition__')
|
||||
for dd in pattern.repetition.displacements:
|
||||
if self.repetition is not None:
|
||||
combined = type(pattern)(name='__repetition__')
|
||||
for dd in self.repetition.displacements:
|
||||
temp_pat = pattern.deepcopy()
|
||||
temp_pat.translate_elements(dd)
|
||||
combined.append(temp_pat)
|
||||
|
@ -28,10 +28,10 @@ class Doseable(metaclass=ABCMeta):
|
||||
"""
|
||||
pass
|
||||
|
||||
@dose.setter
|
||||
@abstractmethod
|
||||
def dose(self, val: float):
|
||||
pass
|
||||
# @dose.setter
|
||||
# @abstractmethod
|
||||
# def dose(self, val: float):
|
||||
# pass
|
||||
|
||||
'''
|
||||
---- Methods
|
||||
|
@ -25,12 +25,12 @@ class Layerable(metaclass=ABCMeta):
|
||||
"""
|
||||
Layer number or name (int, tuple of ints, or string)
|
||||
"""
|
||||
return self._layer
|
||||
pass
|
||||
|
||||
@layer.setter
|
||||
@abstractmethod
|
||||
def layer(self, val: layer_t):
|
||||
self._layer = val
|
||||
# @layer.setter
|
||||
# @abstractmethod
|
||||
# def layer(self, val: layer_t):
|
||||
# pass
|
||||
|
||||
'''
|
||||
---- Methods
|
||||
|
@ -19,18 +19,6 @@ class Lockable(metaclass=ABCMeta):
|
||||
'''
|
||||
---- Methods
|
||||
'''
|
||||
def set_dose(self: T, dose: float) -> T:
|
||||
"""
|
||||
Set the dose
|
||||
|
||||
Args:
|
||||
dose: new value for dose
|
||||
|
||||
Returns:
|
||||
self
|
||||
"""
|
||||
pass
|
||||
|
||||
def lock(self: T) -> T:
|
||||
"""
|
||||
Lock the object, disallowing further changes
|
||||
|
@ -6,7 +6,7 @@ import numpy
|
||||
from ..error import PatternError, PatternLockedError
|
||||
|
||||
T = TypeVar('T', bound='Mirrorable')
|
||||
T = TypeVar('T', bound='MirrorableImpl')
|
||||
#I = TypeVar('I', bound='MirrorableImpl')
|
||||
|
||||
|
||||
class Mirrorable(metaclass=ABCMeta):
|
||||
|
@ -30,10 +30,10 @@ class Positionable(metaclass=ABCMeta):
|
||||
"""
|
||||
pass
|
||||
|
||||
@offset.setter
|
||||
@abstractmethod
|
||||
def offset(self, val: vector2):
|
||||
pass
|
||||
# @offset.setter
|
||||
# @abstractmethod
|
||||
# def offset(self, val: vector2):
|
||||
# pass
|
||||
|
||||
'''
|
||||
--- Abstract methods
|
||||
|
@ -1,4 +1,4 @@
|
||||
from typing import List, Tuple, Callable, TypeVar, Optional
|
||||
from typing import List, Tuple, Callable, TypeVar, Optional, TYPE_CHECKING
|
||||
from abc import ABCMeta, abstractmethod
|
||||
import copy
|
||||
import numpy
|
||||
@ -6,6 +6,10 @@ import numpy
|
||||
from ..error import PatternError, PatternLockedError
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..repetition import Repetition
|
||||
|
||||
|
||||
T = TypeVar('T', bound='Repeatable')
|
||||
I = TypeVar('I', bound='RepeatableImpl')
|
||||
|
||||
@ -27,14 +31,15 @@ class Repeatable(metaclass=ABCMeta):
|
||||
"""
|
||||
pass
|
||||
|
||||
@repetition.setter
|
||||
@abstractmethod
|
||||
def repetition(self, repetition: Optional['Repetition']):
|
||||
pass
|
||||
# @repetition.setter
|
||||
# @abstractmethod
|
||||
# def repetition(self, repetition: Optional['Repetition']):
|
||||
# pass
|
||||
|
||||
'''
|
||||
---- Methods
|
||||
'''
|
||||
@abstractmethod
|
||||
def set_repetition(self: T, repetition: Optional['Repetition']) -> T:
|
||||
"""
|
||||
Set the repetition
|
||||
@ -74,6 +79,6 @@ class RepeatableImpl(Repeatable, metaclass=ABCMeta):
|
||||
'''
|
||||
---- Non-abstract methods
|
||||
'''
|
||||
def set_repetition(self: I, repetition: 'Repetition') -> I:
|
||||
def set_repetition(self: I, repetition: Optional['Repetition']) -> I:
|
||||
self.repetition = repetition
|
||||
return self
|
||||
|
Loading…
Reference in New Issue
Block a user