Ejemplo n.º 1
0
def test_offset():
    gdspy.current_library = gdspy.GdsLibrary()
    r = gdspy.Rectangle((0, 0), (1, 2))
    result = gdspy.Rectangle((-1, -1), (2, 3))
    assert equals(gdspy.offset(r, 1), result)
    c = gdspy.Cell("OFFSET").add(r)
    ca = gdspy.CellArray(c, 2, 1, (1, 0))
    result = gdspy.Rectangle((0.2, 0.2), (1.8, 1.8))
    assert equals(gdspy.offset([ca], -0.2, join_first=True), result)
    v = [gdspy.Rectangle((-1, -1), (1, 1)), [(0, 0), (1, 0), (1, 1), (0, 1)]]
    x = 1 + 0.1 * numpy.tan(numpy.pi / 8)
    result = gdspy.Polygon(
        [
            (-1.1, -x),
            (-1.1, x),
            (-x, 1.1),
            (x, 1.1),
            (1.1, x),
            (1.1, -x),
            (x, -1.1),
            (-x, -1.1),
        ],
        layer=8,
    )
    assert equals(gdspy.offset(v, 0.1, join="bevel", layer=12), result)
Ejemplo n.º 2
0
def convert_to_positive_resist(cell, parts, buffer_radius=3):
    w_cut = 15
    l_cut = 15
    outer = gdspy.offset(parts, buffer_radius, join_first=True)
    diff = gdspy.boolean(outer, parts, 'not')

    x_max = 1
    x_min = 0
    if isinstance(parts, list):
        for onePart in parts:
            [[x_min_temp, __], [x_max_temp, __]] = onePart.get_bounding_box()
            if x_max_temp > x_max:
                x_max = x_max_temp
            if x_min_temp < x_min:
                x_min = x_min_temp
    else:
        [[x_min, __], [x_max, __]] = parts.get_bounding_box()
    points = [(x_min, w_cut), (x_min, -w_cut), (x_min - l_cut, -w_cut),
              (x_min - l_cut, w_cut)]
    poly1 = gdspy.Polygon(points)
    points = [(x_max, w_cut), (x_max, -w_cut), (x_max + l_cut, -w_cut),
              (x_max + l_cut, w_cut)]
    poly2 = gdspy.Polygon(points)
    cut = gdspy.boolean(poly1, poly2, 'or')
    diff = gdspy.boolean(diff, cut, 'not', layer=1, datatype=1)
    cell.add(diff)
Ejemplo n.º 3
0
def offset(
    elements,
    distance=0.1,
    join_first=True,
    precision=1e-4,
    num_divisions=[1, 1],
    join="miter",
    tolerance=2,
    max_points=4000,
    layer=0,
):
    """ returns an element containing all polygons with an offset
    from phidl geometry
    """
    if type(elements) is not list:
        elements = [elements]
    polygons_to_offset = []
    for e in elements:
        if isinstance(e, (Device, DeviceReference)):
            polygons_to_offset += e.get_polygons(by_spec=False)
        elif isinstance(e, (Polygon, gdspy.Polygon)):
            polygons_to_offset.append(e)
    if len(polygons_to_offset) == 0:
        return pp.Component("offset")
    polygons_to_offset = _merge_floating_point_errors(
        polygons_to_offset, tol=precision / 1000
    )
    gds_layer, gds_datatype = _parse_layer(layer)
    if all(np.array(num_divisions) == np.array([1, 1])):
        p = gdspy.offset(
            polygons_to_offset,
            distance=distance,
            join=join,
            tolerance=tolerance,
            precision=precision,
            join_first=join_first,
            max_points=max_points,
            layer=gds_layer,
            datatype=gds_datatype,
        )
    else:
        p = _offset_polygons_parallel(
            polygons_to_offset,
            distance=distance,
            num_divisions=num_divisions,
            join_first=join_first,
            precision=precision,
            join=join,
            tolerance=tolerance,
        )

    D = pp.Component("offset")
    polygons = D.add_polygon(p, layer=layer)
    [
        polygon.fracture(max_points=max_points, precision=precision)
        for polygon in polygons
    ]
    return D
Ejemplo n.º 4
0
    def draw_vias(cls, polygon, layer):
        """Fills ``polygon`` with vias according to appropriate rules.

        Returns list of gdspy geometries on ``layer``
        """ 
        polygon = gdspy.offset(polygon, -cls.min_properties[layer][2])
        return LibTools.via_fill_simple(
                                polygon.polygons[0],
                                cls.min_properties[layer][0],
                                cls.min_properties[layer][1],
                                layer)
Ejemplo n.º 5
0
def bench_gdspy(output=None):
    poly = gdspy.Round((0, 0), 1.5, number_of_points=6, layer=1)
    orig = gdspy.Cell("OFF", exclude_from_current=True)
    orig.add(poly)
    ref = gdspy.CellArray(orig, 4, 1, (2, 0), origin=(-3, 5))
    off = gdspy.offset([poly, ref], 0.2, "round", layer=0)
    boo = gdspy.boolean(off, [poly, ref], "not", layer=2)
    if output:
        cell = gdspy.Cell("MAIN", exclude_from_current=True)
        cell.add([ref, poly, off, boo])
        cell.write_svg(output, 50)
Ejemplo n.º 6
0
def assertsame(c1, c2, tolerance=1e-6):
    d1 = c1.get_polygons(by_spec=True)
    d2 = c2.get_polygons(by_spec=True)
    for key in d1:
        assert key in d2
        result = gdspy.boolean(d1[key],
                               d2[key],
                               "xor",
                               precision=1e-7,
                               layer=key[0],
                               datatype=100)
        if result is not None:
            r1 = gdspy.boolean(
                d1[key],
                gdspy.offset(d2[key], tolerance, precision=1e-7),
                "not",
                precision=1e-7,
                layer=key[0],
                datatype=99,
            )
            r2 = gdspy.boolean(
                d2[key],
                gdspy.offset(d1[key], tolerance, precision=1e-7),
                "not",
                precision=1e-7,
                layer=key[0],
                datatype=99,
            )
            # if not (r1 is None and r2 is None):
            #    c1.add(result)
            #    c2.add(result)
            #    if r1 is not None:
            #        c1.add(r1)
            #    if r2 is not None:
            #        c2.add(r2)
            #    gdspy.LayoutViewer(cells=[c1, c2])
            assert r1 is None
            assert r2 is None
        else:
            assert result is None
Ejemplo n.º 7
0
def buffer(parts, buffer_radius=3):
    w_cut = 15
    l_cut= 15
    outer = gdspy.offset(parts, buffer_radius, join_first=True)

    x_max = 1
    x_min = 0
    if isinstance(parts,list):
        for onePart in parts:
            [[x_min_temp, __], [x_max_temp, __]] = onePart.get_bounding_box()
            if x_max_temp > x_max:
                x_max = x_max_temp
            if x_min_temp < x_min:
                x_min = x_min_temp
    else:
        [[x_min, __], [x_max, __]] = parts.get_bounding_box()
    points = [(x_min, w_cut), (x_min, -w_cut), (x_min-l_cut, -w_cut), (x_min-l_cut, w_cut)]
    poly1 = gdspy.Polygon(points)
    points = [(x_max, w_cut), (x_max, -w_cut), (x_max+l_cut, -w_cut), (x_max+l_cut, w_cut)]
    poly2= gdspy.Polygon(points)
    cut = gdspy.boolean(poly1, poly2, 'or')
    outer2 = gdspy.boolean(outer, cut, 'not', **ld_cld)
    return outer2
Ejemplo n.º 8
0
    # Keep only the left side of slices1, the center part of slices2
    # and the right side of slices3
    slices.add(slices1[0])
    slices.add(slices2[1])
    slices.add(slices3[1])

    draw(slices, "slice_operation")

    # Offset Operation
    rect1 = gdspy.Rectangle((-4, -4), (1, 1))
    rect2 = gdspy.Rectangle((-1, -1), (4, 4))

    # Offset both polygons
    # Because we join them first, a single polygon is created.
    outer = gdspy.offset([rect1, rect2], 0.5, join_first=True, layer=1)
    draw(gdspy.Cell("offset_operation").add([outer, rect1, rect2]))

    # Fillet Operation
    multi_path = gdspy.Path(2, (-3, -2))
    multi_path.segment(4, "+x")
    multi_path.turn(2, "l").turn(2, "r")
    multi_path.segment(4)

    # Create a copy with joined polygons and no fracturing
    joined = gdspy.boolean(multi_path, None, "or", max_points=0)
    joined.translate(0, -5)

    # Fillet applied to each polygon in the path
    multi_path.fillet(0.5)
Ejemplo n.º 9
0
path_dc2.turn(radius_bend, 'r')
path_dc2.segment(l_DC)
path_dc2.turn(radius_bend, 'r')
path_dc2.segment(l_ver)
path_dc2.turn(radius_bend, 'l')
path_dc2.segment(l_heater)
path_dc2.turn(radius_bend, 'l')
path_dc2.segment(l_ver)
path_dc2.turn(radius_bend, 'r')
path_dc2.segment(l_DC)
path_dc2.turn(radius_bend, 'r')
path_dc2.segment(l_ver)
path_dc2.turn(radius_bend, 'l')
path_dc2.segment(l_PortOut)

path_dc_buffer = gdspy.offset([path_dc, path_dc2], 3, join_first=True)
path_positive = gdspy.boolean(path_dc_buffer, [path_dc, path_dc2], 'xor')

x0 = 0
point = [(x0, 20), (x0 - 20, 20), (x0 - 20, -1000), (x0, -1000)]
poly1 = gdspy.Polygon(point)
x0 = l_heater * 2 + 12 * radius_bend + l_PortIn + l_PortOut + 3 * l_DC + 20
point = [(x0, 20), (x0 - 20, 20), (x0 - 20, -1000), (x0, -1000)]
poly2 = gdspy.Polygon(point)

path_positive = gdspy.boolean(path_positive, [poly1, poly2],
                              'not',
                              layer=1,
                              datatype=1)

DC = lib.new_cell("DC")
Ejemplo n.º 10
0
    def __init__(self,
                 cell,
                 grid_size,
                 buffer=None,
                 layers=None,
                 precision=0.001):

        start_time = time.time()

        self.grid_size = grid_size
        if layers is None:
            layers = list(cell.get_layers())
        if not isinstance(layers, list):
            layers = [layers]
        if buffer is None:
            buffer = grid_size / 2

        bounding_box = cell.get_bounding_box()
        x_length = int(
            (bounding_box[1][0] - bounding_box[0][0] + 2 * grid_size) /
            grid_size) + 1
        y_length = int(
            (bounding_box[1][1] - bounding_box[0][1] + 2 * grid_size) /
            grid_size) + 1
        out_string = '-- Constructing map with ' + str(int(
            x_length * y_length)) + ' (' + str(int(x_length)) + ' x ' + str(
                int(y_length)) + ') entries'
        print(out_string, end=(7 - len(out_string) // 8) * '\t', flush=True)

        x_linspace = np.linspace(bounding_box[0][0] - grid_size,
                                 bounding_box[1][0] + grid_size, x_length)
        y_linspace = np.flip(
            np.linspace(bounding_box[0][1] - grid_size,
                        bounding_box[1][1] + grid_size, y_length))
        x_array, y_array = np.meshgrid(x_linspace, y_linspace)
        xy_array = np.array(list(zip(x_array.ravel(),
                                     y_array.ravel()))).reshape(
                                         *x_array.shape, 2)

        self.mask = np.zeros((y_length, x_length))

        self.copy_cell = cell.copy(cell.name + "_copy", deep_copy=True)
        self.copy_cell.remove_polygons(
            lambda pts, layer, datatype: layer not in layers)
        self.copy_polygonset = gp.offset(self.copy_cell.get_polygons(),
                                         distance=buffer)
        map_gdspy = np.array(
            gp.inside(np.array(xy_array).reshape(-1, 2),
                      self.copy_polygonset,
                      precision=precision)).reshape((y_length, x_length))

        for i in range(y_length):
            for j in range(x_length):
                if not map_gdspy[i][j]:
                    if self.mask[i][j] != 1:
                        self.mask[i][j] = 0
                else:
                    try:
                        self.mask[i][j] = self.mask[i - 1][j] = self.mask[
                            i + 1][j] = self.mask[i][j -
                                                     1] = self.mask[i][j +
                                                                       1] = 1
                    except:
                        pass

        elapsed_time = round(time.time() - start_time, 3)
        print('| Finished after ' + str(elapsed_time) + ' s --')

        self.x_length = x_length
        self.y_length = y_length
        self.x_linspace = x_linspace
        self.y_linspace = y_linspace
        self.x_array = x_array
        self.y_array = y_array
        self.xy_array = xy_array
Ejemplo n.º 11
0
                       layer=1))

# Polygon offset (inset and outset) can be used, for instance, to
# define safety margins around shapes.

spec = {'layer': 7}
path4 = gdspy.Path(0.5, (21, -5)).segment(3, '+x', **spec)\
        .turn(4, 'r', **spec).turn(4, 'rr', **spec)\
        .segment(3, **spec)
oper_cell.add(path4)

# Merge all parts into a single polygon.
merged = gdspy.fast_boolean(path4, None, 'or', max_points=0)

# Offset the path shape by 0.5 and add it to the cell.
oper_cell.add(gdspy.offset(merged, 1, layer=8))

# ------------------------------------------------------------------ #
#      SLICING POLYGONS
# ------------------------------------------------------------------ #

# If there is the need to cut a polygon or set of polygons, it's better
# to use the slice function than set up a boolean operation, since it
# runs much faster.  Slices are multiple cuts perpendicular to an axis.
slice_cell = gdspy.Cell('SLICE')
original = gdspy.Round((0, 0), 10, inner_radius=5)

# Slice the original ring along x = -7 and x = 7.
result = gdspy.slice(original, [-7, 7], 0, layer=1)

# The result is a tuple of polygon sets, one for each slice.  To keep
Ejemplo n.º 12
0
def makeBorder(conf: DefaultConfig, parts):
    return cut(gdspy.offset(parts, conf.borderWidth, layer=conf.borderLayer),
               parts)
Ejemplo n.º 13
0
def offset(
    elements: Component,
    distance: float = 0.1,
    join_first: bool = True,
    precision: float = 1e-4,
    num_divisions: Tuple[int, int] = (1, 1),
    join: str = "miter",
    tolerance: int = 2,
    max_points: int = 4000,
    layer: Layer = (1, 0),
) -> Component:
    """Returns an element containing all polygons with an offset
    Shrinks or expands a polygon or set of polygons.

    adapted from phidl.geometry

    Args:
        elements: Component(/Reference), list of Component(/Reference), or Polygon
          Polygons to offset or Component containing polygons to offset.
        distance: Distance to offset polygons. Positive values expand, negative shrink.
        precision: Desired precision for rounding vertex coordinates.
        num_divisions: The number of divisions with which the geometry is divided into
          multiple rectangular regions. This allows for each region to be
          processed sequentially, which is more computationally efficient.
        join: {'miter', 'bevel', 'round'} Type of join used to create polygon offset
        tolerance: For miter joints, this number must be at least 2 represents the
          maximal distance in multiples of offset between new vertices and their
          original position before beveling to avoid spikes at acute joints. For
          round joints, it indicates the curvature resolution in number of
          points per full circle.
        max_points: The maximum number of vertices within the resulting polygon.
        layer: Specific layer to put polygon geometry on.

    Returns
        Component containing a polygon(s) with the specified offset applied.

    """
    if not isinstance(elements, list):
        elements = [elements]
    polygons_to_offset = []
    for e in elements:
        if isinstance(e, (Device, DeviceReference)):
            polygons_to_offset += e.get_polygons(by_spec=False)
        elif isinstance(e, (Polygon, gdspy.Polygon)):
            polygons_to_offset.append(e)
    if len(polygons_to_offset) == 0:
        return gf.Component("offset")
    polygons_to_offset = _merge_floating_point_errors(
        polygons_to_offset, tol=precision / 1000
    )
    gds_layer, gds_datatype = _parse_layer(layer)
    if all(np.array(num_divisions) == np.array([1, 1])):
        p = gdspy.offset(
            polygons_to_offset,
            distance=distance,
            join=join,
            tolerance=tolerance,
            precision=precision,
            join_first=join_first,
            max_points=max_points,
            layer=gds_layer,
            datatype=gds_datatype,
        )
    else:
        p = _offset_polygons_parallel(
            polygons_to_offset,
            distance=distance,
            num_divisions=num_divisions,
            join_first=join_first,
            precision=precision,
            join=join,
            tolerance=tolerance,
        )

    component = gf.Component("offset")
    polygons = component.add_polygon(p, layer=layer)
    [
        polygon.fracture(max_points=max_points, precision=precision)
        for polygon in polygons
    ]
    return component
Ejemplo n.º 14
0
                                 'not', layer=1))

## Polygon offset (inset and outset) can be used, for instance, to
## define safety margins around shapes.

spec = {'layer': 7}
path4 = gdspy.Path(0.5, (21, -5)).segment(3, '+x', **spec)\
        .turn(4, 'r', **spec).turn(4, 'rr', **spec)\
        .segment(3, **spec)
oper_cell.add(path4)

## Merge all parts into a single polygon.
merged = gdspy.fast_boolean(path4, None, 'or', max_points=0)

## Offset the path shape by 0.5 and add it to the cell.
oper_cell.add(gdspy.offset(merged, 1, layer=8))


## ------------------------------------------------------------------ ##
##      SLICING POLYGONS
## ------------------------------------------------------------------ ##


## If there is the need to cut a polygon or set of polygons, it's better
## to use the slice function than set up a boolean operation, since it
## runs much faster.  Slices are multiple cuts perpendicular to an axis.
slice_cell = gdspy.Cell('SLICE')
original = gdspy.Round((0, 0), 10, inner_radius=5)

## Slice the original ring along x = -7 and x = 7.
result = gdspy.slice(original, [-7, 7], 0, layer=1)