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_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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user