add support for annotations
and other fixes
This commit is contained in:
parent
5d83e0e5c0
commit
49a3b4e322
28 changed files with 400 additions and 133 deletions
|
|
@ -1,13 +1,15 @@
|
|||
from typing import List, Tuple, Dict, Optional, Sequence
|
||||
import copy
|
||||
import math
|
||||
import numpy
|
||||
|
||||
import numpy # type: ignore
|
||||
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
|
||||
from ..utils import is_scalar, vector2, layer_t, AutoSlots, annotations_t
|
||||
from ..traits import LockableImpl
|
||||
|
||||
|
||||
class Arc(Shape, metaclass=AutoSlots):
|
||||
|
|
@ -160,10 +162,11 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
layer: layer_t = 0,
|
||||
dose: float = 1.0,
|
||||
repetition: Optional[Repetition] = None,
|
||||
annotations: Optional[annotations_t] = None,
|
||||
locked: bool = False,
|
||||
raw: bool = False,
|
||||
):
|
||||
object.__setattr__(self, 'locked', False)
|
||||
LockableImpl.unlock(self)
|
||||
self.identifier = ()
|
||||
if raw:
|
||||
self._radii = radii
|
||||
|
|
@ -172,6 +175,7 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
self._offset = offset
|
||||
self._rotation = rotation
|
||||
self._repetition = repetition
|
||||
self._annotations = annotations if annotations is not None else {}
|
||||
self._layer = layer
|
||||
self._dose = dose
|
||||
else:
|
||||
|
|
@ -181,12 +185,13 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
self.offset = offset
|
||||
self.rotation = rotation
|
||||
self.repetition = repetition
|
||||
self.annotations = annotations if annotations is not None else {}
|
||||
self.layer = layer
|
||||
self.dose = dose
|
||||
self.poly_num_points = poly_num_points
|
||||
self.poly_max_arclen = poly_max_arclen
|
||||
[self.mirror(a) for a, do in enumerate(mirrored) if do]
|
||||
self.locked = locked
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Arc':
|
||||
memo = {} if memo is None else memo
|
||||
|
|
@ -194,7 +199,8 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
new._offset = self._offset.copy()
|
||||
new._radii = self._radii.copy()
|
||||
new._angles = self._angles.copy()
|
||||
new.locked = self.locked
|
||||
new._annotations = copy.deepcopy(self._annotations)
|
||||
new.set_locked(self.locked)
|
||||
return new
|
||||
|
||||
def to_polygons(self,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
from typing import List, Dict, Optional
|
||||
import copy
|
||||
import numpy
|
||||
|
||||
import numpy # type: ignore
|
||||
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
|
||||
from ..utils import is_scalar, vector2, layer_t, AutoSlots, annotations_t
|
||||
from ..traits import LockableImpl
|
||||
|
||||
|
||||
class Circle(Shape, metaclass=AutoSlots):
|
||||
|
|
@ -48,23 +50,36 @@ class Circle(Shape, metaclass=AutoSlots):
|
|||
layer: layer_t = 0,
|
||||
dose: float = 1.0,
|
||||
repetition: Optional[Repetition] = None,
|
||||
locked: bool = False):
|
||||
object.__setattr__(self, 'locked', False)
|
||||
annotations: Optional[annotations_t] = None,
|
||||
locked: bool = False,
|
||||
raw: bool = False,
|
||||
):
|
||||
LockableImpl.unlock(self)
|
||||
self.identifier = ()
|
||||
self.offset = numpy.array(offset, dtype=float)
|
||||
self.layer = layer
|
||||
self.dose = dose
|
||||
self.radius = radius
|
||||
if raw:
|
||||
self._radius = radius
|
||||
self._offset = offset
|
||||
self._repetition = repetition
|
||||
self._annotations = annotations if annotations is not None else {}
|
||||
self._layer = layer
|
||||
self._dose = dose
|
||||
else:
|
||||
self.radius = radius
|
||||
self.offset = offset
|
||||
self.repetition = repetition
|
||||
self.annotations = annotations if annotations is not None else {}
|
||||
self.layer = layer
|
||||
self.dose = dose
|
||||
self.poly_num_points = poly_num_points
|
||||
self.poly_max_arclen = poly_max_arclen
|
||||
self.repetition = repetition
|
||||
self.locked = locked
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Circle':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self).unlock()
|
||||
new._offset = self._offset.copy()
|
||||
new.locked = self.locked
|
||||
new._annotations = copy.deepcopy(self._annotations)
|
||||
new.set_locked(self.locked)
|
||||
return new
|
||||
|
||||
def to_polygons(self,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
from typing import List, Tuple, Dict, Sequence, Optional
|
||||
import copy
|
||||
import math
|
||||
import numpy
|
||||
|
||||
import numpy # type: ignore
|
||||
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
|
||||
from ..utils import is_scalar, rotation_matrix_2d, vector2, layer_t, AutoSlots, annotations_t
|
||||
from ..traits import LockableImpl
|
||||
|
||||
|
||||
class Ellipse(Shape, metaclass=AutoSlots):
|
||||
|
|
@ -95,16 +97,18 @@ class Ellipse(Shape, metaclass=AutoSlots):
|
|||
layer: layer_t = 0,
|
||||
dose: float = 1.0,
|
||||
repetition: Optional[Repetition] = None,
|
||||
annotations: Optional[annotations_t] = None,
|
||||
locked: bool = False,
|
||||
raw: bool = False,
|
||||
):
|
||||
object.__setattr__(self, 'locked', False)
|
||||
LockableImpl.unlock(self)
|
||||
self.identifier = ()
|
||||
if raw:
|
||||
self._radii = radii
|
||||
self._offset = offset
|
||||
self._rotation = rotation
|
||||
self._repetition = repetition
|
||||
self._annotations = annotations if annotations is not None else {}
|
||||
self._layer = layer
|
||||
self._dose = dose
|
||||
else:
|
||||
|
|
@ -112,19 +116,21 @@ class Ellipse(Shape, metaclass=AutoSlots):
|
|||
self.offset = offset
|
||||
self.rotation = rotation
|
||||
self.repetition = repetition
|
||||
self.annotations = annotations if annotations is not None else {}
|
||||
self.layer = layer
|
||||
self.dose = dose
|
||||
[self.mirror(a) for a, do in enumerate(mirrored) if do]
|
||||
self.poly_num_points = poly_num_points
|
||||
self.poly_max_arclen = poly_max_arclen
|
||||
self.locked = locked
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Ellipse':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self).unlock()
|
||||
new._offset = self._offset.copy()
|
||||
new._radii = self._radii.copy()
|
||||
new.locked = self.locked
|
||||
new._annotations = copy.deepcopy(self._annotations)
|
||||
new.set_locked(self.locked)
|
||||
return new
|
||||
|
||||
def to_polygons(self,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
from typing import List, Tuple, Dict, Optional, Sequence
|
||||
import copy
|
||||
from enum import Enum
|
||||
import numpy
|
||||
|
||||
import numpy # type: ignore
|
||||
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
|
||||
from ..utils import remove_colinear_vertices, remove_duplicate_vertices, annotations_t
|
||||
from ..traits import LockableImpl
|
||||
|
||||
|
||||
class PathCap(Enum):
|
||||
|
|
@ -149,10 +151,11 @@ class Path(Shape, metaclass=AutoSlots):
|
|||
layer: layer_t = 0,
|
||||
dose: float = 1.0,
|
||||
repetition: Optional[Repetition] = None,
|
||||
annotations: Optional[annotations_t] = None,
|
||||
locked: bool = False,
|
||||
raw: bool = False,
|
||||
):
|
||||
object.__setattr__(self, 'locked', False)
|
||||
LockableImpl.unlock(self)
|
||||
self._cap_extensions = None # Since .cap setter might access it
|
||||
|
||||
self.identifier = ()
|
||||
|
|
@ -160,6 +163,7 @@ class Path(Shape, metaclass=AutoSlots):
|
|||
self._vertices = vertices
|
||||
self._offset = offset
|
||||
self._repetition = repetition
|
||||
self._annotations = annotations if annotations is not None else {}
|
||||
self._layer = layer
|
||||
self._dose = dose
|
||||
self._width = width
|
||||
|
|
@ -169,6 +173,7 @@ class Path(Shape, metaclass=AutoSlots):
|
|||
self.vertices = vertices
|
||||
self.offset = offset
|
||||
self.repetition = repetition
|
||||
self.annotations = annotations if annotations is not None else {}
|
||||
self.layer = layer
|
||||
self.dose = dose
|
||||
self.width = width
|
||||
|
|
@ -176,7 +181,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.locked = locked
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Path':
|
||||
memo = {} if memo is None else memo
|
||||
|
|
@ -185,7 +190,8 @@ class Path(Shape, metaclass=AutoSlots):
|
|||
new._vertices = self._vertices.copy()
|
||||
new._cap = copy.deepcopy(self._cap, memo)
|
||||
new._cap_extensions = copy.deepcopy(self._cap_extensions, memo)
|
||||
new.locked = self.locked
|
||||
new._annotations = copy.deepcopy(self._annotations)
|
||||
new.set_locked(self.locked)
|
||||
return new
|
||||
|
||||
@staticmethod
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
from typing import List, Tuple, Dict, Optional, Sequence
|
||||
import copy
|
||||
import numpy
|
||||
|
||||
import numpy # type: ignore
|
||||
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
|
||||
from ..utils import remove_colinear_vertices, remove_duplicate_vertices, annotations_t
|
||||
from ..traits import LockableImpl
|
||||
|
||||
|
||||
class Polygon(Shape, metaclass=AutoSlots):
|
||||
|
|
@ -77,33 +79,37 @@ class Polygon(Shape, metaclass=AutoSlots):
|
|||
layer: layer_t = 0,
|
||||
dose: float = 1.0,
|
||||
repetition: Optional[Repetition] = None,
|
||||
annotations: Optional[annotations_t] = None,
|
||||
locked: bool = False,
|
||||
raw: bool = False,
|
||||
):
|
||||
object.__setattr__(self, 'locked', False)
|
||||
LockableImpl.unlock(self)
|
||||
self.identifier = ()
|
||||
if raw:
|
||||
self._vertices = vertices
|
||||
self._offset = offset
|
||||
self._repetition = repetition
|
||||
self._annotations = annotations if annotations is not None else {}
|
||||
self._layer = layer
|
||||
self._dose = dose
|
||||
else:
|
||||
self.vertices = vertices
|
||||
self.offset = offset
|
||||
self.repetition = repetition
|
||||
self.annotations = annotations if annotations is not None else {}
|
||||
self.layer = layer
|
||||
self.dose = dose
|
||||
self.rotate(rotation)
|
||||
[self.mirror(a) for a, do in enumerate(mirrored) if do]
|
||||
self.locked = locked
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Optional[Dict] = None) -> 'Polygon':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self).unlock()
|
||||
new._offset = self._offset.copy()
|
||||
new._vertices = self._vertices.copy()
|
||||
new.locked = self.locked
|
||||
new._annotations = copy.deepcopy(self._annotations)
|
||||
new.set_locked(self.locked)
|
||||
return new
|
||||
|
||||
@staticmethod
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
from typing import List, Tuple, Callable, TypeVar, Optional, TYPE_CHECKING
|
||||
from abc import ABCMeta, abstractmethod
|
||||
import copy
|
||||
import numpy
|
||||
|
||||
import numpy # type: ignore
|
||||
|
||||
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, RepeatableImpl)
|
||||
PivotableImpl, LockableImpl, RepeatableImpl,
|
||||
AnnotatableImpl)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import Polygon
|
||||
|
|
@ -27,7 +29,7 @@ T = TypeVar('T', bound='Shape')
|
|||
|
||||
|
||||
class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable, Copyable, Scalable,
|
||||
PivotableImpl, RepeatableImpl, LockableImpl, metaclass=ABCMeta):
|
||||
PivotableImpl, RepeatableImpl, LockableImpl, AnnotatableImpl, metaclass=ABCMeta):
|
||||
"""
|
||||
Abstract class specifying functions common to all shapes.
|
||||
"""
|
||||
|
|
@ -39,7 +41,7 @@ class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable
|
|||
def __copy__(self) -> 'Shape':
|
||||
cls = self.__class__
|
||||
new = cls.__new__(cls)
|
||||
for name in self.__slots__:
|
||||
for name in self.__slots__: # type: str
|
||||
object.__setattr__(new, name, getattr(self, name))
|
||||
return new
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from typing import List, Tuple, Dict, Sequence, Optional, MutableSequence
|
||||
import copy
|
||||
import numpy
|
||||
|
||||
import numpy # type: ignore
|
||||
from numpy import pi, inf
|
||||
|
||||
from . import Shape, Polygon, normalized_shape_tuple
|
||||
|
|
@ -8,6 +9,8 @@ from .. import PatternError
|
|||
from ..repetition import Repetition
|
||||
from ..traits import RotatableImpl
|
||||
from ..utils import is_scalar, vector2, get_bit, normalize_mirror, layer_t, AutoSlots
|
||||
from ..utils import annotations_t
|
||||
from ..traits import LockableImpl
|
||||
|
||||
# Loaded on use:
|
||||
# from freetype import Face
|
||||
|
|
@ -67,10 +70,11 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
|
|||
layer: layer_t = 0,
|
||||
dose: float = 1.0,
|
||||
repetition: Optional[Repetition] = None,
|
||||
annotations: Optional[annotations_t] = None,
|
||||
locked: bool = False,
|
||||
raw: bool = False,
|
||||
):
|
||||
object.__setattr__(self, 'locked', False)
|
||||
LockableImpl.unlock(self)
|
||||
self.identifier = ()
|
||||
if raw:
|
||||
self._offset = offset
|
||||
|
|
@ -81,6 +85,7 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
|
|||
self._rotation = rotation
|
||||
self._mirrored = mirrored
|
||||
self._repetition = repetition
|
||||
self._annotations = annotations if annotations is not None else {}
|
||||
else:
|
||||
self.offset = offset
|
||||
self.layer = layer
|
||||
|
|
@ -90,15 +95,17 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
|
|||
self.rotation = rotation
|
||||
self.mirrored = mirrored
|
||||
self.repetition = repetition
|
||||
self.annotations = annotations if annotations is not None else {}
|
||||
self.font_path = font_path
|
||||
self.locked = locked
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Text':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self).unlock()
|
||||
new._offset = self._offset.copy()
|
||||
new._mirrored = copy.deepcopy(self._mirrored, memo)
|
||||
new.locked = self.locked
|
||||
new._annotations = copy.deepcopy(self._annotations)
|
||||
new.set_locked(self.locked)
|
||||
return new
|
||||
|
||||
def to_polygons(self,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue