enable per-shape repetitions
This commit is contained in:
		
							parent
							
								
									f99b72262e
								
							
						
					
					
						commit
						7a0c59c480
					
				| @ -1,14 +1,16 @@ | ||||
| from typing import List, Tuple, Dict | ||||
| from typing import List, Tuple, Dict, Optional | ||||
| import copy | ||||
| import numpy | ||||
| from numpy import pi | ||||
| 
 | ||||
| from .repetition import Repetition | ||||
| from .error import PatternError, PatternLockedError | ||||
| from .utils import is_scalar, vector2, rotation_matrix_2d, layer_t, AutoSlots | ||||
| from .traits import PositionableImpl, LayerableImpl, Copyable, Pivotable, LockableImpl | ||||
| from .traits import PositionableImpl, LayerableImpl, Copyable, Pivotable, LockableImpl, RepeatableImpl | ||||
| 
 | ||||
| 
 | ||||
| class Label(PositionableImpl, LayerableImpl, LockableImpl, Pivotable, Copyable, metaclass=AutoSlots): | ||||
| class Label(PositionableImpl, LayerableImpl, LockableImpl, RepeatableImpl, | ||||
|             Pivotable, Copyable, metaclass=AutoSlots): | ||||
|     """ | ||||
|     A text annotation with a position and layer (but no size; it is not drawn) | ||||
|     """ | ||||
| @ -39,18 +41,21 @@ class Label(PositionableImpl, LayerableImpl, LockableImpl, Pivotable, Copyable, | ||||
|                  string: str, | ||||
|                  offset: vector2 = (0.0, 0.0), | ||||
|                  layer: layer_t = 0, | ||||
|                  repetition: Optional[Repetition] = None, | ||||
|                  locked: bool = False): | ||||
|         object.__setattr__(self, 'locked', False) | ||||
|         self.identifier = () | ||||
|         self.string = string | ||||
|         self.offset = numpy.array(offset, dtype=float, copy=True) | ||||
|         self.layer = layer | ||||
|         self.repetition = repetition | ||||
|         self.locked = locked | ||||
| 
 | ||||
|     def __copy__(self) -> 'Label': | ||||
|         return Label(string=self.string, | ||||
|                      offset=self.offset.copy(), | ||||
|                      layer=self.layer, | ||||
|                      repetition=self.repetition, | ||||
|                      locked=self.locked) | ||||
| 
 | ||||
|     def  __deepcopy__(self, memo: Dict = None) -> 'Label': | ||||
|  | ||||
| @ -575,6 +575,52 @@ class Pattern: | ||||
|             self.append(p) | ||||
|         return self | ||||
| 
 | ||||
|     def wrap_repeated_shapes(self, | ||||
|                              name_func: Callable[['Pattern', Union[Shape, Label]], str] = lambda p, s: '_repetition', | ||||
|                              recursive: bool = True, | ||||
|                              ) -> 'Pattern': | ||||
|         """ | ||||
|         Wraps all shapes and labels with a non-`None` `repetition` attribute | ||||
|           into a `SubPattern`/`Pattern` combination, and applies the `repetition` | ||||
|           to each `SubPattern` instead of its contained shape. | ||||
| 
 | ||||
|         Args: | ||||
|             name_func: Function f(this_pattern, shape) which generates a name for the | ||||
|                         wrapping pattern. Default always returns '_repetition'. | ||||
|             recursive: If `True`, this function is also applied to all referenced patterns | ||||
|                         recursively. Default `True`. | ||||
| 
 | ||||
|         Returns: | ||||
|             self | ||||
|         """ | ||||
|         def do_wrap(pat: Optional[Pattern]) -> Optional[Pattern]: | ||||
|             if pat is None: | ||||
|                 return pat | ||||
| 
 | ||||
|             new_subpatterns = [] | ||||
|             for shape in pat.shapes: | ||||
|                 if shape.repetition is None: | ||||
|                     continue | ||||
|                 new_subpatterns.append(SubPattern(Pattern(name_func(pat, shape), shapes=[shape]))) | ||||
|                 shape.repetition = None | ||||
| 
 | ||||
|             for label in self.labels: | ||||
|                 if label.repetition is None: | ||||
|                     continue | ||||
|                 new_subpatterns.append(SubPattern(Pattern(name_func(pat, shape), labels=[label]))) | ||||
|                 label.repetition = None | ||||
| 
 | ||||
|             pat.subpatterns += new_subpatterns | ||||
|             return pat | ||||
| 
 | ||||
|         if recursive: | ||||
|             self.apply(do_wrap) | ||||
|         else: | ||||
|             do_wrap(self) | ||||
| 
 | ||||
|         return self | ||||
| 
 | ||||
| 
 | ||||
|     def translate_elements(self, offset: vector2) -> 'Pattern': | ||||
|         """ | ||||
|         Translates all shapes, label, and subpatterns by the given offset. | ||||
|  | ||||
| @ -6,6 +6,7 @@ from numpy import pi | ||||
| 
 | ||||
| from . import Shape, Polygon, normalized_shape_tuple, DEFAULT_POLY_NUM_POINTS | ||||
| from .. import PatternError | ||||
| from ..repetition import Repetition | ||||
| from ..utils import is_scalar, vector2, layer_t, AutoSlots | ||||
| 
 | ||||
| 
 | ||||
| @ -158,6 +159,7 @@ class Arc(Shape, metaclass=AutoSlots): | ||||
|                  mirrored: Sequence[bool] = (False, False), | ||||
|                  layer: layer_t = 0, | ||||
|                  dose: float = 1.0, | ||||
|                  repetition: Optional[Repetition] = None, | ||||
|                  locked: bool = False): | ||||
|         object.__setattr__(self, 'locked', False) | ||||
|         self.identifier = () | ||||
| @ -171,6 +173,7 @@ class Arc(Shape, metaclass=AutoSlots): | ||||
|         self.dose = dose | ||||
|         self.poly_num_points = poly_num_points | ||||
|         self.poly_max_arclen = poly_max_arclen | ||||
|         self.repetition = repetition | ||||
|         self.locked = locked | ||||
| 
 | ||||
|     def  __deepcopy__(self, memo: Dict = None) -> 'Arc': | ||||
|  | ||||
| @ -5,6 +5,7 @@ from numpy import pi | ||||
| 
 | ||||
| from . import Shape, Polygon, normalized_shape_tuple, DEFAULT_POLY_NUM_POINTS | ||||
| from .. import PatternError | ||||
| from ..repetition import Repetition | ||||
| from ..utils import is_scalar, vector2, layer_t, AutoSlots | ||||
| 
 | ||||
| 
 | ||||
| @ -46,6 +47,7 @@ class Circle(Shape, metaclass=AutoSlots): | ||||
|                  offset: vector2 = (0.0, 0.0), | ||||
|                  layer: layer_t = 0, | ||||
|                  dose: float = 1.0, | ||||
|                  repetition: Optional[Repetition] = None, | ||||
|                  locked: bool = False): | ||||
|         object.__setattr__(self, 'locked', False) | ||||
|         self.identifier = () | ||||
| @ -55,6 +57,7 @@ class Circle(Shape, metaclass=AutoSlots): | ||||
|         self.radius = radius | ||||
|         self.poly_num_points = poly_num_points | ||||
|         self.poly_max_arclen = poly_max_arclen | ||||
|         self.repetition = repetition | ||||
|         self.locked = locked | ||||
| 
 | ||||
|     def  __deepcopy__(self, memo: Dict = None) -> 'Circle': | ||||
|  | ||||
| @ -6,6 +6,7 @@ from numpy import pi | ||||
| 
 | ||||
| from . import Shape, Polygon, normalized_shape_tuple, DEFAULT_POLY_NUM_POINTS | ||||
| from .. import PatternError | ||||
| from ..repetition import Repetition | ||||
| from ..utils import is_scalar, rotation_matrix_2d, vector2, layer_t, AutoSlots | ||||
| 
 | ||||
| 
 | ||||
| @ -93,6 +94,7 @@ class Ellipse(Shape, metaclass=AutoSlots): | ||||
|                  mirrored: Sequence[bool] = (False, False), | ||||
|                  layer: layer_t = 0, | ||||
|                  dose: float = 1.0, | ||||
|                  repetition: Optional[Repetition] = None, | ||||
|                  locked: bool = False): | ||||
|         object.__setattr__(self, 'locked', False) | ||||
|         self.identifier = () | ||||
| @ -104,6 +106,7 @@ class Ellipse(Shape, metaclass=AutoSlots): | ||||
|         self.dose = dose | ||||
|         self.poly_num_points = poly_num_points | ||||
|         self.poly_max_arclen = poly_max_arclen | ||||
|         self.repetition = repetition | ||||
|         self.locked = locked | ||||
| 
 | ||||
|     def  __deepcopy__(self, memo: Dict = None) -> 'Ellipse': | ||||
|  | ||||
| @ -6,6 +6,7 @@ from numpy import pi, inf | ||||
| 
 | ||||
| from . import Shape, normalized_shape_tuple, Polygon, Circle | ||||
| from .. import PatternError | ||||
| from ..repetition import Repetition | ||||
| from ..utils import is_scalar, rotation_matrix_2d, vector2, layer_t, AutoSlots | ||||
| from ..utils import remove_colinear_vertices, remove_duplicate_vertices | ||||
| 
 | ||||
| @ -147,6 +148,7 @@ class Path(Shape, metaclass=AutoSlots): | ||||
|                  mirrored: Sequence[bool] = (False, False), | ||||
|                  layer: layer_t = 0, | ||||
|                  dose: float = 1.0, | ||||
|                  repetition: Optional[Repetition] = None, | ||||
|                  locked: bool = False, | ||||
|                  ): | ||||
|         object.__setattr__(self, 'locked', False) | ||||
| @ -163,6 +165,7 @@ class Path(Shape, metaclass=AutoSlots): | ||||
|             self.cap_extensions = cap_extensions | ||||
|         self.rotate(rotation) | ||||
|         [self.mirror(a) for a, do in enumerate(mirrored) if do] | ||||
|         self.repetition = repetition | ||||
|         self.locked = locked | ||||
| 
 | ||||
|     def  __deepcopy__(self, memo: Dict = None) -> 'Path': | ||||
|  | ||||
| @ -5,6 +5,7 @@ from numpy import pi | ||||
| 
 | ||||
| from . import Shape, normalized_shape_tuple | ||||
| from .. import PatternError | ||||
| from ..repetition import Repetition | ||||
| from ..utils import is_scalar, rotation_matrix_2d, vector2, layer_t, AutoSlots | ||||
| from ..utils import remove_colinear_vertices, remove_duplicate_vertices | ||||
| 
 | ||||
| @ -75,6 +76,7 @@ class Polygon(Shape, metaclass=AutoSlots): | ||||
|                  mirrored: Sequence[bool] = (False, False), | ||||
|                  layer: layer_t = 0, | ||||
|                  dose: float = 1.0, | ||||
|                  repetition: Optional[Repetition] = None, | ||||
|                  locked: bool = False, | ||||
|                  ): | ||||
|         object.__setattr__(self, 'locked', False) | ||||
| @ -85,6 +87,7 @@ class Polygon(Shape, metaclass=AutoSlots): | ||||
|         self.offset = offset | ||||
|         self.rotate(rotation) | ||||
|         [self.mirror(a) for a, do in enumerate(mirrored) if do] | ||||
|         self.repetition = repetition | ||||
|         self.locked = locked | ||||
| 
 | ||||
|     def  __deepcopy__(self, memo: Optional[Dict] = None) -> 'Polygon': | ||||
|  | ||||
| @ -7,7 +7,7 @@ from ..error import PatternError, PatternLockedError | ||||
| from ..utils import is_scalar, rotation_matrix_2d, vector2, layer_t | ||||
| from ..traits import (PositionableImpl, LayerableImpl, DoseableImpl, | ||||
|                       Rotatable, Mirrorable, Copyable, Scalable, | ||||
|                       PivotableImpl, LockableImpl) | ||||
|                       PivotableImpl, LockableImpl, RepeatableImpl) | ||||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from . import Polygon | ||||
| @ -26,7 +26,8 @@ DEFAULT_POLY_NUM_POINTS = 24 | ||||
| T = TypeVar('T', bound='Shape') | ||||
| 
 | ||||
| 
 | ||||
| class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable, Copyable, Scalable, PivotableImpl, LockableImpl, metaclass=ABCMeta): | ||||
| class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable, Copyable, Scalable, | ||||
|             PivotableImpl, RepeatableImpl, LockableImpl, metaclass=ABCMeta): | ||||
|     """ | ||||
|     Abstract class specifying functions common to all shapes. | ||||
|     """ | ||||
|  | ||||
| @ -5,6 +5,7 @@ from numpy import pi, inf | ||||
| 
 | ||||
| from . import Shape, Polygon, normalized_shape_tuple | ||||
| from .. import PatternError | ||||
| from ..repetition import Repetition | ||||
| from ..traits import RotatableImpl | ||||
| from ..utils import is_scalar, vector2, get_bit, normalize_mirror, layer_t, AutoSlots | ||||
| 
 | ||||
| @ -65,6 +66,7 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots): | ||||
|                  mirrored: Tuple[bool, bool] = (False, False), | ||||
|                  layer: layer_t = 0, | ||||
|                  dose: float = 1.0, | ||||
|                  repetition: Optional[Repetition] = None, | ||||
|                  locked: bool = False, | ||||
|                  ): | ||||
|         object.__setattr__(self, 'locked', False) | ||||
| @ -77,6 +79,7 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots): | ||||
|         self.rotation = rotation | ||||
|         self.font_path = font_path | ||||
|         self.mirrored = mirrored | ||||
|         self.repetition = repetition | ||||
|         self.locked = locked | ||||
| 
 | ||||
|     def  __deepcopy__(self, memo: Dict = None) -> 'Text': | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user