Example #1
0
        def _draw_padded_via(self):

            viaref=DeviceReference(self.via.draw())

            size=float(self.via.size*self.over_via)

            port=viaref.ports['conn']

            trace=pg.rectangle(size=(size,size),layer=self.pad_layers[0])

            trace.move(origin=trace.center,\
                destination=viaref.center)

            trace2=pg.copy_layer(trace,layer=self.pad_layers[0],new_layer=self.pad_layers[1])

            cell=Device(self.name)

            cell.absorb(cell<<trace)

            cell.absorb(cell<<trace2)

            cell.add(viaref)

            port.midpoint=(port.midpoint[0],cell.ymax)

            port.width=size

            cell.add_port(port)

            if bottom_conn==False:

                cell.remove_layers(layers=[self.pad_layers[1]])

            return cell
Example #2
0
def point_path(points=[(0, 0), (4, 0), (4, 8)], width=1, layer=0):
    points = np.asarray(points)
    dxdy = points[1:] - points[:-1]
    angles = (np.arctan2(dxdy[:, 1], dxdy[:, 0])).tolist()
    angles = np.array([angles[0]] + angles + [angles[-1]])
    diff_angles = (angles[1:] - angles[:-1])
    mean_angles = (angles[1:] + angles[:-1]) / 2
    dx = width / 2 * np.cos((mean_angles - pi / 2)) / np.cos((diff_angles / 2))
    dy = width / 2 * np.sin((mean_angles - pi / 2)) / np.cos((diff_angles / 2))
    left_points = points.T - np.array([dx, dy])
    right_points = points.T + np.array([dx, dy])
    all_points = np.concatenate([left_points.T, right_points.T[::-1]])

    D = Device()
    D.add_polygon(all_points, layer=layer)
    D.add_port(name=1,
               midpoint=points[0],
               width=width,
               orientation=angles[0] * 180 / pi + 180)
    D.add_port(name=2,
               midpoint=points[-1],
               width=width,
               orientation=angles[-1] * 180 / pi)
    return D


# quickplot(point_path())
Example #3
0
    def draw(self):
        ''' Generates layout cell based on current parameters.

        'conn' port is included in the cell.

        Returns
        -------
        cell : phidl.Device.
        '''
        o = self.origin

        pad=pg.rectangle(size=self.size.coord,\
        layer=self.layer).move(origin=(0,0),\
        destination=o.coord)

        cell = Device(self.name)

        r1 = cell << pad
        cell.absorb(r1)
        r2 = cell << pad

        r2.move(origin=o.coord,\
        destination=(o+self.distance).coord)

        cell.absorb(r2)

        cell.add_port(name='conn',\
        midpoint=(o+Point(self.size.x/2,self.size.y)).coord,\
        width=self.size.x,\
        orientation=90)

        del pad

        return cell
Example #4
0
def _arc(radius=10,
         width=0.5,
         theta=45,
         start_angle=0,
         angle_resolution=2.5,
         layer=0):
    """ Creates an arc of arclength ``theta`` starting at angle ``start_angle`` """
    inner_radius = radius - width / 2
    outer_radius = radius + width / 2
    angle1 = (start_angle) * pi / 180
    angle2 = (start_angle + theta) * pi / 180
    t = np.linspace(angle1, angle2, np.ceil(abs(theta) / angle_resolution))
    inner_points_x = (inner_radius * cos(t)).tolist()
    inner_points_y = (inner_radius * sin(t)).tolist()
    outer_points_x = (outer_radius * cos(t)).tolist()
    outer_points_y = (outer_radius * sin(t)).tolist()
    xpts = inner_points_x + outer_points_x[::-1]
    ypts = inner_points_y + outer_points_y[::-1]

    D = Device('arc')
    D.add_polygon(points=(xpts, ypts), layer=layer)
    D.add_port(name=1,
               midpoint=(radius * cos(angle1), radius * sin(angle1)),
               width=width,
               orientation=start_angle - 90 + 180 * (theta < 0))
    D.add_port(name=2,
               midpoint=(radius * cos(angle2), radius * sin(angle2)),
               width=width,
               orientation=start_angle + theta + 90 - 180 * (theta < 0))
    D.info['length'] = (abs(theta) * pi / 180) * radius
    return D
Example #5
0
    def draw(self):

        cell = Device(name=self.name)

        lfe_cell = LFERes.draw(self)

        cell.add_ref(lfe_cell, alias='TopCell')

        idt_bottom = copy(self.idt)

        idt_bottom.layer = self.bottom_layer

        idt_ref = cell.add_ref(idt_bottom.draw(), alias='BottomIDT')

        p_bott = idt_ref.ports['bottom']

        p_bott_coord = Point(p_bott.midpoint)

        idt_ref.mirror(p1=(p_bott_coord-Point(p_bott.width/2,0)).coord,\
            p2=(p_bott_coord+Point(p_bott.width/2,0)).coord)

        idt_ref.move(origin=(idt_ref.xmin,idt_ref.ymax),\
            destination=(idt_ref.xmin,idt_ref.ymax+self.idt.length+self.idt.y_offset))

        bus_bottom = copy(self.bus)

        bus_bottom.layer = self.bottom_layer

        bus_ref = cell.add_ref(bus_bottom.draw(), alias='BottomBus')

        bus_ref.move(origin=(0,0),\
        destination=(0,-self.bus.size.y))

        anchor_bottom = copy(self.anchor)

        anchor_bottom.layer = self.bottom_layer

        anchor_bottom.etch_choice = False

        anchor_ref = cell.add_ref(anchor_bottom.draw(),
                                  alias="BottomAnchor_Top")

        anchor_ref.connect(anchor_ref.ports['conn'],\
            destination=idt_ref.ports['top'],\
            overlap=-self.bus.size.y)

        anchor_ref_2 = cell.add_ref(anchor_bottom.draw(),
                                    alias="BottomAnchor_Bottom")

        anchor_ref_2.connect(anchor_ref_2.ports['conn'],\
            destination=idt_ref.ports['bottom'],\
            overlap=-self.bus.size.y)

        for p_value in lfe_cell.ports.values():

            cell.add_port(p_value)

        return cell
Example #6
0
        def draw(self):
            def mirror_label(str):

                if 'N_' in str:

                    return str.replace('N_', 'S_')

                if 'E_' in str:

                    return str.replace('E_', 'W_')

                if 'S_' in str:

                    return str.replace('S_', 'N_')

                if 'W_' in str:

                    return str.replace('W_', 'E_')

                return str

            cell = Device(name=self.name)

            probe_cell = super().draw()

            p1 = cell.add_ref(probe_cell, alias='Port1')

            p2 = cell.add_ref(probe_cell, alias='Port2')

            p2.rotate(center=(p1.x, p1.ymax), angle=180)

            p2.move(destination=self.offset.coord)

            for n, p in p1.ports.items():

                cell.add_port(port=p, name=n + '_1')

            for n, p in p2.ports.items():

                if 'LX' in n:

                    cell.add_port(port=p,
                                  name=mirror_label(n + '_2').replace(
                                      'LX', 'RX'))

                else:

                    if 'RX' in n:

                        cell.add_port(port=p,
                                      name=mirror_label(n + '_2').replace(
                                          'RX', 'LX'))

                    else:

                        cell.add_port(port=p, name=mirror_label(n + '_2'))

            return cell
Example #7
0
    def draw(self):
        ''' Generates layout cell based on current parameters.

        'top' and 'bottom' ports are included in the cell.

        Returns
        -------
        cell : phidl.Device.
        '''

        unitcell = self._draw_unit_cell()

        cell = Device(self.name)

        cell.name = self.name

        cell.add_array(unitcell,columns=self.n,rows=1,\
            spacing=(self.pitch*2,0))

        cell.flatten()

        totx = self.pitch * (self.n * 2 + 1) - self.pitch * (1 - self.coverage)

        midx = totx / 2

        finger_dist=Point(self.pitch*1,\
        self.length+self.y_offset)

        cell = join(cell)

        cell.name = self.name

        cell.add_port(Port(name='bottom',\
        midpoint=(self.origin+\
        Point(midx,0)).coord,\
        width=totx,
        orientation=-90))

        cell.add_port(Port(name='top',\
        midpoint=(self.origin+\
        Point(midx,self.length+self.y_offset)).coord,\
        width=totx,
        orientation=90))

        del unitcell

        return cell
Example #8
0
def attach_taper(cell : Device , port : Port , length : float , \
    width2 : float, layer=LayoutDefault.layerTop) :

    t = pg.taper(length=length, width1=port.width, width2=width2, layer=layer)

    t_ref = cell.add_ref(t)

    t_ref.connect(1, destination=port)

    new_port = t_ref.ports[2]

    new_port.name = port.name

    cell.absorb(t_ref)

    cell.remove(port)

    cell.add_port(new_port)
Example #9
0
    def draw(self):
        ''' Generates layout cell based on current parameters.

        'top' and 'bottom' ports is included in the cell.

        Returns
        -------
        cell : phidl.Device.
        '''
        o = self.origin

        b_main = Bus()

        b_main.origin = o

        b_main.layer = self.layer

        b_main.size = Point(self.x, self.active_area.y)

        b_main.distance = Point(self.active_area.x + self.x, 0)

        main_etch = b_main.draw()

        etch = Device(self.name)

        etch.absorb(etch << main_etch)

        port_up=Port('top',\
        midpoint=(o+Point(self.x+self.active_area.x/2,self.active_area.y)).coord,\
        width=self.active_area.x,\
        orientation=-90)

        port_down=Port('bottom',\
        midpoint=(o+Point(self.x+self.active_area.x/2,0)).coord,\
        width=self.active_area.x,\
        orientation=90)

        etch.add_port(port_up)
        etch.add_port(port_down)

        del main_etch

        return etch
Example #10
0
        def draw(self):

            cell=Device(name=self.name)

            super_ref=cell.add_ref(cls.draw(self))

            nvias_x,nvias_y=self.n_vias

            unit_cell=self._draw_padded_via()

            viacell=join(CellArray(unit_cell,\
                columns=nvias_x,rows=nvias_y,\
                spacing=(unit_cell.xsize,unit_cell.ysize)))

            viacell.add_port(Port(name='conn',\
                midpoint=(viacell.x,viacell.ymax),\
                width=viacell.xsize,\
                orientation=90))

            for sides in side:

                for p_name in super_ref.ports.keys():

                    if re.search(sides,p_name):

                        p=super_ref.ports[p_name]

                        pad=pg.compass(size=(p.width,self.via_distance),layer=self.pad_layers[0])

                        if sides=='top':

                            self._attach_instance(cell, pad, pad.ports['S'], viacell,p)

                        if sides=='bottom':

                            self._attach_instance(cell, pad, pad.ports['N'], viacell,p)

            for p_name,p_value in super_ref.ports.items():

                cell.add_port(p_value)

            return cell
Example #11
0
        def draw(self):

            cell=Device()

            cell.name=self.name

            d_ref=cell.add_ref(cls.draw(self))

            for name,port in d_ref.ports.items():

                self.pad.port=port

                pad_ref=cell.add_ref(self.pad.draw())

                pad_ref.connect(pad_ref.ports['conn'],
                    destination=port)

                cell.absorb(pad_ref)

                cell.add_port(port,name)

            return cell
Example #12
0
    def draw(self):

        name = self.name

        o = self.origin

        pad_x = self.size.x

        if pad_x > self.pitch * 2 / 3:

            pad_x = self.pitch * 2 / 3

            warnings.warn("Pad size too large, capped to pitch*2/3")

        pad_cell=pg.rectangle(size=(pad_x,self.size.y),\
        layer=self.layer)

        pad_cell.move(origin=(0,0),\
        destination=o.coord)

        cell = Device(self.name)

        dp = Point(self.pitch, 0)
        pad_gnd_sx = cell << pad_cell
        pad_sig = cell << pad_cell
        pad_sig.move(origin=o.coord,\
        destination=(o+dp).coord)

        cell.add_port(Port(name='gnd_left',\
        midpoint=(o+Point(pad_x/2+self.pitch,self.size.y)).coord,\
        width=pad_x,\
        orientation=90))

        cell.add_port(Port(name='sig',\
        midpoint=(o+Point(pad_x/2,self.size.y)).coord,\
        width=pad_x,\
        orientation=90))

        return cell
Example #13
0
def from_phidl(component: Device, **kwargs) -> Component:
    """Returns gf.Component from a phidl Device or function"""
    device = call_if_func(component, **kwargs)
    component = Component(name=device.name)

    for ref in device.references:
        new_ref = ComponentReference(
            component=ref.parent,
            origin=ref.origin,
            rotation=ref.rotation,
            magnification=ref.magnification,
            x_reflection=ref.x_reflection,
        )
        new_ref.owner = component
        component.add(new_ref)
        for alias_name, alias_ref in device.aliases.items():
            if alias_ref == ref:
                component.aliases[alias_name] = new_ref

    for p in device.ports.values():
        component.add_port(
            port=Port(
                name=p.name,
                midpoint=p.midpoint,
                width=p.width,
                orientation=p.orientation,
                parent=p.parent,
            )
        )
    for poly in device.polygons:
        component.add_polygon(poly)
    for label in device.labels:
        component.add_label(
            text=label.text,
            position=label.position,
            layer=(label.layer, label.texttype),
        )
    return component
Example #14
0
def add_compass(device: Device) -> Device:
    ''' add four ports at the bbox of a cell.

    Parameters
    ----------
    device : phidl.Device

    Returns
    -------
    device : phidl.Device.
    '''

    bound_cell=pg.compass(size=device.size).move(\
    origin=(0,0),destination=device.center)

    ports = port = bound_cell.get_ports()

    device.add_port(port=ports[0], name='N')
    device.add_port(port=ports[1], name='S')
    device.add_port(port=ports[2], name='E')
    device.add_port(port=ports[3], name='W')

    return device
Example #15
0
    def draw(self):

        cell = Device()

        cell.name = self.name

        supercell = LFERes.draw(self)

        super_ref = cell.add_ref(supercell)

        if self.plate_position == 'out, short':

            plate=pg.rectangle(size=(self.etchpit.active_area.x+8*self.idt.active_area_margin,self.idt.length-self.idt.y_offset/2),\
            layer=self.platelayer)

            plate_ref = cell.add_ref(plate, alias='Plate')

            transl_rel=Point(self.etchpit.x-4*self.idt.active_area_margin,self.anchor.size.y+2*self.anchor.etch_margin.y+self.bus.size.y\
                +self.idt.y_offset*3/4)

            lr_cell = get_corners(cell)[0]
            lr_plate = get_corners(plate_ref)[0]

            plate_ref.move(origin=lr_plate.coord,\
            destination=(lr_plate+lr_cell+transl_rel).coord)

            cell.absorb(plate_ref)

            del plate

        elif self.plate_position == 'in, short':

            plate=pg.rectangle(\
                size=(\
                    self.etchpit.active_area.x-\
                        2*self.idt.active_area_margin,\
                        self.idt.length-self.idt.y_offset/2),\
                layer=self.platelayer)

            plate_ref = cell.add_ref(plate, alias='Plate')

            transl_rel=Point(self.etchpit.x+\
                    self.idt.active_area_margin,\
                self.anchor.size.y+\
                2*self.anchor.etch_margin.y+\
                self.bus.size.y+\
                self.idt.y_offset*3/4)

            lr_cell = get_corners(cell)[0]
            lr_plate = get_corners(plate_ref)[0]

            plate_ref.move(origin=lr_plate.coord,\
            destination=(lr_plate+lr_cell+transl_rel).coord)

            cell.absorb(plate_ref)

            del plate

        elif self.plate_position == 'out, long':

            plate=pg.rectangle(\
                size=(self.etchpit.active_area.x+\
                        8*self.idt.active_area_margin,\
                    self.idt.length+\
                        2*self.bus.size.y+\
                        self.idt.y_offset),\
                layer=self.platelayer)

            plate_ref = cell.add_ref(plate, alias='Plate')

            transl_rel=Point(self.etchpit.x-\
                4*self.idt.active_area_margin,\
                    self.anchor.size.y+2*self.anchor.etch_margin.y)

            lr_cell = get_corners(cell)[0]
            lr_plate = get_corners(plate_ref)[0]

            plate_ref.move(origin=lr_plate.coord,\
            destination=(lr_plate+lr_cell+transl_rel).coord)

            cell.absorb(plate_ref)

            del plate

        elif self.plate_position == 'in, long':

            plate=pg.rectangle(\
                size=(\
                    self.etchpit.active_area.x-\
                        2*self.idt.active_area_margin,\
                        self.idt.length+\
                            2*self.bus.size.y+\
                            self.idt.y_offset),
                layer=self.platelayer)

            plate_ref = cell.add_ref(plate, alias='Plate')

            transl_rel=Point(self.etchpit.x+\
                    self.idt.active_area_margin,\
                        self.anchor.size.y+2*self.anchor.etch_margin.y)

            lr_cell = get_corners(cell)[0]
            lr_plate = get_corners(plate_ref)[0]

            plate_ref.move(origin=lr_plate.coord,\
            destination=(lr_plate+lr_cell+transl_rel).coord)

            cell.absorb(plate_ref)

            del plate

        for name, port in supercell.ports.items():

            cell.add_port(port, name)

        return cell
Example #16
0
from phidl import set_quickplot_options

set_quickplot_options(blocking=True)

distance = 50
width = 10
spacing = 50
n = 4

d = Device()

for i in range(n):

    d.add_port(
        Port(
            midpoint=(spacing * i, 0),
            # midpoint=(0,spacing*i),
            width=width,
            orientation=90,
            name='top_' + str(i)))

connector = connect_ports(d, tag='top', distance=distance)

d << connector

for p in connector.get_ports(depth=0):

    d.add_port(connector.ports[p.name])

qp(d)
Example #17
0
    def draw(self):

        self._set_relations()

        idt_cell = self.idt.draw()

        cell = Device(self.name)

        idt_ref = cell.add_ref(idt_cell, alias="IDT")

        idt_top_port = idt_ref.ports['top']

        idt_bottom_port = idt_ref.ports['bottom']

        bus_cell = self.bus.draw()

        bus_ref = cell.add_ref(bus_cell, alias="BUS")

        bus_ref.connect(port=bus_cell.ports['conn'],\
        destination=idt_bottom_port)

        etch_cell = self.etchpit.draw()

        etch_ref = cell.add_ref(etch_cell, alias='EtchPit')

        etch_ref.connect(etch_ref.ports['bottom'],\
        destination=idt_ref.ports['bottom'],\
        overlap=-self.bus.size.y-self.anchor.etch_margin.y)

        anchor_cell = self.anchor.draw()

        anchor_bottom = cell.add_ref(anchor_cell, alias='AnchorBottom')

        anchor_bottom.connect(anchor_bottom.ports['conn'],
                              destination=idt_ref.ports['bottom'],
                              overlap=-self.bus.size.y)

        if not self._stretch_top_margin:

            anchor_top = cell.add_ref(anchor_cell, alias='AnchorTop')

        else:

            anchor_top_dev = deepcopy(self.anchor)

            anchor_top_dev.metalized = Point(anchor_top_dev.size.x - 2,
                                             anchor_top_dev.metalized.y)

            anchor_top = cell.add_ref(anchor_top_dev.draw(), alias='AnchorTop')

            del anchor_top_dev

        anchor_top.connect(anchor_top.ports['conn'],\
            idt_ref.ports['top'],overlap=-self.bus.size.y)

        outport_top = anchor_top.ports['conn']

        outport_bottom = anchor_bottom.ports['conn']

        outport_top.name = 'top'
        outport_top.orientation = 90
        outport_bottom.name = 'bottom'
        outport_bottom.orientation = -90

        outport_top.midpoint=(\
            outport_top.x,\
            outport_top.y+self.anchor.metalized.y)
        outport_bottom.midpoint=(\
            outport_bottom.x,\
            outport_bottom.y-self.anchor.metalized.y)

        cell.add_port(outport_top)
        cell.add_port(outport_bottom)

        del idt_cell, bus_cell, etch_cell, anchor_cell

        return cell
Example #18
0
    def draw(self):
        ''' Generates layout cell based on current parameters.

        'conn' port is included in the cell.

        Returns
        -------
        cell : phidl.Device.
        '''

        self._check_anchor()

        o = self.origin

        anchor=pg.rectangle(\
            size=(self.size-Point(2*self.etch_margin.x,-2*self.etch_margin.y)).coord,\
            layer=self.layer)

        etch_size=Point(\
        (self.etch_x-self.size.x)/2,\
        self.size.y)

        offset = Point(self.x_offset, 0)

        cell = Device(self.name)

        etch_sx=pg.rectangle(\
            size=(etch_size-offset).coord,\
            layer=self.etch_layer)

        etch_dx=pg.rectangle(\
            size=(etch_size+offset).coord,\
            layer=self.etch_layer)

        etch_sx_ref=(cell<<etch_sx).move(origin=(0,0),\
        destination=(o-Point(0,self.etch_margin.y)).coord)

        anchor_transl = o + Point(etch_sx.size[0] + self.etch_margin.x,
                                  -2 * self.etch_margin.y)

        anchor_ref=(cell<<anchor).move(origin=(0,0),\
        destination=anchor_transl.coord)

        etchdx_transl = anchor_transl + Point(
            anchor.size[0] + self.etch_margin.x, +self.etch_margin.y)

        etch_dx_ref=(cell<<etch_dx).move(origin=(0,0),\
        destination=etchdx_transl.coord)

        cell.add_port(name='conn',\
        midpoint=(anchor_transl+Point(self.size.x/2-self.etch_margin.x,self.size.y+2*self.etch_margin.y)).coord,\
        width=self.metalized.x,\
        orientation=90)

        if self.etch_choice == True:

            cell.absorb(etch_sx_ref)
            cell.absorb(anchor_ref)
            cell.absorb(etch_dx_ref)

        else:

            cell.remove(etch_sx_ref)
            cell.remove(etch_dx_ref)

        del anchor, etch_sx, etch_dx

        return cell
Example #19
0
def route_basic(port1,
                port2,
                path_type='sine',
                width_type='straight',
                width1=None,
                width2=None,
                num_path_pts=99,
                layer=0):

    # Assuming they're both Ports for now
    point_a = np.array(port1.midpoint)
    if width1 is None: width1 = port1.width
    point_b = np.array(port2.midpoint)
    if width2 is None: width2 = port2.width
    if round(abs(mod(port1.orientation - port2.orientation, 360)), 3) != 180:
        raise ValueError(
            '[DEVICE] route() error: Ports do not face each other (orientations must be 180 apart)'
        )
    orientation = port1.orientation

    separation = point_b - point_a  # Vector drawn from A to B
    distance = norm(separation)  # Magnitude of vector from A to B
    rotation = np.arctan2(
        separation[1],
        separation[0]) * 180 / pi  # Rotation of vector from A to B
    angle = rotation - orientation  # If looking out along the normal of ``a``, the angle you would have to look to see ``b``
    forward_distance = distance * cos(angle * pi / 180)
    lateral_distance = distance * sin(angle * pi / 180)

    # Create a path assuming starting at the origin and setting orientation = 0
    # use the "connect" function later to move the path to the correct location
    xf = forward_distance
    yf = lateral_distance
    if path_type == 'straight':
        curve_fun = lambda t: [xf * t, yf * t]
        curve_deriv_fun = lambda t: [xf + t * 0, t * 0]
    if path_type == 'sine':
        curve_fun = lambda t: [xf * t, yf * (1 - cos(t * pi)) / 2]
        curve_deriv_fun = lambda t: [xf + t * 0, yf * (sin(t * pi) * pi) / 2]
    #if path_type == 'semicircle':
    #    def semicircle(t):
    #        t = np.array(t)
    #        x,y = np.zeros(t.shape), np.zeros(t.shape)
    #        ii = (0 <= t) & (t <= 0.5)
    #        jj = (0.5 < t) & (t <= 1)
    #        x[ii] = (cos(-pi/2 + t[ii]*pi/2))*xf
    #        y[ii] = (sin(-pi/2 + t[ii]*pi/2)+1)*yf*2
    #        x[jj] = (cos(pi*3/2 - t[jj]*pi)+2)*xf/2
    #        y[jj] = (sin(pi*3/2 - t[jj]*pi)+1)*yf/2
    #        return x,y
    #    curve_fun = semicircle
    #    curve_deriv_fun = None
    if width_type == 'straight':
        width_fun = lambda t: (width2 - width1) * t + width1
    if width_type == 'sine':
        width_fun = lambda t: (width2 - width1) * (1 - cos(t * pi)
                                                   ) / 2 + width1

    route_path = gdspy.Path(width=width1, initial_point=(0, 0))
    route_path.parametric(curve_fun,
                          curve_deriv_fun,
                          number_of_evaluations=num_path_pts,
                          max_points=199,
                          final_width=width_fun,
                          final_distance=None)
    route_path_polygons = route_path.polygons

    # Make the route path into a Device with ports, and use "connect" to move it
    # into the proper location
    D = Device()
    D.add_polygon(route_path_polygons, layer=layer)
    p1 = D.add_port(name=1, midpoint=(0, 0), width=width1, orientation=180)
    p2 = D.add_port(name=2,
                    midpoint=[forward_distance, lateral_distance],
                    width=width2,
                    orientation=0)
    D.info['length'] = route_path.length

    D.rotate(angle=180 + port1.orientation - p1.orientation,
             center=p1.midpoint)
    D.move(origin=p1, destination=port1)
    return D
Example #20
0
def route_manhattan(port1, port2, bendType='circular', layer=0, radius=20):
    #route along cardinal directions between any two ports placed diagonally
    #from each other

    Total = Device()
    width = port1.width
    #first map into uniform plane with normal x,y coords
    #allows each situation to be put into uniform cases of quadrants for routing.
    #this is because bends change direction and positioning.
    if port1.orientation == 0:
        p2 = [port2.midpoint[0], port2.midpoint[1]]
        p1 = [port1.midpoint[0], port1.midpoint[1]]
    if port1.orientation == 90:
        p2 = [port2.midpoint[1], -port2.midpoint[0]]
        p1 = [port1.midpoint[1], -port1.midpoint[0]]
    if port1.orientation == 180:
        p2 = [-port2.midpoint[0], -port2.midpoint[1]]
        p1 = [-port1.midpoint[0], -port1.midpoint[1]]
    if port1.orientation == 270:
        p2 = [-port2.midpoint[1], port2.midpoint[0]]
        p1 = [-port1.midpoint[1], port1.midpoint[0]]

    Total.add_port(name=1, port=port1)
    Total.add_port(name=2, port=port2)

    if p2[1] == p1[1] or p2[0] == p1[0]:
        raise ValueError('Error - ports must be at different x AND y values.')

    #if it is parallel or anti-parallel, route with 180 option
    if (np.round(np.abs(np.mod(port1.orientation - port2.orientation, 360)), 3)
            == 180) or (np.round(
                np.abs(np.mod(port1.orientation - port2.orientation, 360)), 3)
                        == 0):
        R1 = route_manhattan180(port1=port1,
                                port2=port2,
                                bendType=bendType,
                                layer=layer,
                                radius=radius)
        r1 = Total.add_ref(R1)

    else:
        #first quadrant case
        if (p2[1] > p1[1]) & (p2[0] > p1[0]):
            #simple 90 degree single-bend case
            if port2.orientation == port1.orientation - 90 or port2.orientation == port1.orientation + 270:
                R1 = route_manhattan90(port1=port1,
                                       port2=port2,
                                       bendType=bendType,
                                       layer=layer,
                                       radius=radius)
                r1 = Total.add_ref(R1)
            elif port2.orientation == port1.orientation + 90 or port2.orientation == port1.orientation - 270:
                if bendType == 'circular':
                    B1 = _arc(radius=radius,
                              width=width,
                              layer=layer,
                              angle_resolution=1,
                              start_angle=port1.orientation,
                              theta=90)
                    radiusEff = radius
                if bendType == 'gradual':
                    B1 = _gradual_bend(radius=radius,
                                       width=width,
                                       layer=layer,
                                       start_angle=port1.orientation,
                                       direction='ccw')
                    radiusEff = B1.xsize - width / 2
                b1 = Total.add_ref(B1)
                b1.connect(port=1, destination=port1)

                R1 = route_manhattan180(port1=b1.ports[2],
                                        port2=port2,
                                        bendType=bendType,
                                        layer=layer,
                                        radius=radius)
                r1 = Total.add_ref(R1)
        #second quadrant case
        if (p2[1] > p1[1]) & (p2[0] < p1[0]):
            if np.abs(port1.orientation - port2.orientation) == 90 or np.abs(
                    port1.orientation - port2.orientation) == 270:
                if bendType == 'circular':
                    B1 = _arc(radius=radius,
                              width=width,
                              layer=layer,
                              angle_resolution=1,
                              start_angle=port1.orientation,
                              theta=90)
                    radiusEff = radius
                if bendType == 'gradual':
                    B1 = _gradual_bend(radius=radius,
                                       width=width,
                                       layer=layer,
                                       start_angle=port1.orientation,
                                       direction='ccw')
                    radiusEff = B1.xsize - width / 2
                b1 = Total.add_ref(B1)
                b1.connect(port=1, destination=port1)
                R1 = route_manhattan180(port1=b1.ports[2],
                                        port2=port2,
                                        bendType=bendType,
                                        layer=layer,
                                        radius=radius)
                r1 = Total.add_ref(R1)
        #third quadrant case
        if (p2[1] < p1[1]) & (p2[0] < p1[0]):
            if np.abs(port1.orientation - port2.orientation) == 90 or np.abs(
                    port1.orientation - port2.orientation) == 270:
                if bendType == 'circular':
                    B1 = _arc(radius=radius,
                              width=width,
                              layer=layer,
                              angle_resolution=1,
                              start_angle=port1.orientation,
                              theta=-90)
                    radiusEff = radius
                if bendType == 'gradual':
                    B1 = _gradual_bend(radius=radius,
                                       width=width,
                                       layer=layer,
                                       start_angle=port1.orientation,
                                       direction='cw')
                    radiusEff = B1.xsize - width / 2
                b1 = Total.add_ref(B1)
                b1.connect(port=1, destination=port1)
                R1 = route_manhattan180(port1=b1.ports[2],
                                        port2=port2,
                                        bendType=bendType,
                                        layer=layer,
                                        radius=radius)
                r1 = Total.add_ref(R1)
        #fourth quadrant case
        if (p2[1] < p1[1]) & (p2[0] > p1[0]):
            #simple 90 degree single-bend case
            if port2.orientation == port1.orientation + 90 or port2.orientation == port1.orientation - 270:
                R1 = route_manhattan90(port1=port1,
                                       port2=port2,
                                       bendType=bendType,
                                       layer=layer,
                                       radius=radius)
                r1 = Total.add_ref(R1)
            elif port2.orientation == port1.orientation - 90 or port2.orientation == port1.orientation + 270:
                if bendType == 'circular':
                    B1 = _arc(radius=radius,
                              width=width,
                              layer=layer,
                              angle_resolution=1,
                              start_angle=port1.orientation,
                              theta=-90)
                    radiusEff = radius
                if bendType == 'gradual':
                    B1 = _gradual_bend(radius=radius,
                                       width=width,
                                       layer=layer,
                                       start_angle=port1.orientation,
                                       direction='cw')
                    radiusEff = B1.xsize - width / 2
                b1 = Total.add_ref(B1)
                b1.connect(port=1, destination=port1)
                R1 = route_manhattan180(port1=b1.ports[2],
                                        port2=port2,
                                        bendType=bendType,
                                        layer=layer,
                                        radius=radius)
                r1 = Total.add_ref(R1)
    return Total
Example #21
0
def route_manhattan90(port1, port2, bendType='circular', layer=0, radius=20):
    #this is a subroutine of route_manhattan() and should not be used by itself.
    Total = Device()
    width = port1.width
    #first map into uniform plane with normal x,y coords
    #allows each situation to be put into uniform cases of quadrants for routing.
    #this is because bends change direction and positioning.
    if port1.orientation == 0:
        p2 = [port2.midpoint[0], port2.midpoint[1]]
        p1 = [port1.midpoint[0], port1.midpoint[1]]
    if port1.orientation == 90:
        p2 = [port2.midpoint[1], -port2.midpoint[0]]
        p1 = [port1.midpoint[1], -port1.midpoint[0]]
    if port1.orientation == 180:
        p2 = [-port2.midpoint[0], -port2.midpoint[1]]
        p1 = [-port1.midpoint[0], -port1.midpoint[1]]
    if port1.orientation == 270:
        p2 = [-port2.midpoint[1], port2.midpoint[0]]
        p1 = [-port1.midpoint[1], port1.midpoint[0]]

    #create placeholder ports based on the imaginary coordinates we created
    Total.add_port(name='t1', midpoint=[0, 0], orientation=0, width=width)

    #CHECK THIS

    #first quadrant target, route upward
    if (p2[1] > p1[1]) & (p2[0] > p1[0]):
        Total.add_port(name='t2',
                       midpoint=list(np.subtract(p2, p1)),
                       orientation=-90,
                       width=width)
        if bendType == 'circular':
            B1 = _arc(radius=radius,
                      width=width,
                      layer=layer,
                      angle_resolution=1,
                      start_angle=0,
                      theta=90)
            radiusEff = radius
        if bendType == 'gradual':
            B1 = _gradual_bend(radius=radius,
                               width=width,
                               layer=layer,
                               start_angle=0,
                               direction='ccw')
            radiusEff = B1.xsize - width / 2
        b1 = Total.add_ref(B1)
        b1.connect(port=b1.ports[1], destination=Total.ports['t1'])
        b1.move([p2[0] - p1[0] - radiusEff, 0])

        R1 = route_basic(port1=Total.ports['t1'],
                         port2=b1.ports[1],
                         layer=layer)
        R2 = route_basic(port1=b1.ports[2],
                         port2=Total.ports['t2'],
                         layer=layer)
        r1 = Total.add_ref(R1)
        r2 = Total.add_ref(R2)
        Total.add_port(name=1, port=r1.ports[1])
        Total.add_port(name=2, port=r2.ports[2])

    #fourth quadrant target, route downward
    if (p2[1] < p1[1]) & (p2[0] > p1[0]):
        Total.add_port(name='t2',
                       midpoint=list(np.subtract(p2, p1)),
                       orientation=90,
                       width=width)
        if bendType == 'circular':
            B1 = _arc(radius=radius,
                      width=width,
                      layer=layer,
                      angle_resolution=1,
                      start_angle=0,
                      theta=-90)
            radiusEff = radius
        if bendType == 'gradual':
            B1 = _gradual_bend(radius=radius,
                               width=width,
                               layer=layer,
                               start_angle=0,
                               direction='cw')
            radiusEff = B1.xsize - width / 2
        b1 = Total.add_ref(B1)
        b1.connect(port=b1.ports[1], destination=Total.ports['t1'])
        b1.move([p2[0] - p1[0] - radiusEff, 0])
        R1 = route_basic(port1=Total.ports['t1'],
                         port2=b1.ports[1],
                         layer=layer)
        R2 = route_basic(port1=b1.ports[2],
                         port2=Total.ports['t2'],
                         layer=layer)
        r1 = Total.add_ref(R1)
        r2 = Total.add_ref(R2)
        Total.add_port(name=1, port=r1.ports[1])
        Total.add_port(name=2, port=r2.ports[2])
    Total.rotate(angle=port1.orientation, center=p1)
    Total.move(origin=Total.ports['t1'], destination=port1)

    return Total
Example #22
0
def _gradual_bend(
    radius=20,
    width=1.0,
    angular_coverage=15,
    num_steps=10,
    angle_resolution=0.1,
    start_angle=0,
    direction='ccw',
    layer=0,
):
    """
    creates a 90-degree bent waveguide
    the bending radius is gradually increased until it reaches the minimum
    value of the radius at the "angular coverage" angle.
    it essentially creates a smooth transition to a bent waveguide mode.
    user can control number of steps provided.
    direction determined by start angle and cw or ccw switch
    ############
    with the default 10 "num_steps" and 15 degree coverage, effective radius is about 1.5*radius.
    """
    angular_coverage = np.deg2rad(angular_coverage)
    D = Device()

    #determines the increment in radius through its inverse from 0 to 1/r
    inc_rad = (radius**-1) / (num_steps)
    angle_step = angular_coverage / num_steps

    #construct a series of sub-arcs with equal angles but gradually decreasing bend radius
    arcs = []
    for x in xrange(num_steps):
        A = _arc(radius=1 / ((x + 1) * inc_rad),
                 width=width,
                 theta=np.rad2deg(angle_step),
                 start_angle=x * np.rad2deg(angle_step),
                 angle_resolution=angle_resolution,
                 layer=layer)
        a = D.add_ref(A)
        arcs.append(a)
        if x > 0:
            a.connect(port=1, destination=prevPort)
        prevPort = a.ports[2]
    D.add_port(name=1, port=arcs[0].ports[1])

    #now connect a regular bend for the normal curved portion
    B = _arc(radius=radius,
             width=width,
             theta=45 - np.rad2deg(angular_coverage),
             start_angle=angular_coverage,
             angle_resolution=angle_resolution,
             layer=layer)
    b = D.add_ref(B)
    b.connect(port=1, destination=prevPort)
    prevPort = b.ports[2]
    D.add_port(name=2, port=prevPort)

    #now create the overall structure
    Total = Device()

    #clone the half-curve into two objects and connect for a 90 deg bend.
    D1 = Total.add_ref(D)
    D2 = Total.add_ref(D)
    D2.reflect(p1=[0, 0], p2=[1, 1])
    D2.connect(port=2, destination=D1.ports[2])
    Total.xmin = 0
    Total.ymin = 0

    #orient to default settings...
    Total.reflect(p1=[0, 0], p2=[1, 1])
    Total.reflect(p1=[0, 0], p2=[1, 0])

    #orient to user-provided settings
    if direction == 'cw':
        Total.reflect(p1=[0, 0], p2=[1, 0])
    Total.rotate(angle=start_angle, center=Total.center)
    Total.center = [0, 0]
    Total.add_port(name=1, port=D1.ports[1])
    Total.add_port(name=2, port=D2.ports[1])

    return Total
Example #23
0
def route_manhattan180(port1, port2, bendType='circular', layer=0, radius=20):
    #this is a subroutine of route_manhattan() and should not be used by itself.
    Total = Device()
    width = port1.width
    #first map into uniform plane with normal x,y coords
    #allows each situation to be put into uniform cases of quadrants for routing.
    #this is because bends change direction and positioning.
    if port1.orientation == 0:
        p2 = [port2.midpoint[0], port2.midpoint[1]]
        p1 = [port1.midpoint[0], port1.midpoint[1]]
    if port1.orientation == 90:
        p2 = [port2.midpoint[1], -port2.midpoint[0]]
        p1 = [port1.midpoint[1], -port1.midpoint[0]]
    if port1.orientation == 180:
        p2 = [-port2.midpoint[0], -port2.midpoint[1]]
        p1 = [-port1.midpoint[0], -port1.midpoint[1]]
    if port1.orientation == 270:
        p2 = [-port2.midpoint[1], port2.midpoint[0]]
        p1 = [-port1.midpoint[1], port1.midpoint[0]]

    #create placeholder ports based on the imaginary coordinates we created
    Total.add_port(name='t1', midpoint=[0, 0], orientation=0, width=width)
    if (port1.orientation != port2.orientation):
        Total.add_port(name='t2',
                       midpoint=list(np.subtract(p2, p1)),
                       orientation=180,
                       width=width)
    else:
        Total.add_port(name='t2',
                       midpoint=list(np.subtract(p2, p1)),
                       orientation=0,
                       width=width)

    if port1.orientation == port2.orientation:
        #first quadrant target
        if (p2[1] > p1[1]) & (p2[0] > p1[0]):
            if bendType == 'circular':
                B1 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=0,
                          theta=90)
                B2 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=90,
                          theta=90)
                radiusEff = radius
            if bendType == 'gradual':
                B1 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=0,
                                   direction='ccw')
                B2 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=90,
                                   direction='ccw')
                radiusEff = B1.xsize - width / 2
            b1 = Total.add_ref(B1)
            b2 = Total.add_ref(B2)

            b1.connect(port=b1.ports[1], destination=Total.ports['t1'])
            b1.move([p2[0] - p1[0], 0])
            b2.connect(port=b2.ports[1], destination=b1.ports[2])
            b2.move([0, p2[1] - p1[1] - radiusEff * 2])
            R1 = route_basic(port1=Total.ports['t1'],
                             port2=b1.ports[1],
                             layer=layer)
            r1 = Total.add_ref(R1)
            R2 = route_basic(port1=b1.ports[2], port2=b2.ports[1], layer=layer)
            r2 = Total.add_ref(R2)
            Total.add_port(name=1, port=r1.ports[1])
            Total.add_port(name=2, port=b2.ports[2])
        #second quadrant target
        if (p2[1] > p1[1]) & (p2[0] < p1[0]):
            if bendType == 'circular':
                B1 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=0,
                          theta=90)
                B2 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=90,
                          theta=90)
                radiusEff = radius
            if bendType == 'gradual':
                B1 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=0,
                                   direction='ccw')
                B2 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=90,
                                   direction='ccw')
                radiusEff = B1.xsize - width / 2
            b1 = Total.add_ref(B1)
            b2 = Total.add_ref(B2)
            b1.connect(port=b1.ports[1], destination=Total.ports['t1'])

            b2.connect(port=b2.ports[1], destination=b1.ports[2])
            b2.move([0, p2[1] - p1[1] - radiusEff * 2])
            R1 = route_basic(port1=b1.ports[2], port2=b2.ports[1], layer=layer)
            r1 = Total.add_ref(R1)
            R2 = route_basic(port1=b2.ports[2],
                             port2=Total.ports['t2'],
                             layer=layer)
            r2 = Total.add_ref(R2)
            Total.add_port(name=1, port=b1.ports[1])
            Total.add_port(name=2, port=r2.ports[2])
        #third quadrant target
        if (p2[1] < p1[1]) & (p2[0] < p1[0]):
            if bendType == 'circular':
                B1 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=0,
                          theta=-90)
                B2 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=-90,
                          theta=-90)
                radiusEff = radius
            if bendType == 'gradual':
                B1 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=0,
                                   direction='cw')
                B2 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=-90,
                                   direction='cw')
                radiusEff = B1.xsize - width / 2
            b1 = Total.add_ref(B1)
            b2 = Total.add_ref(B2)
            b1.connect(port=b1.ports[1], destination=Total.ports['t1'])

            b2.connect(port=b2.ports[1], destination=b1.ports[2])
            b2.move([0, p2[1] - p1[1] + radiusEff * 2])
            R1 = route_basic(port1=b1.ports[2], port2=b2.ports[1], layer=layer)
            r1 = Total.add_ref(R1)
            R2 = route_basic(port1=b2.ports[2],
                             port2=Total.ports['t2'],
                             layer=layer)
            r2 = Total.add_ref(R2)
            Total.add_port(name=1, port=b1.ports[1])
            Total.add_port(name=2, port=r2.ports[2])
        #fourth quadrant target
        if (p2[1] < p1[1]) & (p2[0] > p1[0]):
            if bendType == 'circular':
                B1 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=0,
                          theta=-90)
                B2 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=-90,
                          theta=-90)
                radiusEff = radius
            if bendType == 'gradual':
                B1 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=0,
                                   direction='cw')
                B2 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=-90,
                                   direction='cw')
                radiusEff = B1.xsize - width / 2
            b1 = Total.add_ref(B1)
            b2 = Total.add_ref(B2)

            b1.connect(port=b1.ports[1], destination=Total.ports['t1'])
            b1.move([p2[0] - p1[0], 0])
            b2.connect(port=b2.ports[1], destination=b1.ports[2])
            b2.move([0, p2[1] - p1[1] + radiusEff * 2])
            R1 = route_basic(port1=Total.ports['t1'],
                             port2=b1.ports[1],
                             layer=layer)
            r1 = Total.add_ref(R1)
            R2 = route_basic(port1=b1.ports[2], port2=b2.ports[1], layer=layer)
            r2 = Total.add_ref(R2)
            Total.add_port(name=1, port=r1.ports[1])
            Total.add_port(name=2, port=b2.ports[2])

    #other port orientations are not supported:
    elif np.round(np.abs(np.mod(port1.orientation - port2.orientation, 360)),
                  3) != 180:
        raise ValueError(
            '[DEVICE] route() error: Ports do not face each other (orientations must be 180 apart)'
        )
    #otherwise, they are 180 degrees apart:
    else:
        #first quadrant target
        if (p2[1] > p1[1]) & (p2[0] > p1[0]):
            if bendType == 'circular':
                B1 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=0,
                          theta=90)
                B2 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=90,
                          theta=-90)
                radiusEff = radius
            if bendType == 'gradual':
                B1 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=0,
                                   direction='ccw')
                B2 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=90,
                                   direction='cw')
                radiusEff = B1.xsize - width / 2
            b1 = Total.add_ref(B1)
            b2 = Total.add_ref(B2)

            b1.connect(port=b1.ports[1], destination=Total.ports['t1'])
            b1.move([p2[0] - p1[0] - radiusEff * 2, 0])
            b2.connect(port=b2.ports[1], destination=b1.ports[2])
            b2.move([0, p2[1] - p1[1] - radiusEff * 2])
            R1 = route_basic(port1=Total.ports['t1'],
                             port2=b1.ports[1],
                             layer=layer)
            r1 = Total.add_ref(R1)
            R2 = route_basic(port1=b1.ports[2], port2=b2.ports[1], layer=layer)
            r2 = Total.add_ref(R2)
            Total.add_port(name=1, port=r1.ports[1])
            Total.add_port(name=2, port=b2.ports[2])
        #second quadrant target
        if (p2[1] > p1[1]) & (p2[0] < p1[0]):
            if bendType == 'circular':
                B1 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=0,
                          theta=90)
                B2 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=90,
                          theta=90)
                B3 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=180,
                          theta=-90)
                B4 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=90,
                          theta=-90)
                radiusEff = radius
            if bendType == 'gradual':
                B1 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=0,
                                   direction='ccw')
                B2 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=90,
                                   direction='ccw')
                B3 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=180,
                                   direction='cw')
                B4 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=90,
                                   direction='cw')
                radiusEff = B1.xsize - width / 2
            b1 = Total.add_ref(B1)
            b2 = Total.add_ref(B2)
            b3 = Total.add_ref(B3)
            b4 = Total.add_ref(B4)

            b1.connect(port=b1.ports[1], destination=Total.ports['t1'])

            b2.connect(port=b2.ports[1], destination=b1.ports[2])
            b2.move([0, p2[1] - p1[1] - radiusEff * 4])
            R1 = route_basic(port1=b1.ports[2], port2=b2.ports[1], layer=layer)
            r1 = Total.add_ref(R1)
            b3.connect(port=b3.ports[1], destination=b2.ports[2])
            b3.move([p2[0] - p1[0], 0])
            R2 = route_basic(port1=b2.ports[2], port2=b3.ports[1], layer=layer)
            r2 = Total.add_ref(R2)

            b4.connect(port=b4.ports[1], destination=b3.ports[2])

            Total.add_port(name=1, port=r1.ports[1])
            Total.add_port(name=2, port=b4.ports[2])
        #third quadrant target
        if (p2[1] < p1[1]) & (p2[0] < p1[0]):
            if bendType == 'circular':
                B1 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=0,
                          theta=-90)
                B2 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=-90,
                          theta=-90)
                B3 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=-180,
                          theta=90)
                B4 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=-90,
                          theta=90)
                radiusEff = radius
            if bendType == 'gradual':
                B1 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=0,
                                   direction='cw')
                B2 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=-90,
                                   direction='cw')
                B3 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=-180,
                                   direction='ccw')
                B4 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=-90,
                                   direction='ccw')
                radiusEff = B1.xsize - width / 2
            b1 = Total.add_ref(B1)
            b2 = Total.add_ref(B2)
            b3 = Total.add_ref(B3)
            b4 = Total.add_ref(B4)

            b1.connect(port=b1.ports[1], destination=Total.ports['t1'])

            b2.connect(port=b2.ports[1], destination=b1.ports[2])
            b2.move([0, p2[1] - p1[1] + radiusEff * 4])
            R1 = route_basic(port1=b1.ports[2], port2=b2.ports[1], layer=layer)
            r1 = Total.add_ref(R1)
            b3.connect(port=b3.ports[1], destination=b2.ports[2])
            b3.move([p2[0] - p1[0], 0])
            R2 = route_basic(port1=b2.ports[2], port2=b3.ports[1], layer=layer)
            r2 = Total.add_ref(R2)

            b4.connect(port=b4.ports[1], destination=b3.ports[2])

            Total.add_port(name=1, port=r1.ports[1])
            Total.add_port(name=2, port=b4.ports[2])
        #fourth quadrant target
        if (p2[1] < p1[1]) & (p2[0] > p1[0]):
            if bendType == 'circular':
                B1 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=0,
                          theta=-90)
                B2 = _arc(radius=radius,
                          width=width,
                          layer=layer,
                          angle_resolution=1,
                          start_angle=-90,
                          theta=90)
                radiusEff = radius
            if bendType == 'gradual':
                B1 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=0,
                                   direction='cw')
                B2 = _gradual_bend(radius=radius,
                                   width=width,
                                   layer=layer,
                                   start_angle=-90,
                                   direction='ccw')
                radiusEff = B1.xsize - width / 2
            b1 = Total.add_ref(B1)
            b2 = Total.add_ref(B2)

            b1.connect(port=b1.ports[1], destination=Total.ports['t1'])
            b1.move([p2[0] - p1[0] - radiusEff * 2, 0])
            b2.connect(port=b2.ports[1], destination=b1.ports[2])
            b2.move([0, p2[1] - p1[1] + radiusEff * 2])
            R1 = route_basic(port1=Total.ports['t1'],
                             port2=b1.ports[1],
                             layer=layer)
            r1 = Total.add_ref(R1)
            R2 = route_basic(port1=b1.ports[2], port2=b2.ports[1], layer=layer)
            r2 = Total.add_ref(R2)
            Total.add_port(name=1, port=r1.ports[1])
            Total.add_port(name=2, port=b2.ports[2])

    Total.rotate(angle=port1.orientation, center=p1)
    Total.move(origin=Total.ports['t1'], destination=port1)
    return Total