Esempio n. 1
0
    def _draw_frame(self):

        rect = pg.bbox(self.clearance, layer=self.layer)
        rect.add_port(self.source)
        rect.add_port(self.destination)
        rect.name = self.name + "frame"

        return rect
Esempio n. 2
0
def add_vias(cell: Device,
             bbox,
             via: pt.LayoutPart,
             spacing: float = 0,
             tolerance: float = 0):
    ''' adds via pattern to cell with constraints.

    Parameters:
    -----------

    cell : Device
        where the vias will be located

    bbox : iterable
        x,y coordinates of box ll and ur to define vias patterns size

    via : pt.LayoutPart

    spacing : float

    tolerance : float (default 0)
        if not 0, used to determine via distance from target object border

    Returns:
    --------
    cell_out : Device
    '''

    bbox_cell = pg.bbox(bbox)

    nvias_x = int(np.floor(bbox_cell.xsize / (via.size + spacing)))

    nvias_y = int(np.floor(bbox_cell.ysize / (via.size + spacing)))

    if nvias_x == 0 or nvias_y == 0:

        return

    via_cell = pt.draw_array(via.draw(),
                             nvias_x,
                             nvias_y,
                             row_spacing=spacing,
                             column_spacing=spacing)

    via_cell.move(origin=(via_cell.x, via_cell.y),
                  destination=(bbox_cell.x, bbox_cell.y))

    tbr = []

    for elem in via_cell.references:

        if not pt.is_cell_inside(elem, cell, tolerance):

            tbr.append(elem)

    via_cell.remove(tbr)

    cell.absorb(cell.add_ref(via_cell, alias="Vias"))
def global_markers(layer_marker=10, layer_mask=20):
    D = Device('Global Markers')
    R = pg.rectangle(size=(20, 20), layer=1)
    a = D.add_array(R, columns=6, rows=6, spacing=(100, 100))
    a.move([-260, -260])  #Center of the array

    R = pg.rectangle(size=(20, 20), layer=1)
    a = D.add_array(R, columns=6, rows=6, spacing=(100, 100))
    a.move([-260, -260])  #Center of the array

    #Add marker cover
    cover = pg.bbox(bbox=a.bbox, layer=layer_mask)
    D << pg.offset(cover, distance=100, layer=layer_mask)
    return D
Esempio n. 4
0
import traceback

bbox = ((0, 100), (400, 600))

route = pc.Routing()

route.source = dl.Port(name='source',
                       midpoint=(200, 0),
                       width=50,
                       orientation=90)

route.destination = dl.Port(name='destination',
                            midpoint=(200, 800),
                            width=50,
                            orientation=0)

route.trace_width = 20

route.clearance = bbox

route.overhang = 50

route.side = 'right'

cell = pg.bbox(bbox)
# st.check(route._draw_frame())
cell << route.draw()

st.check(cell)
Esempio n. 5
0
from phidl import quickplot as qp

D = pg.rectangle(size = (4.5, 2), layer = 0)
qp(D) # quickplot the geometry
create_image(D, 'rectangle')


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

D = Device()
arc = D << pg.arc(radius = 10, width = 0.5, theta = 85, layer = 1).rotate(25)
 # Draw a rectangle around the arc we created by using the arc's bounding box
rect = D << pg.bbox(bbox = arc.bbox, layer = 0)
qp(D) # quickplot the geometry
create_image(D, 'bbox')

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

D = pg.cross(length = 10, width = 0.5, layer = 0)
qp(D) # quickplot the geometry
create_image(D, 'cross')

# example-ellipse
import phidl.geometry as pg
from phidl import quickplot as qp
Esempio n. 6
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
Esempio n. 7
0
def alignment_marks_4layers(scale=[0.2, 0.5, 1]):
    def dr(cell):

        return DeviceReference(cell)

    BElayer = pt.LayoutDefault.layerBottom
    TElayer = pt.LayoutDefault.layerTop
    VIAlayer = pt.LayoutDefault.layerVias
    ETCHlayer = pt.LayoutDefault.layerEtch
    PETCHlayer = pt.LayoutDefault.layerPartialEtch
    Zerolayer = pt.LayoutDefault.layerPad

    align1 = verniers(scale,
                      layers=[BElayer, VIAlayer],
                      label='VIA',
                      reversed=True)
    align_ph = pg.bbox(align1.bbox)  #only for space
    align2 = verniers(scale, layers=[BElayer, TElayer], label='TE')
    align3 = verniers(scale, layers=[BElayer, ETCHlayer], label='ETCH')
    align4 = verniers(scale, layers=[BElayer, PETCHlayer], label='PETCH')

    text = pc.Text()
    text.size = 300
    text.layer = (BElayer, TElayer, ETCHlayer, PETCHlayer, VIAlayer)
    text.label = "Align to BE"

    t1 = text.draw()

    g = Group([align1, dr(align_ph), align2, align3, align4, t1])
    g.distribute(direction='x', spacing=150)
    g.align(alignment='y')

    align5 = verniers(scale,
                      layers=[TElayer, VIAlayer],
                      label='VIA',
                      reversed=True)
    align6 = verniers(scale, layers=[TElayer, ETCHlayer], label='ETCH')
    align7 = verniers(scale, layers=[TElayer, PETCHlayer], label='PETCH')

    text.layer = (TElayer, ETCHlayer, PETCHlayer, VIAlayer)
    text.label = 'Align to TE'
    t2 = text.draw()

    g2 = Group([align5, dr(align_ph), dr(align_ph), align6, align7, t2])
    g2.distribute(direction='x', spacing=150)
    g2.align(alignment='y')

    align8 = verniers(scale,
                      layers=[Zerolayer, VIAlayer],
                      label='VIA',
                      reversed=True)
    align9 = verniers(scale, layers=[Zerolayer, BElayer], label='BE')
    align10 = verniers(scale, layers=[Zerolayer, TElayer], label='TE')
    align11 = verniers(scale, layers=[Zerolayer, ETCHlayer], label='ETCH')
    align12 = verniers(scale, layers=[Zerolayer, PETCHlayer], label='PETCH')

    text.layer = (Zerolayer, BElayer, TElayer, ETCHlayer, PETCHlayer, VIAlayer)
    text.label = "Align to Pad"

    t3 = text.draw()

    g3 = Group([align8, align9, align10, align11, align12, t3])
    g3.distribute(direction='x', spacing=150)
    g3.align(alignment='y')

    g_tot = Group([g, g2, g3])
    g_tot.distribute(direction='y', spacing=150)
    g_tot.align(alignment='xmin')

    cell = Device("Alignments")

    for c in [align1, align2, align3, align4, t1]:

        cell.add(c)

    for c in [align5, align6, align7, t2]:
        cell.add(c)

    for c in [align8, align9, align10, align11, align12, t3]:
        cell.add(c)

    return cell
Esempio n. 8
0
def test_bbox():
    D = pg.bbox(bbox=[(-1, -1), (3, 4)], layer=0)
    h = D.hash_geometry(precision=1e-4)
    assert (h == 'e04a2dc0457f4ae300e9d1235fde335362c8b454')
Esempio n. 9
0
    def path(self):

        tol = 1e-3

        bbox = pg.bbox(self.clearance)

        ll, lr, ul, ur = get_corners(bbox)

        source = self.source

        destination = self.destination

        if source.y > destination.y:

            source = self.destination
            destination = self.source

        if Point(source.midpoint).in_box(bbox.bbox):

            raise ValueError(
                f" Source of routing {source.midport} is in clearance area {bbox.bbox}"
            )

        if Point(destination.midpoint).in_box(bbox.bbox):

            raise ValueError(
                f" Destination of routing{destination.midpoint} is in clearance area{bbox.bbox}"
            )

        if destination.y <= ll.y + tol:  # destination is below clearance

            if not(destination.orientation==source.orientation+180 or \
                destination.orientation==source.orientation-180):

                raise Exception(
                    "Routing error: non-hindered routing needs +90 -> -90 oriented ports"
                )

            distance=Point(destination.midpoint)-\
                Point(source.midpoint)

            p1 = Point(source.midpoint)

            p2 = p1 + Point(distance.x, distance.y * (3 / 4))

            p3 = p2 + Point(0, distance.y / 4)

            list_points = _check_points_path(p1,
                                             p2,
                                             p3,
                                             trace_width=self.trace_width)

            try:

                p = pp.smooth(points=list_points,
                              radius=self._radius,
                              num_pts=self._num_pts)

            except Exception:

                raise ValueError("error for non-hindered path ")

        else:  #destination is above clearance

            if not destination.orientation == 90:

                raise ValueError("Routing case not covered yet")

            elif source.orientation == 0:  #right ground_pad_side

                source.name = 'source'

                destination.name = 'destination'

                p0 = Point(source.midpoint)

                p1 = Point(ur.x + self.trace_width, p0.y)

                p2 = Point(p1.x, ur.y + self.trace_width)

                p3 = Point(destination.x, p2.y)

                p4 = Point(destination.x, destination.y)

                list_points_rx = _check_points_path(
                    p0, p1, p2, p3, p4, trace_width=self.trace_width)

                try:

                    p = pp.smooth(points=list_points_rx,
                                  radius=self._radius,
                                  num_pts=self._num_pts)

                except Exception:

                    raise ValueError("error in +0 source, rx path")

            if source.orientation == 90:

                if source.x + self.trace_width > ll.x and source.x - self.trace_width < lr.x:  #source tucked inside clearance

                    p0 = Point(source.midpoint)

                    center_box = Point(bbox.center)

                    #left path
                    p1 = p0 - Point(0, source.width / 2)

                    p2 = Point(ll.x - self.trace_width, p1.y)

                    p3 = Point(p2.x, self.trace_width + destination.y)

                    p4 = Point(destination.x, p3.y)

                    p5 = Point(destination.x, destination.y)

                    list_points_lx = _check_points_path(
                        p0, p1, p2, p3, p4, p5, trace_width=self.trace_width)

                    try:

                        p_lx = pp.smooth(points=list_points_lx,
                                         radius=self._radius,
                                         num_pts=self._num_pts)

                    except:

                        raise ValueError(
                            "error in +90 hindered tucked path, lx path")

                    #right path

                    p1 = p0 - Point(0, source.width / 2)

                    p2 = Point(lr.x + self.trace_width, p1.y)

                    p3 = Point(p2.x, self.trace_width + destination.y)

                    p4 = Point(destination.x, p3.y)

                    p5 = Point(destination.x, destination.y)

                    list_points_rx = _check_points_path(
                        p0, p1, p2, p3, p4, p5, trace_width=self.trace_width)

                    try:

                        p_rx = pp.smooth(points=list_points_rx,
                                         radius=self._radius,
                                         num_pts=self._num_pts)

                    except:

                        raise ValueError("error in +90 source, rx path")

                    if self.side == 'auto':

                        if p_lx.length() < p_rx.length():

                            p = p_lx

                        else:

                            p = p_rx

                    elif self.side == 'left':

                        p = p_lx

                    elif self.side == 'right':

                        p = p_rx

                    else:

                        raise ValueError("Invalid option for side :{}".format(
                            self.side))

                else:  # source is not tucked under the clearance

                    p0 = Point(source.midpoint)

                    ll, lr, ul, ur = get_corners(bbox)

                    center_box = Point(bbox.center)

                    #left path
                    p1 = Point(p0.x, destination.y + self.trace_width)

                    p2 = Point(destination.x, p1.y)

                    p3 = Point(destination.x, destination.y)

                    list_points = _check_points_path(
                        p0, p1, p2, p3, trace_width=self.trace_width)

                    try:

                        p = pp.smooth(points=list_points,
                                      radius=self._radius,
                                      num_pts=self._num_pts
                                      )  #source tucked inside clearance

                    except Exception:

                        raise ValueError(
                            "error for non-tucked hindered p ,90 deg")

            elif source.orientation == 180:  #left path

                p0 = Point(source.midpoint)

                p1 = Point(ll.x - self.trace_width, p0.y)

                p2 = Point(p1.x, ur.y + self.trace_width)

                p3 = Point(destination.x, p2.y)

                p4 = Point(destination.x, destination.y)

                list_points_lx = _check_points_path(
                    p0, p1, p2, p3, p4, trace_width=self.trace_width)

                try:

                    p = pp.smooth(points=list_points_lx,
                                  radius=self._radius,
                                  num_pts=self._num_pts)

                except Exception:

                    import pdb
                    pdb.set_trace()

                    raise ValueError("error in +180 source, lx path")

        return p