snapshot 2019-04-20 13:34:52.427189

This commit is contained in:
Jan Petykiewicz 2019-04-20 13:34:52 -07:00
parent fa66e09f9b
commit bab12add10
5 changed files with 21 additions and 73 deletions

View File

@ -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,76 +272,23 @@ 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:
shape.clean_vertices() shape.clean_vertices()

View File

@ -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

View File

@ -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

View File

@ -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])

View File

@ -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,