コード例 #1
0
def layout_box(cell, layer, point1, point3, ex):
    """ Lays out a box

    Args:
        point1: bottom-left point
        point3: top-right point

    """

    ey = rotate90(ex)
    polygon = box(point1, point3, ex, ey)
    insert_shape(cell, layer, polygon)
    return polygon
コード例 #2
0
    def origin_ex_ey(self, multiple_of_90=False):  # pylint: disable=unused-argument
        EX = kdb.DVector(1, 0)
        cp = self.get_cell_params()
        origin = kdb.DPoint(0, 0)
        # if 'angle_ex' not in cp.__dict__:
        #     cp.angle_ex = 0
        if multiple_of_90:
            if cp.angle_ex % 90 != 0:
                raise RuntimeError("Specify an angle multiple of 90 degrees")

        from math import pi

        ex = rotate(EX, cp.angle_ex * pi / 180)
        ey = rotate90(ex)
        return origin, ex, ey
コード例 #3
0
def layout_rectangle(cell, layer, center, width, height, ex):
    """ Lays out a rectangle

    Args:
        center: pya.DPoint (um units)
        width: float (um units)
        height: float (um unit)
        ex: orientation

    """

    ey = rotate90(ex)

    shape = rectangle(center, width, height, ex, ey)
    insert_shape(cell, layer, shape)
    return shape
コード例 #4
0
    def draw(self, cell, layer):
        """ Draws this port on cell's layer using klayout.db"""
        if self.name.startswith("el"):
            pin_length = self.width
        else:
            # port is optical
            pin_length = max(2, self.width / 10)

        ex = self.direction

        # Place a Path around the port pointing towards its exit
        port_path = kdb.DPath(
            [
                self.position - 0.5 * pin_length * ex,
                self.position + 0.5 * pin_length * ex,
            ],
            self.width,
        )
        cell.shapes(layer).insert(port_path)

        # Place a small arrow around the tip of the port
        from zeropdk.layout.geometry import rotate90

        ey = rotate90(ex)
        port_tip = kdb.DSimplePolygon(
            [
                self.position + 0.5 * pin_length * ex,
                self.position + 0.4 * pin_length * ex + 0.1 * pin_length * ey,
                self.position + 0.4 * pin_length * ex - 0.1 * pin_length * ey,
            ]
        )
        cell.shapes(layer).insert(port_tip)
        # pin_rectangle = rectangle(self.position, self.width,
        #                           pin_length, ex, ey)
        # cell.shapes(layer).insert(pin_rectangle)

        # Place a text object annotating the name of the port
        cell.shapes(layer).insert(
            kdb.DText(
                self.name,
                kdb.DTrans(kdb.DTrans.R0, self.position.x, self.position.y),
                min(pin_length, 20),
                0,
            )
        )

        return self
コード例 #5
0
ファイル: polygon.py プロジェクト: lightwave-lab/zeropdk
        def transform_and_rotate(self, center, ex=None):
            """Translates the polygon by 'center' and rotates by the 'ex' orientation.

            Example: if current polygon is a unit square with bottom-left corner at (0,0),
            then square.transform_and_rotate(DPoint(0, 1), DVector(0, 1)) will
            rotate the square by 90 degrees and translate it by 1 y-unit.
            The new square's bottom-left corner will be at (-1, 1).
            """
            if ex is None:
                ex = backend.DVector(1, 0)
            ey = rotate90(ex)

            polygon_dpoints_transformed = [
                center + p.x * ex + p.y * ey for p in self.each_point()
            ]
            self.assign(_SimplePolygon(polygon_dpoints_transformed))
            return self
コード例 #6
0
def layout_square(cell, layer, center, width, ex=None):
    """ Lays out a square in a layer

    Args:
        center: pya.DPoint (um units)
        width: float (um units)
        ex: orientation

    """

    if ex is None:
        ex = pya.DPoint(1, 0)
    ey = rotate90(ex)

    shape = square(center, width, ex, ey)
    insert_shape(cell, layer, shape)
    return shape
コード例 #7
0
ファイル: routing.py プロジェクト: lightwave-lab/zeropdk
def connect_ports_L(cell, cplayer, ports_from, ports_to, ex):
    """ Connects ports ports_from to ports_to, always leaving vertically"""

    ey = rotate90(ex)
    for port_from, port_to in zip(ports_from, ports_to):
        assert port_from.direction == ey or port_from.direction == -ey
        o_y = ey if port_to.position * ey > port_from.position * ey else -ey
        o_x = ex if port_to.position * ex > port_from.position * ex else -ex

        middle_point = manhattan_intersection(port_from.position,
                                              port_to.position, ex)
        layout_waveguide(
            cell,
            ensure_layer(cell.layout(), cplayer),
            [port_from.position, middle_point + port_to.width * 0.5 * o_y],
            port_from.width,
        )
        layout_waveguide(
            cell,
            ensure_layer(cell.layout(), cplayer),
            [middle_point - port_from.width * 0.5 * o_x, port_to.position],
            port_to.width,
        )
コード例 #8
0
ファイル: routing.py プロジェクト: lightwave-lab/zeropdk
def common_layout_manhattan_traces(cell,
                                   layer1,
                                   layer2,
                                   layervia,
                                   via_cell_placer,
                                   path,
                                   ex,
                                   initiate_with_via=False):
    """Lays out a manhattan trace, potentially with vias

    Args:
        layer1 and layer2 are given to layout.LayerInfo(layer), generally
            layer2 is on top
        via_cell_placer: returns a cell when called with
            via_cell_placer(parent_cell, pya.DPoint origin, width, layer1, layer2, layervia, ex)
        path: list of tuples containing necessary info ((x, y) or pya.DPoint, layer, width)

    Returns:
        path

    Algorithm places a via when there is a change of layers. To terminate with a via,
    have the last layer be different than the penultimate one.
    """

    assert isinstance(ex, (pya.DPoint, pya.DVector))
    ey = rotate90(ex)

    first_point, _, first_width = path[0]
    if initiate_with_via:
        via_cell_placer(cell, first_point, first_width, layer1, layer2,
                        layervia, ex)

    points_list = list()
    widths_list = list()
    _, previous_layer, _ = path[0]
    layout = cell.layout()

    for point, layer, width in path:
        if isinstance(point, tuple):  # point are (x, y) coordinates
            x, y = point
            point = x * ex + y * ey
        else:
            assert isinstance(point, (pya.DPoint, pya.DVector))
            if isinstance(point, pya.DVector):
                point = pya.DPoint(point)

        if layer == previous_layer:
            points_list.append(point)  # store points
            widths_list.append(width)
        else:  # time to place a via and layout
            points_list.append(point)
            widths_list.append(width)
            layout_waveguide(
                cell,
                ensure_layer(layout, previous_layer),
                points_list,
                widths_list,
                smooth=True,
            )

            via_cell_placer(cell, point, width, layer1, layer2, layervia, ex)

            # delete all but the last point
            del points_list[:-1]
            del widths_list[:-1]
        previous_layer = layer

    # layout last trace
    if len(points_list) >= 2:
        layout_waveguide(
            cell,
            ensure_layer(layout, previous_layer),
            points_list,
            widths_list,
            smooth=True,
        )

    return path
コード例 #9
0
ファイル: routing.py プロジェクト: lightwave-lab/zeropdk
def append_Z_trace_vertical(path,
                            new_point,
                            height,
                            ex,
                            middle_layer=None,
                            middle_taper=False):
    """Adds new_point to the path list plus TWO Z or S manhattan interesections.
    Args:
        path: list of tuples containing necessary info (pya.DPoint, layer, width)
        new_point: tuple ((x, y) or pya.DPoint, layer, width)
        height: y-coordinate of where to place the inner point,
            from 0 to abs(new_point.y - path.y)
        ex: orientation of ports
        middle_layer (optional): layer of middle trace
        middle_taper (default False): Adds a middle point in the Z-shaped trace attempting to avoid collisions and DRC errors.
    """

    assert len(path) > 0

    ey = rotate90(ex)

    P0, l0, w0 = path[-1]
    P3, l3, w3 = new_point

    height = abs(height)
    # assert height <= abs(P0 * ey - P3 * ey)

    # Invert sign of height if P3 is below P0
    if P3 * ey < P0 * ey:
        height = -height

    P1 = P0 + height * ey
    P2 = P1 * ey * ey + P3 * ex * ex

    # selecting middle_layer
    if middle_layer is None:
        l1, l2 = l0, l3
    else:
        l1 = l2 = middle_layer

    # lmid defined below

    # selecting middle widths
    w1, w2 = w0, w3
    if (P2 - P1).norm() <= w1 + w2:
        # w1 = w2 = min(w1, w2)
        middle_taper = False  # middle taper when points are that close looks weird
    if w1 < w2:
        wmid = w1
        lmid = l1
    else:
        wmid = w2
        lmid = l2

    path.append((P1, l1, w1))

    # move P2 a little bit to avoid acute corners
    delta_w = abs(w2 - w1) / 2
    if P3 * ey < P0 * ey:
        delta_w = -delta_w
    P2 += delta_w * ey

    Pmid = (P1 + P2) / 2

    if (P1 - P2).norm() <= max(w1, w2):
        if (P3 - P2) * ey > max(w1, w2) * 3:
            path.append((P2 + ey * max(w1, w2) * 3, l2, w2))
        else:
            path.append((P3 + ey * max(w1, w2) * 0.2, l3, w3))
    else:
        if middle_taper:
            path.append((Pmid, lmid, wmid))
        path.append((P2, l2, w2))
    path.append(new_point)
    return path
コード例 #10
0
ファイル: routing.py プロジェクト: lightwave-lab/zeropdk
def compute_paths_from_clusters(ports_clusters,
                                layer,
                                ex,
                                pitch=None,
                                middle_taper=False,
                                initial_height=0):
    """
    Args:
        - middle_taper: Adds a middle point in the Z-shaped trace attempting to avoid collisions and DRC errors.
    provide a pitch for optical waveguides. electrical waveguides are figured
    out automatically.
    path: list of tuples containing necessary info (pya.DPoint, layer, width)
    """

    Z = 0
    S = 1
    ey = rotate90(ex)

    paths = []

    for ports_cluster, orientation in ports_clusters:
        assert orientation in (Z, S)

        # start from the lowest height Z trace
        height = initial_height
        if orientation == S:
            ports_iterator = list(iter(ports_cluster))
        elif orientation == Z:
            ports_iterator = list(reversed(ports_cluster))

        is_to_top = is_to_bottom = False
        # check which row is on the top:
        for port_from, port_to in ports_iterator:
            if (port_to.position - port_from.position) * ey > 0:
                is_to_top = True or is_to_top
            else:
                is_to_bottom = True or is_to_bottom

        assert not (
            is_to_bottom and is_to_top
        ), "There must be a line dividing the top and bottom port rows. Maybe you are using the wrong ex argument?"

        if is_to_top:
            offset_port_from = max(
                [port_from.position * ey for port_from, _ in ports_iterator])
        else:
            offset_port_from = min(
                [port_from.position * ey for port_from, _ in ports_iterator])

        paths_cluster = []
        for port_from, port_to in ports_iterator:

            # # Make port_from be the one with largest width
            # if port_from.width < port_to.width:
            #     port_from, port_to = port_to, port_from

            P0 = port_from.position  # + port_from.direction * port_from.width / 2
            P3 = port_to.position  # + port_to.direction * port_to.width / 2

            if pitch is None:
                new_pitch = max(port_from.width, port_to.width) * 1.5
            else:
                new_pitch = max(max(port_from.width, port_to.width), pitch)

            height += new_pitch
            new_height = height + abs(offset_port_from - P0 * ey)
            paths_cluster.append(
                append_Z_trace_vertical(
                    [(P0, layer, port_from.width)],
                    (P3, layer, port_to.width),
                    new_height,
                    ex,
                    middle_taper=middle_taper,
                ))
        if orientation == S:
            paths.extend(paths_cluster)
        elif orientation == Z:
            paths.extend(reversed(paths_cluster))
    return paths