From bab12add102641daa4e2bc5ebad6aec3ad73c679 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Sat, 20 Apr 2019 13:34:52 -0700 Subject: [PATCH] snapshot 2019-04-20 13:34:52.427189 --- masque/file/gdsii.py | 79 +++++++--------------------------------- masque/shapes/arc.py | 2 +- masque/shapes/ellipse.py | 2 +- masque/shapes/path.py | 7 ++-- masque/shapes/polygon.py | 4 +- 5 files changed, 21 insertions(+), 73 deletions(-) diff --git a/masque/file/gdsii.py b/masque/file/gdsii.py index cefb5eb..e7fa39f 100644 --- a/masque/file/gdsii.py +++ b/masque/file/gdsii.py @@ -15,7 +15,7 @@ import logging from .utils import mangle_name, make_dose_table 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 remove_colinear_vertices @@ -272,76 +272,23 @@ def read(filename: str, pat.shapes.append(shape) if isinstance(element, gdsii.elements.Path): - if element.path_type == 0: - #cap = Path.Cap.Flush - extension = 0.0 - elif element.path_type in (1, 4): - raise PatternError('Round-ended and custom paths (types 1 and 4) are not implemented yet') - elif element.path_type == 2: - extension = element.width / 2 + cap_map = {0: Path.Cap.Flush, + 1: Path.Cap.Circle, + 2: Path.Cap.Square, + #3: custom? + } + if element.path_type in cap_map: + cap = cap_map[element.path_type] else: 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: - shape = Polygon(vertices=verts, - dose=element.data_type, - layer=element.layer) + shape = Path(vertices=element.xy, + dose=element.data_type, + layer=element.layer) else: - shape = Polygon(vertices=verts, - layer=(element.layer, element.data_type)) + shape = Path(vertices=element.xy, + layer=(element.layer, element.data_type)) if clean_vertices: try: shape.clean_vertices() diff --git a/masque/shapes/arc.py b/masque/shapes/arc.py index d44a450..0daa93b 100644 --- a/masque/shapes/arc.py +++ b/masque/shapes/arc.py @@ -153,7 +153,7 @@ class Arc(Shape): self.width = width self.offset = offset 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.dose = dose self.poly_num_points = poly_num_points diff --git a/masque/shapes/ellipse.py b/masque/shapes/ellipse.py index 043d155..724c11d 100644 --- a/masque/shapes/ellipse.py +++ b/masque/shapes/ellipse.py @@ -92,7 +92,7 @@ class Ellipse(Shape): self.radii = radii self.offset = offset 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.dose = dose self.poly_num_points = poly_num_points diff --git a/masque/shapes/path.py b/masque/shapes/path.py index 511dcb6..b6d1687 100644 --- a/masque/shapes/path.py +++ b/masque/shapes/path.py @@ -127,7 +127,7 @@ class Path(Shape): self.width = width self.cap = cap 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 def travel(travel_pairs: Tuple[Tuple[float, float]], @@ -142,11 +142,12 @@ class Path(Shape): """ TODO - :param rotation: Rotation counterclockwise, in radians + :param offset: Offset, default (0, 0) + :param rotation: Rotation counterclockwise, in radians :param layer: Layer, default 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]) diff --git a/masque/shapes/polygon.py b/masque/shapes/polygon.py index c060990..eb1bdf8 100644 --- a/masque/shapes/polygon.py +++ b/masque/shapes/polygon.py @@ -1,4 +1,4 @@ -from typing import List +from typing import List, Tuple import copy import numpy from numpy import pi @@ -82,7 +82,7 @@ class Polygon(Shape): self.vertices = vertices self.offset = offset 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 def square(side_length: float,