style and type fixes (per flake8)
could potentially fix some bugs in `Library` class and dxf reader
This commit is contained in:
parent
f6ad272c2c
commit
f364970403
31 changed files with 293 additions and 297 deletions
|
|
@ -1,4 +1,4 @@
|
|||
from typing import List, Tuple, Dict, Optional, Sequence
|
||||
from typing import List, Dict, Optional, Sequence
|
||||
import copy
|
||||
import math
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
|
||||
# arc start/stop angle properties
|
||||
@property
|
||||
def angles(self) -> numpy.ndarray: #ndarray[float]
|
||||
def angles(self) -> numpy.ndarray:
|
||||
"""
|
||||
Return the start and stop angles `[a_start, a_stop]`.
|
||||
Angles are measured from x-axis after rotation
|
||||
|
|
@ -194,7 +194,7 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
[self.mirror(a) for a, do in enumerate(mirrored) if do]
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Arc':
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Arc':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self).unlock()
|
||||
new._offset = self._offset.copy()
|
||||
|
|
@ -214,8 +214,8 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
poly_max_arclen = self.poly_max_arclen
|
||||
|
||||
if (poly_num_points is None) and (poly_max_arclen is None):
|
||||
raise PatternError('Max number of points and arclength left unspecified' +
|
||||
' (default was also overridden)')
|
||||
raise PatternError('Max number of points and arclength left unspecified'
|
||||
+ ' (default was also overridden)')
|
||||
|
||||
r0, r1 = self.radii
|
||||
|
||||
|
|
@ -273,7 +273,7 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
mins = []
|
||||
maxs = []
|
||||
for a, sgn in zip(a_ranges, (-1, +1)):
|
||||
wh = sgn * self.width/2
|
||||
wh = sgn * self.width / 2
|
||||
rx = self.radius_x + wh
|
||||
ry = self.radius_y + wh
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
|
||||
# Cutoff angles
|
||||
xpt = (-self.rotation) % (2 * pi) + a0_offset
|
||||
ypt = (pi/2 - self.rotation) % (2 * pi) + a0_offset
|
||||
ypt = (pi / 2 - self.rotation) % (2 * pi) + a0_offset
|
||||
xnt = (xpt - pi) % (2 * pi) + a0_offset
|
||||
ynt = (ypt - pi) % (2 * pi) + a0_offset
|
||||
|
||||
|
|
@ -356,9 +356,9 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
rotation %= 2 * pi
|
||||
width = self.width
|
||||
|
||||
return (type(self), radii, angles, width/norm_value, self.layer), \
|
||||
(self.offset, scale/norm_value, rotation, False, self.dose), \
|
||||
lambda: Arc(radii=radii*norm_value, angles=angles, width=width*norm_value, layer=self.layer)
|
||||
return ((type(self), radii, angles, width / norm_value, self.layer),
|
||||
(self.offset, scale / norm_value, rotation, False, self.dose),
|
||||
lambda: Arc(radii=radii * norm_value, angles=angles, width=width * norm_value, layer=self.layer))
|
||||
|
||||
def get_cap_edges(self) -> numpy.ndarray:
|
||||
'''
|
||||
|
|
@ -373,7 +373,7 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
mins = []
|
||||
maxs = []
|
||||
for a, sgn in zip(a_ranges, (-1, +1)):
|
||||
wh = sgn * self.width/2
|
||||
wh = sgn * self.width / 2
|
||||
rx = self.radius_x + wh
|
||||
ry = self.radius_y + wh
|
||||
|
||||
|
|
@ -388,7 +388,7 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
|
||||
mins.append([xn, yn])
|
||||
maxs.append([xp, yp])
|
||||
return numpy.array([mins, maxs]) + self.offset
|
||||
return numpy.array([mins, maxs]) + self.offset
|
||||
|
||||
def _angles_to_parameters(self) -> numpy.ndarray:
|
||||
'''
|
||||
|
|
@ -398,12 +398,12 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
'''
|
||||
a = []
|
||||
for sgn in (-1, +1):
|
||||
wh = sgn * self.width/2
|
||||
wh = sgn * self.width / 2
|
||||
rx = self.radius_x + wh
|
||||
ry = self.radius_y + wh
|
||||
|
||||
# create paremeter 'a' for parametrized ellipse
|
||||
a0, a1 = (numpy.arctan2(rx*numpy.sin(a), ry*numpy.cos(a)) for a in self.angles)
|
||||
a0, a1 = (numpy.arctan2(rx * numpy.sin(a), ry * numpy.cos(a)) for a in self.angles)
|
||||
sign = numpy.sign(self.angles[1] - self.angles[0])
|
||||
if sign != numpy.sign(a1 - a0):
|
||||
a1 += sign * 2 * pi
|
||||
|
|
@ -424,8 +424,8 @@ class Arc(Shape, metaclass=AutoSlots):
|
|||
return self
|
||||
|
||||
def __repr__(self) -> str:
|
||||
angles = f' a°{self.angles*180/pi}'
|
||||
rotation = f' r°{self.rotation*180/pi:g}' if self.rotation != 0 else ''
|
||||
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}>'
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ class Circle(Shape, metaclass=AutoSlots):
|
|||
self.poly_max_arclen = poly_max_arclen
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Circle':
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Circle':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self).unlock()
|
||||
new._offset = self._offset.copy()
|
||||
|
|
@ -127,9 +127,9 @@ class Circle(Shape, metaclass=AutoSlots):
|
|||
def normalized_form(self, norm_value) -> normalized_shape_tuple:
|
||||
rotation = 0.0
|
||||
magnitude = self.radius / norm_value
|
||||
return (type(self), self.layer), \
|
||||
(self.offset, magnitude, rotation, False, self.dose), \
|
||||
lambda: Circle(radius=norm_value, layer=self.layer)
|
||||
return ((type(self), self.layer),
|
||||
(self.offset, magnitude, rotation, False, self.dose),
|
||||
lambda: Circle(radius=norm_value, layer=self.layer))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
dose = f' d{self.dose:g}' if self.dose != 1 else ''
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import List, Tuple, Dict, Sequence, Optional
|
||||
from typing import List, Dict, Sequence, Optional
|
||||
import copy
|
||||
import math
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ class Ellipse(Shape, metaclass=AutoSlots):
|
|||
self.poly_max_arclen = poly_max_arclen
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Ellipse':
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Ellipse':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self).unlock()
|
||||
new._offset = self._offset.copy()
|
||||
|
|
@ -198,9 +198,9 @@ class Ellipse(Shape, metaclass=AutoSlots):
|
|||
radii = self.radii[::-1] / self.radius_y
|
||||
scale = self.radius_y
|
||||
angle = (self.rotation + pi / 2) % pi
|
||||
return (type(self), radii, self.layer), \
|
||||
(self.offset, scale/norm_value, angle, False, self.dose), \
|
||||
lambda: Ellipse(radii=radii*norm_value, layer=self.layer)
|
||||
return ((type(self), radii, self.layer),
|
||||
(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
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class PathCap(Enum):
|
|||
Circle = 1 # Path extends past final vertices with a semicircle of radius width/2
|
||||
Square = 2 # Path extends past final vertices with a width-by-width/2 rectangle
|
||||
SquareCustom = 4 # Path extends past final vertices with a rectangle of length
|
||||
# defined by path.cap_extensions
|
||||
# # defined by path.cap_extensions
|
||||
|
||||
|
||||
class Path(Shape, metaclass=AutoSlots):
|
||||
|
|
@ -103,7 +103,7 @@ class Path(Shape, metaclass=AutoSlots):
|
|||
|
||||
@vertices.setter
|
||||
def vertices(self, val: numpy.ndarray):
|
||||
val = numpy.array(val, dtype=float) #TODO document that these might not be copied
|
||||
val = numpy.array(val, dtype=float) # TODO document that these might not be copied
|
||||
if len(val.shape) < 2 or val.shape[1] != 2:
|
||||
raise PatternError('Vertices must be an Nx2 array')
|
||||
if val.shape[0] < 2:
|
||||
|
|
@ -184,7 +184,7 @@ class Path(Shape, metaclass=AutoSlots):
|
|||
[self.mirror(a) for a, do in enumerate(mirrored) if do]
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Path':
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Path':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self).unlock()
|
||||
new._offset = self._offset.copy()
|
||||
|
|
@ -199,7 +199,7 @@ class Path(Shape, metaclass=AutoSlots):
|
|||
def travel(travel_pairs: Tuple[Tuple[float, float]],
|
||||
width: float = 0.0,
|
||||
cap: PathCap = PathCap.Flush,
|
||||
cap_extensions = None,
|
||||
cap_extensions: Optional[Tuple[float, float]] = None,
|
||||
offset: vector2 = (0.0, 0.0),
|
||||
rotation: float = 0,
|
||||
mirrored: Sequence[bool] = (False, False),
|
||||
|
|
@ -275,9 +275,9 @@ class Path(Shape, metaclass=AutoSlots):
|
|||
intersection_p = v[:-2] + rp * dv[:-1] + perp[:-1]
|
||||
intersection_n = v[:-2] + rn * dv[:-1] - perp[:-1]
|
||||
|
||||
towards_perp = (dv[1:] * perp[:-1]).sum(axis=1) > 0 # path bends towards previous perp?
|
||||
# straight = (dv[1:] * perp[:-1]).sum(axis=1) == 0 # path is straight
|
||||
acute = (dv[1:] * dv[:-1]).sum(axis=1) < 0 # angle is acute?
|
||||
towards_perp = (dv[1:] * perp[:-1]).sum(axis=1) > 0 # path bends towards previous perp?
|
||||
# straight = (dv[1:] * perp[:-1]).sum(axis=1) == 0 # path is straight
|
||||
acute = (dv[1:] * dv[:-1]).sum(axis=1) < 0 # angle is acute?
|
||||
|
||||
# Build vertices
|
||||
o0 = [v[0] + perp[0]]
|
||||
|
|
@ -370,10 +370,10 @@ class Path(Shape, metaclass=AutoSlots):
|
|||
|
||||
width0 = self.width / norm_value
|
||||
|
||||
return (type(self), reordered_vertices.data.tobytes(), width0, self.cap, self.layer), \
|
||||
(offset, scale/norm_value, rotation, False, self.dose), \
|
||||
lambda: Path(reordered_vertices*norm_value, width=self.width*norm_value,
|
||||
cap=self.cap, layer=self.layer)
|
||||
return ((type(self), reordered_vertices.data.tobytes(), width0, self.cap, self.layer),
|
||||
(offset, scale / norm_value, rotation, False, self.dose),
|
||||
lambda: Path(reordered_vertices * norm_value, width=self.width * norm_value,
|
||||
cap=self.cap, layer=self.layer))
|
||||
|
||||
def clean_vertices(self) -> 'Path':
|
||||
"""
|
||||
|
|
@ -409,7 +409,7 @@ class Path(Shape, metaclass=AutoSlots):
|
|||
if self.cap == PathCap.Square:
|
||||
extensions = numpy.full(2, self.width / 2)
|
||||
elif self.cap == PathCap.SquareCustom:
|
||||
extensions = self.cap_extensions
|
||||
extensions = self.cap_extensions
|
||||
else:
|
||||
# Flush or Circle
|
||||
extensions = numpy.zeros(2)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import List, Tuple, Dict, Optional, Sequence
|
||||
from typing import List, Dict, Optional, Sequence
|
||||
import copy
|
||||
|
||||
import numpy # type: ignore
|
||||
|
|
@ -34,7 +34,7 @@ class Polygon(Shape, metaclass=AutoSlots):
|
|||
|
||||
@vertices.setter
|
||||
def vertices(self, val: numpy.ndarray):
|
||||
val = numpy.array(val, dtype=float) #TODO document that these might not be copied
|
||||
val = numpy.array(val, dtype=float) # TODO document that these might not be copied
|
||||
if len(val.shape) < 2 or val.shape[1] != 2:
|
||||
raise PatternError('Vertices must be an Nx2 array')
|
||||
if val.shape[0] < 3:
|
||||
|
|
@ -104,7 +104,7 @@ class Polygon(Shape, metaclass=AutoSlots):
|
|||
[self.mirror(a) for a, do in enumerate(mirrored) if do]
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Optional[Dict] = None) -> 'Polygon':
|
||||
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()
|
||||
|
|
@ -269,7 +269,6 @@ class Polygon(Shape, metaclass=AutoSlots):
|
|||
layer=layer, dose=dose)
|
||||
return poly
|
||||
|
||||
|
||||
def to_polygons(self,
|
||||
poly_num_points: int = None, # unused
|
||||
poly_max_arclen: float = None, # unused
|
||||
|
|
@ -316,9 +315,9 @@ class Polygon(Shape, metaclass=AutoSlots):
|
|||
|
||||
# TODO: normalize mirroring?
|
||||
|
||||
return (type(self), reordered_vertices.data.tobytes(), self.layer), \
|
||||
(offset, scale/norm_value, rotation, False, self.dose), \
|
||||
lambda: Polygon(reordered_vertices*norm_value, layer=self.layer)
|
||||
return ((type(self), reordered_vertices.data.tobytes(), self.layer),
|
||||
(offset, scale / norm_value, rotation, False, self.dose),
|
||||
lambda: Polygon(reordered_vertices * norm_value, layer=self.layer))
|
||||
|
||||
def clean_vertices(self) -> 'Polygon':
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
from typing import List, Tuple, Callable, TypeVar, Optional, TYPE_CHECKING
|
||||
from abc import ABCMeta, abstractmethod
|
||||
import copy
|
||||
|
||||
import numpy # type: ignore
|
||||
|
||||
from ..error import PatternError, PatternLockedError
|
||||
from ..utils import rotation_matrix_2d, vector2, layer_t
|
||||
from ..traits import (PositionableImpl, LayerableImpl, DoseableImpl,
|
||||
Rotatable, Mirrorable, Copyable, Scalable,
|
||||
PivotableImpl, LockableImpl, RepeatableImpl,
|
||||
|
|
@ -142,7 +139,6 @@ class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable
|
|||
if err_xmax >= 0.5:
|
||||
gxi_max += 1
|
||||
|
||||
|
||||
if abs(dv[0]) < 1e-20:
|
||||
# Vertical line, don't calculate slope
|
||||
xi = [gxi_min, gxi_max - 1]
|
||||
|
|
@ -155,8 +151,9 @@ class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable
|
|||
vertex_lists.append(segment)
|
||||
continue
|
||||
|
||||
m = dv[1]/dv[0]
|
||||
def get_grid_inds(xes):
|
||||
m = dv[1] / dv[0]
|
||||
|
||||
def get_grid_inds(xes: numpy.ndarray) -> numpy.ndarray:
|
||||
ys = m * (xes - v[0]) + v[1]
|
||||
|
||||
# (inds - 1) is the index of the y-grid line below the edge's intersection with the x-grid
|
||||
|
|
@ -178,7 +175,7 @@ class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable
|
|||
xs2 = (xs[:-1] + xs[1:]) / 2
|
||||
inds2 = get_grid_inds(xs2)
|
||||
|
||||
xinds = numpy.round(numpy.arange(gxi_min, gxi_max - 0.99, 1/3)).astype(int)
|
||||
xinds = numpy.round(numpy.arange(gxi_min, gxi_max - 0.99, 1 / 3)).astype(int)
|
||||
|
||||
# interleave the results
|
||||
yinds = xinds.copy()
|
||||
|
|
@ -202,7 +199,6 @@ class Shape(PositionableImpl, LayerableImpl, DoseableImpl, Rotatable, Mirrorable
|
|||
|
||||
return manhattan_polygons
|
||||
|
||||
|
||||
def manhattanize(self,
|
||||
grid_x: numpy.ndarray,
|
||||
grid_y: numpy.ndarray
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import List, Tuple, Dict, Sequence, Optional, MutableSequence
|
||||
from typing import List, Tuple, Dict, Sequence, Optional
|
||||
import copy
|
||||
|
||||
import numpy # type: ignore
|
||||
|
|
@ -26,7 +26,7 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
|
|||
|
||||
_string: str
|
||||
_height: float
|
||||
_mirrored: numpy.ndarray #ndarray[bool]
|
||||
_mirrored: numpy.ndarray # ndarray[bool]
|
||||
font_path: str
|
||||
|
||||
# vertices property
|
||||
|
|
@ -51,7 +51,7 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
|
|||
|
||||
# Mirrored property
|
||||
@property
|
||||
def mirrored(self) -> numpy.ndarray: #ndarray[bool]
|
||||
def mirrored(self) -> numpy.ndarray: # ndarray[bool]
|
||||
return self._mirrored
|
||||
|
||||
@mirrored.setter
|
||||
|
|
@ -100,7 +100,7 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
|
|||
self.font_path = font_path
|
||||
self.set_locked(locked)
|
||||
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Text':
|
||||
def __deepcopy__(self, memo: Dict = None) -> 'Text':
|
||||
memo = {} if memo is None else memo
|
||||
new = copy.copy(self).unlock()
|
||||
new._offset = self._offset.copy()
|
||||
|
|
@ -144,14 +144,14 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
|
|||
mirror_x, rotation = normalize_mirror(self.mirrored)
|
||||
rotation += self.rotation
|
||||
rotation %= 2 * pi
|
||||
return (type(self), self.string, self.font_path, self.layer), \
|
||||
(self.offset, self.height / norm_value, rotation, mirror_x, self.dose), \
|
||||
lambda: Text(string=self.string,
|
||||
height=self.height * norm_value,
|
||||
font_path=self.font_path,
|
||||
rotation=rotation,
|
||||
mirrored=(mirror_x, False),
|
||||
layer=self.layer)
|
||||
return ((type(self), self.string, self.font_path, self.layer),
|
||||
(self.offset, self.height / norm_value, rotation, mirror_x, self.dose),
|
||||
lambda: Text(string=self.string,
|
||||
height=self.height * norm_value,
|
||||
font_path=self.font_path,
|
||||
rotation=rotation,
|
||||
mirrored=(mirror_x, False),
|
||||
layer=self.layer))
|
||||
|
||||
def get_bounds(self) -> numpy.ndarray:
|
||||
# rotation makes this a huge pain when using slot.advance and glyph.bbox(), so
|
||||
|
|
@ -168,7 +168,7 @@ class Text(RotatableImpl, Shape, metaclass=AutoSlots):
|
|||
|
||||
def get_char_as_polygons(font_path: str,
|
||||
char: str,
|
||||
resolution: float = 48*64,
|
||||
resolution: float = 48 * 64,
|
||||
) -> Tuple[List[List[List[float]]], float]:
|
||||
from freetype import Face # type: ignore
|
||||
from matplotlib.path import Path # type: ignore
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue