WIP: make libraries and names first-class!
This commit is contained in:
parent
f834ec6be5
commit
7aaf73cb37
34 changed files with 1780 additions and 1812 deletions
|
|
@ -10,7 +10,6 @@ from . import Shape, Polygon, normalized_shape_tuple, DEFAULT_POLY_NUM_POINTS
|
|||
from .. import PatternError
|
||||
from ..repetition import Repetition
|
||||
from ..utils import is_scalar, layer_t, AutoSlots, annotations_t
|
||||
from ..traits import LockableImpl
|
||||
|
||||
|
||||
class Arc(Shape, metaclass=AutoSlots):
|
||||
|
|
@ -166,10 +165,8 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
dose: float = 1.0,
|
||||
repetition: Optional[Repetition] = None,
|
||||
annotations: Optional[annotations_t] = None,
|
||||
locked: bool = False,
|
||||
raw: bool = False,
|
||||
) -> None:
|
||||
LockableImpl.unlock(self)
|
||||
self.identifier = ()
|
||||
if raw:
|
||||
assert(isinstance(radii, numpy.ndarray))
|
||||
|
|
@ -197,17 +194,14 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
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.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Arc':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self)
|
||||
Shape.unlock(new)
|
||||
new._offset = self._offset.copy()
|
||||
new._radii = self._radii.copy()
|
||||
new._angles = self._angles.copy()
|
||||
new._annotations = copy.deepcopy(self._annotations)
|
||||
new.set_locked(self.locked)
|
||||
return new
|
||||
|
||||
def to_polygons(
|
||||
|
|
@ -429,21 +423,8 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
a.append((a0, a1))
|
||||
return numpy.array(a)
|
||||
|
||||
def lock(self) -> 'Arc':
|
||||
self.radii.flags.writeable = False
|
||||
self.angles.flags.writeable = False
|
||||
Shape.lock(self)
|
||||
return self
|
||||
|
||||
def unlock(self) -> 'Arc':
|
||||
Shape.unlock(self)
|
||||
self.radii.flags.writeable = True
|
||||
self.angles.flags.writeable = True
|
||||
return self
|
||||
|
||||
def __repr__(self) -> str:
|
||||
angles = f' a°{numpy.rad2deg(self.angles)}'
|
||||
rotation = f' r°{numpy.rad2deg(self.rotation):g}' if self.rotation != 0 else ''
|
||||
dose = f' d{self.dose:g}' if self.dose != 1 else ''
|
||||
locked = ' L' if self.locked else ''
|
||||
return f'<Arc l{self.layer} o{self.offset} r{self.radii}{angles} w{self.width:g}{rotation}{dose}{locked}>'
|
||||
return f'<Arc l{self.layer} o{self.offset} r{self.radii}{angles} w{self.width:g}{rotation}{dose}>'
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ from . import Shape, Polygon, normalized_shape_tuple, DEFAULT_POLY_NUM_POINTS
|
|||
from .. import PatternError
|
||||
from ..repetition import Repetition
|
||||
from ..utils import is_scalar, layer_t, AutoSlots, annotations_t
|
||||
from ..traits import LockableImpl
|
||||
|
||||
|
||||
class Circle(Shape, metaclass=AutoSlots):
|
||||
|
|
@ -54,10 +53,8 @@ class Circle(Shape, metaclass=AutoSlots):
|
|||
dose: float = 1.0,
|
||||
repetition: Optional[Repetition] = None,
|
||||
annotations: Optional[annotations_t] = None,
|
||||
locked: bool = False,
|
||||
raw: bool = False,
|
||||
) -> None:
|
||||
LockableImpl.unlock(self)
|
||||
self.identifier = ()
|
||||
if raw:
|
||||
assert(isinstance(offset, numpy.ndarray))
|
||||
|
|
@ -76,15 +73,12 @@ class Circle(Shape, metaclass=AutoSlots):
|
|||
self.dose = dose
|
||||
self.poly_num_points = poly_num_points
|
||||
self.poly_max_arclen = poly_max_arclen
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Circle':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self)
|
||||
Shape.unlock(new)
|
||||
new._offset = self._offset.copy()
|
||||
new._annotations = copy.deepcopy(self._annotations)
|
||||
new.set_locked(self.locked)
|
||||
return new
|
||||
|
||||
def to_polygons(
|
||||
|
|
@ -138,5 +132,4 @@ class Circle(Shape, metaclass=AutoSlots):
|
|||
|
||||
def __repr__(self) -> str:
|
||||
dose = f' d{self.dose:g}' if self.dose != 1 else ''
|
||||
locked = ' L' if self.locked else ''
|
||||
return f'<Circle l{self.layer} o{self.offset} r{self.radius:g}{dose}{locked}>'
|
||||
return f'<Circle l{self.layer} o{self.offset} r{self.radius:g}{dose}>'
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ 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, layer_t, AutoSlots, annotations_t
|
||||
from ..traits import LockableImpl
|
||||
|
||||
|
||||
class Ellipse(Shape, metaclass=AutoSlots):
|
||||
|
|
@ -101,10 +100,8 @@ class Ellipse(Shape, metaclass=AutoSlots):
|
|||
dose: float = 1.0,
|
||||
repetition: Optional[Repetition] = None,
|
||||
annotations: Optional[annotations_t] = None,
|
||||
locked: bool = False,
|
||||
raw: bool = False,
|
||||
) -> None:
|
||||
LockableImpl.unlock(self)
|
||||
self.identifier = ()
|
||||
if raw:
|
||||
assert(isinstance(radii, numpy.ndarray))
|
||||
|
|
@ -127,16 +124,13 @@ class Ellipse(Shape, metaclass=AutoSlots):
|
|||
[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.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Ellipse':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self)
|
||||
Shape.unlock(new)
|
||||
new._offset = self._offset.copy()
|
||||
new._radii = self._radii.copy()
|
||||
new._annotations = copy.deepcopy(self._annotations)
|
||||
new.set_locked(self.locked)
|
||||
return new
|
||||
|
||||
def to_polygons(
|
||||
|
|
@ -209,18 +203,7 @@ class Ellipse(Shape, metaclass=AutoSlots):
|
|||
(self.offset, scale / norm_value, angle, False, self.dose),
|
||||
lambda: Ellipse(radii=radii * norm_value, layer=self.layer))
|
||||
|
||||
def lock(self) -> 'Ellipse':
|
||||
self.radii.flags.writeable = False
|
||||
Shape.lock(self)
|
||||
return self
|
||||
|
||||
def unlock(self) -> 'Ellipse':
|
||||
Shape.unlock(self)
|
||||
self.radii.flags.writeable = True
|
||||
return self
|
||||
|
||||
def __repr__(self) -> str:
|
||||
rotation = f' r{self.rotation*180/pi:g}' if self.rotation != 0 else ''
|
||||
dose = f' d{self.dose:g}' if self.dose != 1 else ''
|
||||
locked = ' L' if self.locked else ''
|
||||
return f'<Ellipse l{self.layer} o{self.offset} r{self.radii}{rotation}{dose}{locked}>'
|
||||
return f'<Ellipse l{self.layer} o{self.offset} r{self.radii}{rotation}{dose}>'
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ from .. import PatternError
|
|||
from ..repetition import Repetition
|
||||
from ..utils import is_scalar, rotation_matrix_2d, layer_t, AutoSlots
|
||||
from ..utils import remove_colinear_vertices, remove_duplicate_vertices, annotations_t
|
||||
from ..traits import LockableImpl
|
||||
|
||||
|
||||
class PathCap(Enum):
|
||||
|
|
@ -155,10 +154,8 @@ class Path(Shape, metaclass=AutoSlots):
|
|||
dose: float = 1.0,
|
||||
repetition: Optional[Repetition] = None,
|
||||
annotations: Optional[annotations_t] = None,
|
||||
locked: bool = False,
|
||||
raw: bool = False,
|
||||
) -> None:
|
||||
LockableImpl.unlock(self)
|
||||
self._cap_extensions = None # Since .cap setter might access it
|
||||
|
||||
self.identifier = ()
|
||||
|
|
@ -187,18 +184,15 @@ 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.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Path':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self)
|
||||
Shape.unlock(new)
|
||||
new._offset = self._offset.copy()
|
||||
new._vertices = self._vertices.copy()
|
||||
new._cap = copy.deepcopy(self._cap, memo)
|
||||
new._cap_extensions = copy.deepcopy(self._cap_extensions, memo)
|
||||
new._annotations = copy.deepcopy(self._annotations)
|
||||
new.set_locked(self.locked)
|
||||
return new
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -424,22 +418,7 @@ class Path(Shape, metaclass=AutoSlots):
|
|||
extensions = numpy.zeros(2)
|
||||
return extensions
|
||||
|
||||
def lock(self) -> 'Path':
|
||||
self.vertices.flags.writeable = False
|
||||
if self.cap_extensions is not None:
|
||||
self.cap_extensions.flags.writeable = False
|
||||
Shape.lock(self)
|
||||
return self
|
||||
|
||||
def unlock(self) -> 'Path':
|
||||
Shape.unlock(self)
|
||||
self.vertices.flags.writeable = True
|
||||
if self.cap_extensions is not None:
|
||||
self.cap_extensions.flags.writeable = True
|
||||
return self
|
||||
|
||||
def __repr__(self) -> str:
|
||||
centroid = self.offset + self.vertices.mean(axis=0)
|
||||
dose = f' d{self.dose:g}' if self.dose != 1 else ''
|
||||
locked = ' L' if self.locked else ''
|
||||
return f'<Path l{self.layer} centroid {centroid} v{len(self.vertices)} w{self.width} c{self.cap}{dose}{locked}>'
|
||||
return f'<Path l{self.layer} centroid {centroid} v{len(self.vertices)} w{self.width} c{self.cap}{dose}>'
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ from .. import PatternError
|
|||
from ..repetition import Repetition
|
||||
from ..utils import is_scalar, rotation_matrix_2d, layer_t, AutoSlots
|
||||
from ..utils import remove_colinear_vertices, remove_duplicate_vertices, annotations_t
|
||||
from ..traits import LockableImpl
|
||||
|
||||
|
||||
class Polygon(Shape, metaclass=AutoSlots):
|
||||
|
|
@ -83,10 +82,8 @@ class Polygon(Shape, metaclass=AutoSlots):
|
|||
dose: float = 1.0,
|
||||
repetition: Optional[Repetition] = None,
|
||||
annotations: Optional[annotations_t] = None,
|
||||
locked: bool = False,
|
||||
raw: bool = False,
|
||||
) -> None:
|
||||
LockableImpl.unlock(self)
|
||||
self.identifier = ()
|
||||
if raw:
|
||||
assert(isinstance(vertices, numpy.ndarray))
|
||||
|
|
@ -106,16 +103,13 @@ class Polygon(Shape, metaclass=AutoSlots):
|
|||
self.dose = dose
|
||||
self.rotate(rotation)
|
||||
[self.mirror(a) for a, do in enumerate(mirrored) if do]
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Optional[Dict] = None) -> 'Polygon':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self)
|
||||
Shape.unlock(new)
|
||||
new._offset = self._offset.copy()
|
||||
new._vertices = self._vertices.copy()
|
||||
new._annotations = copy.deepcopy(self._annotations)
|
||||
new.set_locked(self.locked)
|
||||
return new
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -430,18 +424,7 @@ class Polygon(Shape, metaclass=AutoSlots):
|
|||
self.vertices = remove_colinear_vertices(self.vertices, closed_path=True)
|
||||
return self
|
||||
|
||||
def lock(self) -> 'Polygon':
|
||||
self.vertices.flags.writeable = False
|
||||
Shape.lock(self)
|
||||
return self
|
||||
|
||||
def unlock(self) -> 'Polygon':
|
||||
Shape.unlock(self)
|
||||
self.vertices.flags.writeable = True
|
||||
return self
|
||||
|
||||
def __repr__(self) -> str:
|
||||
centroid = self.offset + self.vertices.mean(axis=0)
|
||||
dose = f' d{self.dose:g}' if self.dose != 1 else ''
|
||||
locked = ' L' if self.locked else ''
|
||||
return f'<Polygon l{self.layer} centroid {centroid} v{len(self.vertices)}{dose}{locked}>'
|
||||
return f'<Polygon l{self.layer} centroid {centroid} v{len(self.vertices)}{dose}>'
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ from abc import ABCMeta, abstractmethod
|
|||
import numpy
|
||||
from numpy.typing import NDArray, ArrayLike
|
||||
|
||||
from ..traits import (PositionableImpl, LayerableImpl, DoseableImpl,
|
||||
Rotatable, Mirrorable, Copyable, Scalable,
|
||||
PivotableImpl, LockableImpl, RepeatableImpl,
|
||||
AnnotatableImpl)
|
||||
from ..traits import (
|
||||
PositionableImpl, LayerableImpl, DoseableImpl,
|
||||
Rotatable, Mirrorable, Copyable, Scalable,
|
||||
PivotableImpl, RepeatableImpl, AnnotatableImpl,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import Polygon
|
||||
|
|
@ -27,7 +28,7 @@ T = TypeVar('T', bound='Shape')
|
|||
|
||||
|
||||
class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable, Copyable, Scalable,
|
||||
PivotableImpl, RepeatableImpl, LockableImpl, AnnotatableImpl, metaclass=ABCMeta):
|
||||
PivotableImpl, RepeatableImpl, AnnotatableImpl, metaclass=ABCMeta):
|
||||
"""
|
||||
Abstract class specifying functions common to all shapes.
|
||||
"""
|
||||
|
|
@ -303,13 +304,3 @@ class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable
|
|||
dose=self.dose))
|
||||
|
||||
return manhattan_polygons
|
||||
|
||||
def lock(self: T) -> T:
|
||||
PositionableImpl._lock(self)
|
||||
LockableImpl.lock(self)
|
||||
return self
|
||||
|
||||
def unlock(self: T) -> T:
|
||||
LockableImpl.unlock(self)
|
||||
PositionableImpl._unlock(self)
|
||||
return self
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ from ..repetition import Repetition
|
|||
from ..traits import RotatableImpl
|
||||
from ..utils import is_scalar, get_bit, normalize_mirror, layer_t, AutoSlots
|
||||
from ..utils import annotations_t
|
||||
from ..traits import LockableImpl
|
||||
|
||||
# Loaded on use:
|
||||
# from freetype import Face
|
||||
|
|
@ -74,10 +73,8 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
|
|||
dose: float = 1.0,
|
||||
repetition: Optional[Repetition] = None,
|
||||
annotations: Optional[annotations_t] = None,
|
||||
locked: bool = False,
|
||||
raw: bool = False,
|
||||
) -> None:
|
||||
LockableImpl.unlock(self)
|
||||
self.identifier = ()
|
||||
if raw:
|
||||
assert(isinstance(offset, numpy.ndarray))
|
||||
|
|
@ -102,16 +99,13 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
|
|||
self.repetition = repetition
|
||||
self.annotations = annotations if annotations is not None else {}
|
||||
self.font_path = font_path
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Text':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self)
|
||||
Shape.unlock(new)
|
||||
new._offset = self._offset.copy()
|
||||
new._mirrored = copy.deepcopy(self._mirrored, memo)
|
||||
new._annotations = copy.deepcopy(self._annotations)
|
||||
new.set_locked(self.locked)
|
||||
return new
|
||||
|
||||
def to_polygons(
|
||||
|
|
@ -259,19 +253,8 @@ def get_char_as_polygons(
|
|||
|
||||
return polygons, advance
|
||||
|
||||
def lock(self) -> 'Text':
|
||||
self.mirrored.flags.writeable = False
|
||||
Shape.lock(self)
|
||||
return self
|
||||
|
||||
def unlock(self) -> 'Text':
|
||||
Shape.unlock(self)
|
||||
self.mirrored.flags.writeable = True
|
||||
return self
|
||||
|
||||
def __repr__(self) -> str:
|
||||
rotation = f' r°{self.rotation*180/pi:g}' if self.rotation != 0 else ''
|
||||
dose = f' d{self.dose:g}' if self.dose != 1 else ''
|
||||
locked = ' L' if self.locked else ''
|
||||
mirrored = ' m{:d}{:d}'.format(*self.mirrored) if self.mirrored.any() else ''
|
||||
return f'<TextShape "{self.string}" l{self.layer} o{self.offset} h{self.height:g}{rotation}{mirrored}{dose}{locked}>'
|
||||
return f'<TextShape "{self.string}" l{self.layer} o{self.offset} h{self.height:g}{rotation}{mirrored}{dose}>'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue