Exemplo n.º 1
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
Exemplo n.º 2
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
Exemplo n.º 3
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
Exemplo n.º 4
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