def test_copy_transform(proof_cells): ref_cell1 = gdstk.Cell("Reference 1") ref_cell1.add(*gdstk.text("F.", 10, (0, 0))) ref_cell1.add(gdstk.Label("LaBeL", (2.4, 8.7), "s")) ref_cell1.add( gdstk.FlexPath(8 + 4j, 1, gdsii_path=True, layer=3).arc(2, 0, numpy.pi / 2) ) ref_cell1.add( gdstk.RobustPath(7.5 + 7j, 1, gdsii_path=True, layer=4).bezier( [-2 + 1j, -2 + 3j, 4j, 6j, -3 + 6j], relative=True ) ) ref_cell2 = gdstk.Cell("Reference 2") ref_cell2.add(*gdstk.text("^", 10, (0, 5), layer=1)) ref_cell2.add(gdstk.Reference(ref_cell1)) cell = gdstk.Cell("Original cell") cell.add(gdstk.rectangle((-1, -0.5), (1, 0.5), layer=2)) cell.add(gdstk.Reference(ref_cell2)) cell.add(gdstk.Reference(ref_cell1, (10, 7), numpy.pi / 4, 0.5, True)) cell.add( gdstk.Reference(ref_cell1, (-7, 15), -numpy.pi / 3, 0.5, True, 3, 2, (5, 4)) ) cell.add( gdstk.Reference(ref_cell2, (-7, 23), numpy.pi / 3, 0.5, True, 3, 2, (5, 8)) ) cell_copy = cell.copy("Cell.copy", (-10, -10), numpy.pi / 2, 2, True).flatten() for path in cell_copy.paths: cell_copy.add(*path.to_polygons()) assert_same_shape(proof_cells["Cell.copy"].polygons, cell_copy.polygons)
def convex_hull_image(): polygons = gdstk.text("F", 10, (0, 0)) f_cell = gdstk.Cell("F_CELL") f_cell.add(*polygons) array_ref = gdstk.Reference( f_cell, rotation=numpy.pi / 4, columns=3, rows=2, spacing=(8, 10) ) path = gdstk.FlexPath([(-5, 0), (0, -5), (5, 0)], 1, simple_path=True) main_cell = gdstk.Cell("MAIN") main_cell.add(array_ref, path) hull = main_cell.convex_hull() error = hull - numpy.array( [ [1.14904852, 27.66555281], [-12.81631041, 13.70019389], [-5.35355339, -0.35355339], [0.0, -5.70710678], [5.35355339, -0.35355339], [11.3137085, 13.96535893], [9.98788328, 17.94283457], [8.66205807, 20.15254326], ] ) assert numpy.abs(error).max() < 1e-8 polygon_hull = gdstk.Polygon(hull, datatype=1) main_cell.name = "convex_hull" return main_cell.add(polygon_hull)
def init_image(): polygons = gdstk.text("F", 10, (0, 0)) f_cell = gdstk.Cell("F_CELL") f_cell.add(*polygons) ref = gdstk.Reference(f_cell, rotation=numpy.pi / 2) array_ref = gdstk.Reference(f_cell, columns=3, rows=2, spacing=(8, 10)) return gdstk.Cell("init").add(ref, array_ref)
def boolean_image(): circle = gdstk.ellipse((0, 0), 50) path = gdstk.FlexPath((-50, 30), [5, 5], 10) path.interpolation([(20, 15), (0, 0), (-20, -15), (50, -30)], angles=[0.3, None, None, None, 0.3]) text = gdstk.text("GDSTK", 40, (-2.5 * 40 * 9 / 16, -40 / 2)) result = gdstk.boolean(circle, text + [path], "not") return gdstk.Cell("boolean").add(*result)
def make_second_lib(filename): lib = gdstk.Library("Second") main = lib.new_cell("Main") main.add(*gdstk.text("Second library", 10, (0, 0))) ref = lib.new_cell("Circle") ref.add(gdstk.ellipse((-10, 5), 5)) main.add(gdstk.Reference(ref)) lib.write_gds(filename)
def remove_image(): polygons = gdstk.text("Filter dots\nin i and j!", 8, (0, 0)) cell = gdstk.Cell("FILTERED") cell.add(*polygons) dots = [poly for poly in cell.polygons if poly.area() < 2] cell.remove(*dots) cell.name = "remove" return cell
def offset_image(): text = gdstk.text("#A", 10, (0, 0), datatype=1) circle = gdstk.ellipse( (5, 11), 5, initial_angle=0, final_angle=numpy.pi, datatype=1 ) path = gdstk.FlexPath([(0, -1), (5, -10), (10, -1)], 1, datatype=1) dilated = gdstk.offset(text + [circle, path], 0.4) eroded = gdstk.offset(text + [circle, path], -0.4, use_union=True, layer=1) return gdstk.Cell("offset").add(*text, circle, path, *dilated, *eroded)
def make_first_lib(filename): lib = gdstk.Library("First") main = lib.new_cell("Main") main.add(*gdstk.text("First library", 10, (0, 0))) ref1 = lib.new_cell("Square") ref1.add(gdstk.rectangle((-15, 0), (-5, 10))) main.add(gdstk.Reference(ref1)) ref2 = lib.new_cell("Circle") ref2.add(gdstk.ellipse((0, 0), 4)) ref1.add(gdstk.Reference(ref2, (-10, 5))) lib.write_gds(filename)
def bounding_box_image(): polygons = gdstk.text("F", 10, (0, 0)) f_cell = gdstk.Cell("F_CELL") f_cell.add(*polygons) array_ref = gdstk.Reference(f_cell, rotation=numpy.pi / 4, columns=3, rows=2, spacing=(8, 10)) bbox = array_ref.bounding_box() # print(bbox) polygon_bb = gdstk.rectangle(*bbox, datatype=1) return gdstk.Cell("bounding_box").add(array_ref, polygon_bb)
def test_gds_array(tmpdir): lib = gdstk.Library("Library") ref_cell = lib.new_cell("Base") ref_cell.add(*gdstk.text("F", 1, (0, 0))) for rect in (True, False): for cols in (1, 3): for rows in (1, 3): if cols * rows == 1: continue for dx in (-3, 0, 3): for dy in (-4, 0, 4): if rect: rep = gdstk.Repetition(columns=cols, rows=rows, spacing=(dx, dy)) else: rep = gdstk.Repetition(columns=cols, rows=rows, v1=(dx, 0), v2=(0, dy)) for rot in range(-3, 4): for refl in (True, False): cell = lib.new_cell( f"{'RECT' if rect else 'REGL'}" f"_{cols}_{rows}_{dx}_{dy}" f"_{rot}{'_X' if refl else ''}") ref = gdstk.Reference( ref_cell, (-0.5, -1), 0.5 * numpy.pi * rot, x_reflection=refl, ) ref.repetition = rep cell.add(ref) fname = str(tmpdir.join("aref_test.gds")) lib.write_gds(fname) lib2 = gdstk.read_gds(fname) cell_dict = {cell.name: cell for cell in lib.cells} for cell in lib2.cells: if len(cell.references) == 0: continue assert len(cell.references) == 1 assert cell.references[0].repetition.size > 1 assert cell.name in cell_dict polygons1 = cell_dict[cell.name].get_polygons() polygons2 = cell.get_polygons() assert len(polygons1) == len(polygons2) assert_same_shape(polygons1, polygons2)
def bounding_box_image(): polygons = gdstk.text("F", 10, (0, 0)) f_cell = gdstk.Cell("F_CELL") f_cell.add(*polygons) array_ref = gdstk.Reference(f_cell, rotation=numpy.pi / 4, columns=3, rows=2, spacing=(8, 10)) bbox = array_ref.bounding_box() assert bbox == ( (-12.816310409006173, 1.7677669529663689), (11.313708498984761, 27.66555281392367), ) polygon_bb = gdstk.rectangle(*bbox, datatype=1) return gdstk.Cell("bounding_box").add(array_ref, polygon_bb)
def bounding_box_image(): polygons = gdstk.text("F", 10, (0, 0)) f_cell = gdstk.Cell("F_CELL") f_cell.add(*polygons) array_ref = gdstk.Reference(f_cell, rotation=numpy.pi / 4, columns=3, rows=2, spacing=(8, 10)) path = gdstk.FlexPath([(-5, 0), (0, -5), (5, 0)], 1, gdsii_path=True) main_cell = gdstk.Cell("MAIN") main_cell.add(array_ref, path) bbox = main_cell.bounding_box() # print(bbox) polygon_bb = gdstk.rectangle(*bbox, datatype=1) main_cell.name = "bounding_box" return main_cell.add(polygon_bb)
def bounding_box_image(): polygons = gdstk.text("F", 10, (0, 0)) f_cell = gdstk.Cell("F_CELL") f_cell.add(*polygons) array_ref = gdstk.Reference( f_cell, rotation=numpy.pi / 4, columns=3, rows=2, spacing=(8, 10) ) path = gdstk.FlexPath([(-5, 0), (0, -5), (5, 0)], 1, simple_path=True) main_cell = gdstk.Cell("MAIN") main_cell.add(array_ref, path) bbox = main_cell.bounding_box() assert bbox == ( (-12.816310409006173, -5.707106781186548), (11.313708498984761, 27.66555281392367), ) polygon_bb = gdstk.rectangle(*bbox, datatype=1) main_cell.name = "bounding_box" return main_cell.add(polygon_bb)
def convex_hull_image(): polygons = gdstk.text("F", 10, (0, 0)) f_cell = gdstk.Cell("F_CELL") f_cell.add(*polygons) array_ref = gdstk.Reference(f_cell, rotation=numpy.pi / 4, columns=3, rows=2, spacing=(8, 10)) hull = array_ref.convex_hull() error = hull - numpy.array([ [1.14904852, 27.66555281], [-12.81631041, 13.70019389], [-0.88388348, 1.76776695], [11.3137085, 13.96535893], [9.98788328, 17.94283457], [8.66205807, 20.15254326], ]) assert numpy.abs(error).max() < 1e-8 polygon_hull = gdstk.Polygon(hull, datatype=1) return gdstk.Cell("convex_hull").add(array_ref, polygon_hull)
def make_proof_lib(): lib = gdstk.Library("Test Library", unit=1e-6, precision=1e-12) cell = lib.new_cell("Polygon.fillet") p1 = gdstk.Polygon([(0, 0), (1.2, 0), (1.2, 0.3), (1, 0.3), (1.5, 1), (0, 1.5)]) p2 = p1.copy().translate(2, 0) cell.add(p1.fillet(0.3, tolerance=1e-3)) cell.add(p2.fillet([0.3, 0, 0.1, 0, 0.5, 10], tolerance=1e-3)) for scale_width in [True, False]: cell = lib.new_cell(f"FlexPath: scale_width {scale_width}") path0 = gdstk.FlexPath( (0j, 1j, 0.5 + 1j), [0.1, 0.2], 0.3, tolerance=1e-4, scale_width=scale_width, ) path0.turn(0.4, -numpy.pi, [0.2, 0.1]).segment((-0.2, 0), relative=True) path1 = path0.copy().mirror((1.5, 0)) path1.set_layers(1, 1) path2 = path0.copy().mirror((1.5, 0), (1.5, 1)) path2.set_layers(2, 2) path3 = path0.copy().scale(2, (3, 0)) path3.set_layers(3, 3) path4 = path0.copy().scale(-2, (-1, 0)) path4.set_layers(4, 4) path5 = path0.copy().rotate(numpy.pi / 2, (2, 1)).translate(0.2, -0.3) path5.set_layers(5, 5) cell.add(path0, path1, path2, path3, path4, path5) for scale_width in [True, False]: cell = lib.new_cell(f"RobustPath: scale_width {scale_width}") path0 = gdstk.RobustPath( 0j, [0.1, 0.2], 0.3, tolerance=1e-4, scale_width=scale_width, ) path0.vertical(1).horizontal(0.5).turn(0.4, -numpy.pi, [0.2, 0.1]).segment( (-0.2, 0), relative=True) path1 = path0.copy().mirror((1.5, 0)) path1.set_layers(1, 1) path2 = path0.copy().mirror((1.5, 0), (1.5, 1)) path2.set_layers(2, 2) path3 = path0.copy().scale(2, (3, 0)) path3.set_layers(3, 3) path4 = path0.copy().scale(-2, (-1, 0)) path4.set_layers(4, 4) path5 = path0.copy().rotate(numpy.pi / 2, (2, 1)).translate(0.2, -0.3) path5.set_layers(5, 5) cell.add(path0, path1, path2, path3, path4, path5) ref_cell1 = gdstk.Cell("Reference 1") ref_cell1.add(*gdstk.text("F.", 10, (0, 0))) ref_cell1.add(gdstk.Label("LaBeL", (2.4, 8.7), "s")) ref_cell1.add(gdstk.FlexPath(8 + 4j, 1, layer=3).arc(2, 0, numpy.pi / 2)) ref_cell1.add( gdstk.RobustPath(7.5 + 7j, 1, layer=4).bezier([-2 + 1j, -2 + 3j, 4j, 6j, -3 + 6j], relative=True)) ref_cell2 = gdstk.Cell("Reference 2") ref_cell2.add(*gdstk.text("^", 10, (0, 5), layer=1)) ref_cell2.add(gdstk.Reference(ref_cell1)) cell = gdstk.Cell("Original cell") cell.add(gdstk.rectangle((-1, -0.5), (1, 0.5), layer=2)) cell.add(gdstk.Reference(ref_cell2)) cell.add(gdstk.Reference(ref_cell1, (10, 7), numpy.pi / 4, 0.5, True)) cell.add( gdstk.Reference(ref_cell1, (-7, 15), -numpy.pi / 3, 0.5, True, 3, 2, (5, 4))) cell.add( gdstk.Reference(ref_cell2, (-7, 23), numpy.pi / 3, 0.5, True, 3, 2, (5, 8))) cell_copy = cell.copy("Cell.copy", (-10, -10), numpy.pi / 2, 2, True).flatten() lib.add(cell_copy) gds_outfile = pathlib.Path(__file__).parent / "proof_lib.gds" if gds_outfile.exists(): print(f"Test library {str(gds_outfile)} already exists.") else: lib.write_gds(gds_outfile) print(f"Test library saved as {str(gds_outfile)}.") oas_outfile = pathlib.Path(__file__).parent / "proof_lib.oas" if oas_outfile.exists(): print(f"Test library {str(oas_outfile)} already exists.") else: lib.write_oas(oas_outfile) print(f"Test library saved as {str(oas_outfile)}.")
def text_image(): text = gdstk.text(f"Created with\nGDSTK {gdstk.__version__}", 1, (0, 0)) rect = gdstk.rectangle((0, -5 / 4), (5 * 9 / 16, -1 / 4), datatype=1) return gdstk.Cell("text").add(*text, rect)
lambda u: numpy.array((4 * numpy.sin(6 * numpy.pi * u), 45 * u)), offset=[ lambda u: -0.25 * numpy.cos(24 * numpy.pi * u), lambda u: 0.25 * numpy.cos(24 * numpy.pi * u), -0.75, 0.75, ], ) draw(gdstk.Cell("robust_paths").add(rp), path) # Text # Label centered at (1, 3) label = gdstk.Label("Sample label", (5, 3), texttype=2) # Horizontal text with height 2.25 htext = gdstk.text("12345", 2.25, (0.25, 6)) # Vertical text with height 1.5 vtext = gdstk.text("ABC", 1.5, (10.5, 4), vertical=True) rect = gdstk.rectangle((0, 0), (10, 6), layer=10) draw(gdstk.Cell("text").add(*htext, *vtext, label, rect), path) # Boolean Operations # Create some text text = gdstk.text("GDSTK", 4, (0, 0)) # Create a rectangle extending the text's bounding box by 1 rect = gdstk.rectangle((-1, -1), (5 * 4 * 9 / 16 + 1, 4 + 1)) # Subtract the text from the rectangle inv = gdstk.boolean(rect, text, "not")
rect = gdstk.rectangle((-r / 2, -r / 2), (r / 2, r / 2)) # Path for illustration path = gdstk.FlexPath( [(-n * d, 0), (n * d, 0)], r, ends=(r, r), gdsii_path=True, scale_width=False, layer=1, ) ressonator.add(rect, path, *patches) # Main output cell with the original resonator,… main = gdstk.Cell("Main") main.add(gdstk.Reference(ressonator)) main.add(*gdstk.text("Original", d, ((n + 1) * d, -d / 2))) # … a copy created by scaling a reference to the original resonator,… main.add( gdstk.Reference(ressonator, (0, (1 + s) * (n + 1) * d), magnification=s)) main.add(*gdstk.text("Reference\nscaling", d, (s * (n + 1) * d, (1 + s) * (n + 1) * d))) # … and another copy created by copying and scaling the Cell itself. ressonator_copy = ressonator.copy("Resonator Copy", magnification=s) main.add(gdstk.Reference(ressonator_copy, (0, (1 + 3 * s) * (n + 1) * d))) main.add(*gdstk.text("Cell copy\nscaling", d, (s * (n + 1) * d, (1 + 3 * s) * (n + 1) * d))) main.name = "transforms" path = pathlib.Path(__file__).parent.absolute() / "how-tos"
if __name__ == "__main__": path = pathlib.Path(__file__).parent.absolute() unit = gdstk.Cell("Unit") unit.add(gdstk.cross((0, 0), 1, 0.2)) main = gdstk.Cell("Main") # Create repeating pattern using references d = 2 ref1 = gdstk.Reference(unit, columns=11, rows=6, spacing=(d, d * 3**0.5)) ref2 = gdstk.Reference(unit, (d / 2, d * 3**0.5 / 2), columns=10, rows=5, spacing=(d, d * 3**0.5)) main.add(ref1, ref2) main.flatten() hole = gdstk.text("PY", 8 * d, (0.5 * d, 0), layer=1) test = gdstk.inside([pol.points for pol in main.polygons], hole, "any") for pol, inside in zip(main.polygons, test): if inside: main.remove(pol) main.add(*hole) gdstk.Library().add(main).write_gds(path / "pos_filtering.gds") main.name = "pos_filtering" draw(main, path / "how-tos")