def assert_same_shape(sh1, sh2): precision = 3e-3 d12 = gdstk.boolean(sh1, gdstk.offset(sh2, precision, use_union=True), "not", precision, 255, 102) d21 = gdstk.boolean(sh2, gdstk.offset(sh1, precision, use_union=True), "not", precision, 255, 201) if len(d12) > 0 or len(d21) > 0: lib = gdstk.Library("Debug") cell = lib.new_cell("Debug") if hasattr(sh1, "__iter__"): cell.add(*sh1) else: cell.add(sh1) if hasattr(sh2, "__iter__"): cell.add(*sh2) else: cell.add(sh2) if len(d12) > 0: cell.add(*d12) if len(d21) > 0: cell.add(*d21) outfile = pathlib.Path(tempfile.gettempdir()) / "debug.gds" lib.write_gds(outfile) raise AssertionError("Shapes don't match. Debug library saved as %s" % outfile)
def render_text(text, size=None, position=(0, 0), font_prop=None, tolerance=0.1): tol = 0.1 * tolerance path = TextPath(position, text, size=size, prop=font_prop) polys = [] xmax = position[0] for points, code in path.iter_segments(): if code == path.MOVETO: c = gdstk.Curve(points, tolerance=tolerance) elif code == path.LINETO: c.segment(points.reshape(points.size // 2, 2)) elif code == path.CURVE3: c.quadratic(points.reshape(points.size // 2, 2)) elif code == path.CURVE4: c.cubic(points.reshape(points.size // 2, 2)) elif code == path.CLOSEPOLY: poly = c.points() if poly.size > 0: if poly[:, 0].min() < xmax: i = len(polys) - 1 while i >= 0: if gdstk.inside(poly[:1], [polys[i]], precision=tol)[0]: p = polys.pop(i) b = gdstk.boolean([p], [poly], "xor", tol) poly = b[0].points break elif gdstk.inside(polys[i][:1], [poly], precision=tol)[0]: p = polys.pop(i) b = gdstk.boolean([p], [poly], "xor", tol) poly = b[0].points i -= 1 xmax = max(xmax, poly[:, 0].max()) polys.append(poly) return polys
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 bench_gdstk(output=None): poly = gdstk.regular_polygon((0, 0), 1.5, 6, layer=1) orig = gdstk.Cell("OFF") orig.add(poly) ref = gdstk.Reference(orig, (-3, 5), columns=4, spacing=(2, 0)) off = gdstk.offset([poly, ref], 0.2, "bevel", layer=0) boo = gdstk.boolean(off, [poly, ref], "not", layer=2) if output: cell = gdstk.Cell("MAIN") cell.add(ref, poly, *off, *boo) cell.write_svg(output, 50)
def render_text(text, size=None, position=(0, 0), font_prop=None, tolerance=0.1): precision = 0.1 * tolerance path = TextPath(position, text, size=size, prop=font_prop) polys = [] xmax = position[0] for points, code in path.iter_segments(): if code == path.MOVETO: c = gdstk.Curve(points, tolerance=tolerance) elif code == path.LINETO: c.segment(points.reshape(points.size // 2, 2)) elif code == path.CURVE3: c.quadratic(points.reshape(points.size // 2, 2)) elif code == path.CURVE4: c.cubic(points.reshape(points.size // 2, 2)) elif code == path.CLOSEPOLY: pts = c.points() if pts.size > 0: poly = gdstk.Polygon(pts) if pts[:, 0].min() < xmax: i = len(polys) - 1 while i >= 0: if polys[i].contain_any(*poly.points): p = polys.pop(i) poly = gdstk.boolean(p, poly, "xor", precision)[0] break elif poly.contain_any(*polys[i].points): p = polys.pop(i) poly = gdstk.boolean(p, poly, "xor", precision)[0] i -= 1 xmax = max(xmax, poly.points[:, 0].max()) polys.append(poly) return polys
def main(filename, pixel_size, output): """Convert an image to a GDS file""" img = cv2.imread(filename, flags=cv2.IMREAD_GRAYSCALE) _, binaryImage = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY) binaryImage = cv2.flip( binaryImage, 0) # Flip image vertically since upper left corner is coordinate basis contours, hierarchy = cv2.findContours( binaryImage, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_TC89_KCOS) # Extract coordinates of contours hierarchy = np.squeeze(hierarchy) for i in range(len(contours)): contours[i] = np.squeeze(contours[i]).astype(float) * float( pixel_size) # Squeeze and correct dimensions lib = gdstk.Library() cell = gdstk.Cell("main") ld = {"layer": 0, "datatype": 1000} for i in np.where(hierarchy[:, 3] == -1)[0]: if hierarchy[i, 2] == -1 and len(contours[i]) > 2: cell.add(gdstk.Polygon(contours[i], **ld)) # Add a polygon without internals elif len(contours[i]) > 2 and hierarchy[i, 2] != -1: poly_p = gdstk.Polygon(contours[i], **ld) j = hierarchy[i, 2] while True: if len(contours[j]) > 2: poly_p = gdstk.boolean(poly_p, gdstk.Polygon(contours[j], **ld), "not", **ld) j = hierarchy[j, 0] if j == -1: break try: cell.add(*poly_p) except: cell.add(poly_p) lib.add(cell) lib.write_gds(output)
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") draw(gdstk.Cell("boolean_operations").add(*inv), path) # Slice Operation ring1 = gdstk.ellipse((-6, 0), 6, inner_radius=4) ring2 = gdstk.ellipse((0, 0), 6, inner_radius=4) ring3 = gdstk.ellipse((6, 0), 6, inner_radius=4) # Slice the first ring across x=-3, the second ring across x=-3 # and x=3, and the third ring across x=3 slices1 = gdstk.slice(ring1, -3, "x") slices2 = gdstk.slice(ring2, [-3, 3], "x") slices3 = gdstk.slice(ring3, 3, "x") slices = gdstk.Cell("SLICES")
import numpy import gdstk if __name__ == "__main__": # X-explicit repetition vline = gdstk.FlexPath([(3, 2), (3, 3.5)], 0.1, gdsii_path=True) vline.repetition = gdstk.Repetition(x_offsets=[0.2, 0.6, 1.4, 3.0]) # Y-explicit repetition hline = gdstk.RobustPath((3, 2), 0.05, gdsii_path=True) hline.segment((6, 2)) hline.repetition = gdstk.Repetition(y_offsets=[0.1, 0.3, 0.7, 1.5]) # Create all copies vlines = vline.apply_repetition() hlines = hline.apply_repetition() # Include original elements for boolean operation vlines.append(vline) hlines.append(hline) result = gdstk.boolean(vlines, hlines, "or") main = gdstk.Cell("Main") main.add(*result) main.name = "apply_repetition" path = pathlib.Path(__file__).parent.absolute() / "how-tos" path.mkdir(parents=True, exist_ok=True) draw(main, path)