示例#1
0
def boolean(
    A: Component,
    B: Component,
    operation: str,
    precision: float = 1e-4,
    num_divisions: List[int] = [1, 1],
    max_points: int = 4000,
    layer: ListConfig = 0,
) -> Component:
    """
    Performs boolean operations between 2 Device/DeviceReference objects,
    or lists of Devices/DeviceReferences.

    ``operation`` should be one of {'not', 'and', 'or', 'xor', 'A-B', 'B-A', 'A+B'}.
    Note that 'A+B' is equivalent to 'or', 'A-B' is equivalent to 'not', and
    'B-A' is equivalent to 'not' with the operands switched
    """
    c = pg.boolean(
        A=A,
        B=B,
        operation=operation,
        precision=precision,
        num_divisions=num_divisions,
        max_points=max_points,
        layer=layer,
    )
    return import_phidl_component(component=c)
def chip(size=(13000, 18000),
         keepout=2000,
         name='chip01',
         text_size=250,
         layer_text=10,
         layer=99):
    k = keepout
    DX = size[0]
    DY = size[1]
    OUT = pg.rectangle(size=size, layer=layer)
    IN = pg.rectangle(size=(DX - 2 * k, DY - 2 * k), layer=layer)
    IN.move((k, k))

    CHIP = pg.boolean(A=OUT, B=IN, operation='A-B', layer=layer)

    #Add name
    L = pg.text(text=name, size=text_size, layer=1, justify='center')
    CHIP.add_ref(L).move((DX / 2, k - text_size - 200))

    #Add markers
    M = global_markers()
    offset = 110
    CHIP.add_ref(M).move([k - offset, k - offset])
    CHIP.add_ref(M).move([DX - k + offset - 3000, k - offset])
    CHIP.add_ref(M).move([k - offset, DY - k + offset])
    CHIP.add_ref(M).move([DX - k + offset - 3000, DY - k + offset])

    return CHIP
示例#3
0
    def invert(self, layer, padding=None):
        """Inverts a pattern from positive to negative or vice versa.

        Parameters
        ----------
        layer: string
            Layer of new, inverted device.
        padding: np.array
            Array containing padding of bounding box used to substract device
            [left, right, top, bottom]
        """
        bounding_box = Device('interim_bounding_box')

        if padding is None:
            padding = [0, 0, 0, 0]

        bounding_box.add_polygon(
            [(self.xmin - padding[0], self.ymin - padding[3]),
             (self.xmin - padding[0], self.ymax + padding[2]),
             (self.xmax + padding[1], self.ymax + padding[2]),
             (self.xmax + padding[1], self.ymin - padding[3])],
            layer=layer)

        # perform substraction for positive e-beam resist
        inverse = pg.boolean(A=bounding_box,
                             B=self,
                             operation='A-B',
                             layer=layer)

        return inverse
def contact_pads(size=(150, 150), label='', label_size=50, layer=10):
    # P = Device('Pad')
    R = pg.rectangle(size, layer)
    if label != '':
        L = pg.text(label, label_size, layer=layer)
        L.move([10, 10])
        P = pg.boolean(A=R, B=L, operation='A-B', layer=layer)
    else:
        P = R
    return P
示例#5
0
def boolean(
        A: Union[ComponentOrReference, Tuple[ComponentOrReference, ...]],
        B: Union[ComponentOrReference, Tuple[ComponentOrReference, ...]],
        operation: str,
        precision: float = 1e-4,
        num_divisions: Union[int, Int2] = (1, 1),
        max_points: int = 4000,
        layer: Layer = (1, 0),
) -> Component:
    """Performs boolean operations between 2 Component/Reference objects,
    or lists of Devices/DeviceReferences.

    ``operation`` should be one of {'not', 'and', 'or', 'xor', 'A-B', 'B-A', 'A+B'}.
    Note that 'A+B' is equivalent to 'or', 'A-B' is equivalent to 'not', and
    'B-A' is equivalent to 'not' with the operands switched

    gdsfactory wrapper for phidl.geometry.boolean

    You can also use gdsfactory.drc.boolean that uses Klayout backend

    Args:
        A: Component(/Reference) or list of Component(/References)
        B: Component(/Reference) or list of Component(/References)
        operation: {'not', 'and', 'or', 'xor', 'A-B', 'B-A', 'A+B'}
        precision: float Desired precision for rounding vertex coordinates.
        num_divisions: 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.
        max_points: The maximum number of vertices within the resulting polygon.
        layer: Specific layer to put polygon geometry on.

    Returns: Component with polygon(s) of the boolean operations between
      the 2 input Devices performed.

    Notes
    -----
    'A+B' is equivalent to 'or'.
    'A-B' is equivalent to 'not'.
    'B-A' is equivalent to 'not' with the operands switched.
    """

    A = list(A) if isinstance(A, tuple) else A
    B = list(B) if isinstance(B, tuple) else B

    c = pg.boolean(
        A=A,
        B=B,
        operation=operation,
        precision=precision,
        num_divisions=num_divisions,
        max_points=max_points,
        layer=layer,
    )
    return gf.read.from_phidl(component=c)
示例#6
0
def boolean(
    A: Component,
    B: Component,
    operation: str,
    precision: float = 1e-4,
    num_divisions: Optional[int] = None,
    max_points: int = 4000,
    layer: ListConfig = 0,
) -> Component:
    """Performs boolean operations between 2 Device/DeviceReference objects,
    or lists of Devices/DeviceReferences.

    ``operation`` should be one of {'not', 'and', 'or', 'xor', 'A-B', 'B-A', 'A+B'}.
    Note that 'A+B' is equivalent to 'or', 'A-B' is equivalent to 'not', and
    'B-A' is equivalent to 'not' with the operands switched

    Args:
        A : Device(/Reference) or list of Device(/Reference) or Polygon Input Devices.
        B : Device(/Reference) or list of Device(/Reference) or Polygon Input Devices.
        operation : {'not', 'and', 'or', 'xor', 'A-B', 'B-A', 'A+B'} Boolean operation to perform.
        precision : float Desired precision for rounding vertex coordinates.
        num_divisions : array-like[2] of int
            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.
        max_points :
            The maximum number of vertices within the resulting polygon.
        layer : int, array-like[2], or set
            Specific layer(s) to put polygon geometry on.

    Returns:  Device
        A Device containing a polygon(s) with the boolean operations between
        the 2 input Devices performed.

    Notes
    -----
    'A+B' is equivalent to 'or'.
    'A-B' is equivalent to 'not'.
    'B-A' is equivalent to 'not' with the operands switched.
    """
    num_divisions = num_divisions or [1, 1]
    c = pg.boolean(
        A=A,
        B=B,
        operation=operation,
        precision=precision,
        num_divisions=num_divisions,
        max_points=max_points,
        layer=layer,
    )
    return import_phidl_component(component=c)
示例#7
0
def add_passivation(cell, margin, scale, layer):

    rect = pg.rectangle(size=(cell.xsize * scale.x, cell.ysize * scale.y))

    margin_rect = pg.rectangle(size=(margin.x * cell.xsize,
                                     margin.y * cell.ysize))

    rect.move(origin=rect.center, destination=cell.center)

    margin_rect.move(origin=margin_rect.center, destination=cell.center)

    pa = pg.boolean(rect, margin_rect, operation='xor')

    for l in layer:

        cell.add_polygon(pa.get_polygons(), layer=(l, 0))
#==============================================================================
# Making boolean shapes
#==============================================================================
# If you want to subtract one shape from another, merge two shapes, or
# perform an XOR on them, you can do that with the pg.boolean() function.
# the ``operation`` argument should be {not, and, or, xor, 'A-B', 'B-A', 'A+B'}.
# Note that 'A+B' is equivalent to 'or', 'A-B' is equivalent to 'not', and
#  'B-A' is equivalent to 'not' with the operands switched

D = Device()
E1 = pg.ellipse()
E2 = pg.ellipse().movex(15)
E3 = pg.ellipse().movex(30)
qp([E1, E2, E3])

D2 = pg.boolean(A=[E1, E3], B=E2, operation='A-B')
qp(D2)

#==============================================================================
# Creating outlines of shapes
#==============================================================================
# Sometimes, when writing in a positive-tone resist, it is useful to produce
# an outline of an existing shape. The pg.outline() function allows you to do
# exactly that

D = pg.ellipse(layer=1)
D2 = pg.outline(D, distance=1, layer=2)
qp([D, D2])

#==============================================================================
# Joining (Unioning) shapes together
示例#9
0
import phidl.geometry as pg
from phidl import quickplot as qp

E = pg.ellipse(radii = (10,5))
D = pg.invert(E, border = 0.5, precision = 1e-6, layer = 0)
qp(D) # quickplot the geometry
create_image(D, 'invert')

# example-boolean
import phidl.geometry as pg
from phidl import quickplot as qp
from phidl import Device

E = pg.ellipse(radii = (10,5), layer = 1)
R = pg.rectangle(size = [15,5], layer = 2).movey(-1.5)
C = pg.boolean(A = E, B = R, operation = 'not', precision = 1e-6, num_divisions = [1,1], layer = 0)
# Other operations include 'and', 'or', 'xor', or equivalently 'A-B', 'B-A', 'A+B'

# Plot the originals and the result
D = Device()
D.add_ref(E)
D.add_ref(R)
D.add_ref(C).movex(30)
qp(D) # quickplot the geometry
create_image(D, 'boolean')

# example-outline
import phidl.geometry as pg
from phidl import quickplot as qp
from phidl import Device
示例#10
0
def verniers(scale=[1, 0.5, 0.1],
             layers=[1, 2],
             label='TE',
             text_size=20,
             reversed=False):
    """ Create a cell with vernier aligners.

    Parameters
    ----------
        scale : iterable of float (default [1,0.5,0.25])
            each float in list is the offset of a vernier.
            for each of them a vernier will be created in the X-Y axis

        layers : 2-len iterable of int (default [1,2])
            define the two layers for the verniers.

        label : str (default "TE")

            add a label to the set of verniers.

        text_size : float (default)

            label size

        reversed : boolean

            if true, creates a negative alignment mark for the second layer

    Returns
    -------
        cell : phidl.Device.
    """

    cell = dl.Device(name="verniers")

    import numpy

    if not isinstance(scale, numpy.ndarray):

        scale = np.array(scale)

    scale = np.sort(scale)

    xvern = []

    for dim in scale:

        notch_size = [dim * 5, dim * 25]
        notch_spacing = dim * 10
        num_notches = 5
        notch_offset = dim
        row_spacing = 0
        layer1 = layers[0]
        layer2 = layers[1]

        cal=pg.litho_calipers(\
            notch_size,\
            notch_spacing,\
            num_notches,\
            notch_offset,\
            row_spacing,\
            layer1,\
            layer2)

        cal.flatten()

        if reversed:

            tobedel = cal.get_polygons(by_spec=(layer2, 0))

            cal = cal.remove_polygons(
                lambda pts, layer, datatype: layer == layer2)

            replica = dl.Device()

            replica.add(gdspy.PolygonSet(tobedel, layer=layer2))

            frame = dl.Device()

            frame.add(pg.bbox(replica.bbox, layer=layer2))

            frame_ext = dl.Device()

            frame_ext.add(
                gdspy.PolygonSet(frame.copy('tmp', scale=1.5).get_polygons(),
                                 layer=layer2))

            frame_ext.flatten()

            frame_ext.move(origin=frame_ext.center, destination=replica.center)

            new_cal = pg.boolean(replica, frame_ext, 'xor', layer=layer2)

            new_cal.rotate(angle=180,
                           center=(cal.xmin + cal.xsize / 2, cal.ymin))

            new_cal.move(destination=(0, -notch_size[1]))

            cal << new_cal

            cal.flatten()

        xvern.append(cal)

    g = dl.Group(xvern)

    g.distribute(direction='y', spacing=scale[-1] * 20)
    g.align(alignment='x')
    xcell = dl.Device(name="x")

    for x in xvern:

        xcell << x

    xcell = pt.join(xcell)

    vern_x = cell << xcell
    vern_y = cell << xcell

    vern_y.rotate(angle=-90)
    vern_y.move(origin=(vern_y.xmin,vern_y.y),\
        destination=(vern_x.x+scale[-1]*10,vern_x.ymin-scale[-1]*10))

    cell.absorb(vern_x)
    cell.absorb(vern_y)

    label = pg.text(text=label, size=text_size, layer=layers[0])

    label.move(destination=(cell.xmax - label.xsize / 2,
                            cell.ymax - 2 * label.ysize))

    overlabel = pg.bbox(label.bbox, layer=layers[1])

    overlabel_scaled = dl.Device().add(
        gdspy.PolygonSet(overlabel.copy('tmp', scale=2).get_polygons(),
                         layer=layers[1]))

    overlabel_scaled.move(origin=overlabel_scaled.center,\
        destination=label.center)

    cutlab = pg.boolean(label, overlabel_scaled, 'xor', layer=layers[1])

    cell << label
    cell << cutlab

    cell = pt.join(cell)

    return cell
示例#11
0
def test_boolean():
    A = pg.cross(length=10, width=3, layer=0)
    B = pg.ellipse(radii=(10, 5), angle_resolution=2.5, layer=1)
    D = pg.boolean(A=A, B=B, operation='and', precision=1e-6, layer=2)
    h = D.hash_geometry(precision=1e-4)
    assert (h == 'fcf1d0809488be01480027a5914dfb399faf088c')