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