snapshot 2019-04-20 13:34:52.427189
This commit is contained in:
parent
fa66e09f9b
commit
bab12add10
@ -15,7 +15,7 @@ import logging
|
|||||||
|
|
||||||
from .utils import mangle_name, make_dose_table
|
from .utils import mangle_name, make_dose_table
|
||||||
from .. import Pattern, SubPattern, GridRepetition, PatternError, Label, Shape
|
from .. import Pattern, SubPattern, GridRepetition, PatternError, Label, Shape
|
||||||
from ..shapes import Polygon
|
from ..shapes import Polygon, Path
|
||||||
from ..utils import rotation_matrix_2d, get_bit, set_bit, vector2, is_scalar
|
from ..utils import rotation_matrix_2d, get_bit, set_bit, vector2, is_scalar
|
||||||
from ..utils import remove_colinear_vertices
|
from ..utils import remove_colinear_vertices
|
||||||
|
|
||||||
@ -272,75 +272,22 @@ def read(filename: str,
|
|||||||
pat.shapes.append(shape)
|
pat.shapes.append(shape)
|
||||||
|
|
||||||
if isinstance(element, gdsii.elements.Path):
|
if isinstance(element, gdsii.elements.Path):
|
||||||
if element.path_type == 0:
|
cap_map = {0: Path.Cap.Flush,
|
||||||
#cap = Path.Cap.Flush
|
1: Path.Cap.Circle,
|
||||||
extension = 0.0
|
2: Path.Cap.Square,
|
||||||
elif element.path_type in (1, 4):
|
#3: custom?
|
||||||
raise PatternError('Round-ended and custom paths (types 1 and 4) are not implemented yet')
|
}
|
||||||
elif element.path_type == 2:
|
if element.path_type in cap_map:
|
||||||
extension = element.width / 2
|
cap = cap_map[element.path_type]
|
||||||
else:
|
else:
|
||||||
raise PatternError('Unrecognized path type: {}'.format(element.path_type))
|
raise PatternError('Unrecognized path type: {}'.format(element.path_type))
|
||||||
|
|
||||||
if element.width == 0:
|
|
||||||
continue
|
|
||||||
|
|
||||||
v = remove_colinear_vertices(numpy.array(element.xy, dtype=float), closed_path=False)
|
|
||||||
dv = numpy.diff(v, axis=0)
|
|
||||||
dvdir = dv / numpy.sqrt((dv * dv).sum(axis=1))[:, None]
|
|
||||||
perp = dvdir[:, ::-1] * [[1, -1]] * element.width / 2
|
|
||||||
|
|
||||||
# add extension
|
|
||||||
v[0] -= dvdir[0] * extension
|
|
||||||
v[-1] += dvdir[-1] * extension
|
|
||||||
|
|
||||||
# Find intersections of expanded sides
|
|
||||||
As = numpy.stack((dv[:-1], -dv[1:]), axis=2)
|
|
||||||
bs = v[1:-1] - v[:-2] + perp[1:] - perp[:-1]
|
|
||||||
ds = v[1:-1] - v[:-2] - perp[1:] + perp[:-1]
|
|
||||||
|
|
||||||
rp = numpy.linalg.solve(As, bs)[:, 0, None]
|
|
||||||
rn = numpy.linalg.solve(As, ds)[:, 0, None]
|
|
||||||
|
|
||||||
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?
|
|
||||||
|
|
||||||
|
|
||||||
o0 = [v[0] + perp[0]]
|
|
||||||
o1 = [v[0] - perp[0]]
|
|
||||||
for i in range(dv.shape[0] - 1):
|
|
||||||
if towards_perp[i]:
|
|
||||||
o0.append(intersection_p[i])
|
|
||||||
if acute[i]:
|
|
||||||
o1.append(intersection_n[i])
|
|
||||||
else:
|
|
||||||
# Opposite is >270
|
|
||||||
pt0 = v[i + 1] - perp[i + 0] + dvdir[i + 0] * element.width / 2
|
|
||||||
pt1 = v[i + 1] - perp[i + 1] - dvdir[i + 1] * element.width / 2
|
|
||||||
o1 += [pt0, pt1]
|
|
||||||
else:
|
|
||||||
o1.append(intersection_n[i])
|
|
||||||
if acute[i]:
|
|
||||||
# > 270
|
|
||||||
pt0 = v[i + 1] + perp[i + 0] + dvdir[i + 0] * element.width / 2
|
|
||||||
pt1 = v[i + 1] + perp[i + 1] - dvdir[i + 1] * element.width / 2
|
|
||||||
o0 += [pt0, pt1]
|
|
||||||
else:
|
|
||||||
o0.append(intersection_p[i])
|
|
||||||
o0.append(v[-1] + perp[-1])
|
|
||||||
o1.append(v[-1] - perp[-1])
|
|
||||||
verts = numpy.vstack((o0, o1[::-1]))
|
|
||||||
|
|
||||||
if use_dtype_as_dose:
|
if use_dtype_as_dose:
|
||||||
shape = Polygon(vertices=verts,
|
shape = Path(vertices=element.xy,
|
||||||
dose=element.data_type,
|
dose=element.data_type,
|
||||||
layer=element.layer)
|
layer=element.layer)
|
||||||
else:
|
else:
|
||||||
shape = Polygon(vertices=verts,
|
shape = Path(vertices=element.xy,
|
||||||
layer=(element.layer, element.data_type))
|
layer=(element.layer, element.data_type))
|
||||||
if clean_vertices:
|
if clean_vertices:
|
||||||
try:
|
try:
|
||||||
|
@ -153,7 +153,7 @@ class Arc(Shape):
|
|||||||
self.width = width
|
self.width = width
|
||||||
self.offset = offset
|
self.offset = offset
|
||||||
self.rotation = rotation
|
self.rotation = rotation
|
||||||
[self.mirror(a) for a in a, do in enumerate(mirrored) if do]
|
[self.mirror(a) for a, do in enumerate(mirrored) if do]
|
||||||
self.layer = layer
|
self.layer = layer
|
||||||
self.dose = dose
|
self.dose = dose
|
||||||
self.poly_num_points = poly_num_points
|
self.poly_num_points = poly_num_points
|
||||||
|
@ -92,7 +92,7 @@ class Ellipse(Shape):
|
|||||||
self.radii = radii
|
self.radii = radii
|
||||||
self.offset = offset
|
self.offset = offset
|
||||||
self.rotation = rotation
|
self.rotation = rotation
|
||||||
[self.mirror(a) for a in a, do in enumerate(mirrored) if do]
|
[self.mirror(a) for a, do in enumerate(mirrored) if do]
|
||||||
self.layer = layer
|
self.layer = layer
|
||||||
self.dose = dose
|
self.dose = dose
|
||||||
self.poly_num_points = poly_num_points
|
self.poly_num_points = poly_num_points
|
||||||
|
@ -127,7 +127,7 @@ class Path(Shape):
|
|||||||
self.width = width
|
self.width = width
|
||||||
self.cap = cap
|
self.cap = cap
|
||||||
self.rotate(rotation)
|
self.rotate(rotation)
|
||||||
[self.mirror(a) for a in a, do in enumerate(mirrored) if do]
|
[self.mirror(a) for a, do in enumerate(mirrored) if do]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def travel(travel_pairs: Tuple[Tuple[float, float]],
|
def travel(travel_pairs: Tuple[Tuple[float, float]],
|
||||||
@ -142,11 +142,12 @@ class Path(Shape):
|
|||||||
"""
|
"""
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
:param rotation: Rotation counterclockwise, in radians
|
|
||||||
:param offset: Offset, default (0, 0)
|
:param offset: Offset, default (0, 0)
|
||||||
|
:param rotation: Rotation counterclockwise, in radians
|
||||||
:param layer: Layer, default 0
|
:param layer: Layer, default 0
|
||||||
:param dose: Dose, default 1.0
|
:param dose: Dose, default 1.0
|
||||||
:return: A Polygon object containing the requested square
|
:return: The resulting Path object
|
||||||
"""
|
"""
|
||||||
direction = numpy.array([1, 0])
|
direction = numpy.array([1, 0])
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from typing import List
|
from typing import List, Tuple
|
||||||
import copy
|
import copy
|
||||||
import numpy
|
import numpy
|
||||||
from numpy import pi
|
from numpy import pi
|
||||||
@ -82,7 +82,7 @@ class Polygon(Shape):
|
|||||||
self.vertices = vertices
|
self.vertices = vertices
|
||||||
self.offset = offset
|
self.offset = offset
|
||||||
self.rotate(rotation)
|
self.rotate(rotation)
|
||||||
[self.mirror(a) for a in a, do in enumerate(mirrored) if do]
|
[self.mirror(a) for a, do in enumerate(mirrored) if do]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def square(side_length: float,
|
def square(side_length: float,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user