Example #1
0
  def test_touches(self):

    p1 = pya.Polygon(pya.Box(10, 20, 30, 40))
    self.assertEqual(p1.touches(pya.Polygon(pya.Box(30, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.Polygon(pya.Box(31, 20, 40, 50))), False)
    self.assertEqual(p1.touches(pya.Polygon(pya.Box(29, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.SimplePolygon(pya.Box(30, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.SimplePolygon(pya.Box(31, 20, 40, 50))), False)
    self.assertEqual(p1.touches(pya.SimplePolygon(pya.Box(29, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.Box(30, 20, 40, 50)), True)
    self.assertEqual(p1.touches(pya.Box(31, 20, 40, 50)), False)
    self.assertEqual(p1.touches(pya.Box(29, 20, 40, 50)), True)
    self.assertEqual(p1.touches(pya.Edge(30, 20, 40, 50)), True)
    self.assertEqual(p1.touches(pya.Edge(31, 20, 40, 50)), False)
    self.assertEqual(p1.touches(pya.Edge(29, 20, 40, 50)), True)

    p1 = pya.SimplePolygon(pya.Box(10, 20, 30, 40))
    self.assertEqual(p1.touches(pya.Polygon(pya.Box(30, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.Polygon(pya.Box(31, 20, 40, 50))), False)
    self.assertEqual(p1.touches(pya.Polygon(pya.Box(29, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.SimplePolygon(pya.Box(30, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.SimplePolygon(pya.Box(31, 20, 40, 50))), False)
    self.assertEqual(p1.touches(pya.SimplePolygon(pya.Box(29, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.Box(30, 20, 40, 50)), True)
    self.assertEqual(p1.touches(pya.Box(31, 20, 40, 50)), False)
    self.assertEqual(p1.touches(pya.Box(29, 20, 40, 50)), True)
    self.assertEqual(p1.touches(pya.Edge(30, 20, 40, 50)), True)
    self.assertEqual(p1.touches(pya.Edge(31, 20, 40, 50)), False)
    self.assertEqual(p1.touches(pya.Edge(29, 20, 40, 50)), True)

    p1 = pya.DPolygon(pya.DBox(10, 20, 30, 40))
    self.assertEqual(p1.touches(pya.DPolygon(pya.DBox(30, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.DPolygon(pya.DBox(31, 20, 40, 50))), False)
    self.assertEqual(p1.touches(pya.DPolygon(pya.DBox(29, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.DSimplePolygon(pya.DBox(30, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.DSimplePolygon(pya.DBox(31, 20, 40, 50))), False)
    self.assertEqual(p1.touches(pya.DSimplePolygon(pya.DBox(29, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.DBox(30, 20, 40, 50)), True)
    self.assertEqual(p1.touches(pya.DBox(31, 20, 40, 50)), False)
    self.assertEqual(p1.touches(pya.DBox(29, 20, 40, 50)), True)
    self.assertEqual(p1.touches(pya.DEdge(30, 20, 40, 50)), True)
    self.assertEqual(p1.touches(pya.DEdge(31, 20, 40, 50)), False)
    self.assertEqual(p1.touches(pya.DEdge(29, 20, 40, 50)), True)

    p1 = pya.DSimplePolygon(pya.DBox(10, 20, 30, 40))
    self.assertEqual(p1.touches(pya.DPolygon(pya.DBox(30, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.DPolygon(pya.DBox(31, 20, 40, 50))), False)
    self.assertEqual(p1.touches(pya.DPolygon(pya.DBox(29, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.DSimplePolygon(pya.DBox(30, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.DSimplePolygon(pya.DBox(31, 20, 40, 50))), False)
    self.assertEqual(p1.touches(pya.DSimplePolygon(pya.DBox(29, 20, 40, 50))), True)
    self.assertEqual(p1.touches(pya.DBox(30, 20, 40, 50)), True)
    self.assertEqual(p1.touches(pya.DBox(31, 20, 40, 50)), False)
    self.assertEqual(p1.touches(pya.DBox(29, 20, 40, 50)), True)
    self.assertEqual(p1.touches(pya.DEdge(30, 20, 40, 50)), True)
    self.assertEqual(p1.touches(pya.DEdge(31, 20, 40, 50)), False)
    self.assertEqual(p1.touches(pya.DEdge(29, 20, 40, 50)), True)
Example #2
0
  def test_extractRad(self):

    ex = pya.SimplePolygon().extract_rad()
    self.assertEqual(repr(ex), "[]")

    sp = pya.SimplePolygon.from_s("(0,0;0,200000;300000,200000;300000,100000;100000,100000;100000,0)")

    sp = sp.round_corners(10000, 5000, 200)
    ex = sp.extract_rad()

    self.assertEqual(ex, [pya.SimplePolygon.from_s("(0,0;0,200000;300000,200000;300000,100000;100000,100000;100000,0)"), 10000.0, 5000.0, 200])

    ex = pya.Polygon().extract_rad()
    self.assertEqual(ex, [])

    sp = pya.Polygon.from_s("(0,0;0,300000;300000,300000;300000,0/100000,100000;200000,100000;200000,200000;100000,200000)")

    sp = sp.round_corners(10000, 5000, 200)
    ex = sp.extract_rad()

    self.assertEqual(ex, [pya.Polygon.from_s("(0,0;0,300000;300000,300000;300000,0/100000,100000;200000,100000;200000,200000;100000,200000)"), 10000.0, 5000.0, 200])

    # double coords too ...

    ex = pya.DSimplePolygon().extract_rad()
    self.assertEqual(ex, [])

    sp = pya.DSimplePolygon.from_s("(0,0;0,200000;300000,200000;300000,100000;100000,100000;100000,0)")

    sp = sp.round_corners(10000, 5000, 200)
    ex = sp.extract_rad()

    # round to integers for better comparison
    
    ex[0] = pya.SimplePolygon(ex[0])
    self.assertEqual(ex, [pya.SimplePolygon.from_s("(0,0;0,200000;300000,200000;300000,100000;100000,100000;100000,0)"), 10000.0, 5000.0, 200])

    ex = pya.DPolygon().extract_rad()
    self.assertEqual(ex, [])

    sp = pya.DPolygon.from_s("(0,0;0,300000;300000,300000;300000,0/100000,100000;200000,100000;200000,200000;100000,200000)")

    sp = sp.round_corners(10000, 5000, 200)
    ex = sp.extract_rad()

    # round to integers for better comparison
    ex[0] = pya.Polygon(ex[0])

    self.assertEqual(ex, [pya.Polygon.from_s("(0,0;0,300000;300000,300000;300000,0/100000,100000;200000,100000;200000,200000;100000,200000)"), 10000.0, 5000.0, 200])
Example #3
0
    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 = pya.DPoint(1, 0)
        ey = rotate90(ex)

        polygon_dpoints_transformed = [center + p.x *
                                       ex + p.y * ey for p in self.each_point()]
        self.assign(pya.DSimplePolygon(polygon_dpoints_transformed))
        return self
Example #4
0
def layout_circle(cell, layer, center, r):
    """
    function to produce the layout of a filled circle
    cell: layout cell to place the layout
    layer: which layer to use
    center: origin DPoint
    r: radius
    w: waveguide width
    theta_start, theta_end: angle in radians
    units in microns
    optimal sampling
    """

    arc_function = lambda t: np.array([center.x + r * np.cos(t), center.y + r * np.sin(t)])
    t, coords = sample_function(arc_function,
                                [0, 2 * np.pi - 0.001], tol=0.002 / r)

    dbu = cell.layout().dbu
    dpoly = pya.DSimplePolygon([pya.DPoint(x, y) for x, y in zip(*coords)])
    cell.shapes(layer).insert(dpoly.to_itype(dbu))
Example #5
0
    def clip(self, x_bounds=(-np.inf, np.inf), y_bounds=(-np.inf, np.inf)):
        ''' Clips the polygon at four possible boundaries.
        The boundaries are tuples based on absolute coordinates and cartesian axes.
        This method is very powerful when used with transform_and_rotate.
        '''
        # Add points exactly at the boundary, so that the filter below works.
        x_bounds = (np.min(x_bounds), np.max(x_bounds))
        y_bounds = (np.min(y_bounds), np.max(y_bounds))

        check_within_bounds = lambda p: x_bounds[0] <= p.x and x_bounds[1] >= p.x and \
            y_bounds[0] <= p.y and y_bounds[1] >= p.y

        def intersect_left_boundary(p1, p2, x_bounds, y_bounds):
            left_most, right_most = (p1, p2) if p1.x < p2.x else (p2, p1)
            bottom_most, top_most = (p1, p2) if p1.y < p2.y else (p2, p1)
            if left_most.x < x_bounds[0]:
                # intersection only if right_most crosses x_bound[0]
                if right_most.x > x_bounds[0]:
                    # outside the box, on the left
                    y_intersect = np.interp(x_bounds[0], [left_most.x, right_most.x], [
                                            left_most.y, right_most.y])
                    if y_bounds[0] < y_intersect and y_bounds[1] > y_intersect:
                        return pya.DPoint(float(x_bounds[0]), float(y_intersect))
            return None

        def intersect(p1, p2, x_bounds, y_bounds):
            intersect_list = list()
            last_intersect = None

            def rotate_bounds90(x_bounds, y_bounds, i_times):
                for i in range(i_times):
                    x_bounds, y_bounds = (-y_bounds[1], -y_bounds[0]), (x_bounds[0], x_bounds[1])
                return x_bounds, y_bounds

            for i in range(4):
                p1i, p2i = rotate(p1, i * pi / 2), rotate(p2, i * pi / 2)
                x_boundsi, y_boundsi = rotate_bounds90(x_bounds, y_bounds, i)
                p = intersect_left_boundary(p1i, p2i, x_boundsi, y_boundsi)
                if p is not None:
                    last_intersect = i
                    intersect_list.append(rotate(p, -i * pi / 2))
            return intersect_list, last_intersect

        polygon_dpoints_clipped = list()
        polygon_dpoints = list(self.each_point())

        def boundary_vertex(edge_from, edge_to):
            # left edge:0, top edge:1 etc.
            # returns the vertex between two edges
            assert abs(edge_from - edge_to) == 1
            if edge_from % 2 == 0:
                vertical_edge = edge_from
                horizontal_edge = edge_to
            else:
                vertical_edge = edge_to
                horizontal_edge = edge_from
            x = x_bounds[(vertical_edge // 2) % 2]
            y = y_bounds[((horizontal_edge - 1) // 2) % 2]
            return pya.DPoint(x, y)

        # Rotate point list so we can start from a point inside
        # (helps the boundary_vertex algorithm)
        for idx, point in enumerate(polygon_dpoints):
            if check_within_bounds(point):
                break
        else:
            # polygon was never within bounds
            # this can only happen if boundaries are finite
            # return boundary vertices
            boundary_vertices = [boundary_vertex(i, i - 1) for i in range(4, 0, -1)]
            self.assign(pya.DSimplePolygon(boundary_vertices))
            return self

        idx += 1  # make previous_point below already be inside
        polygon_dpoints = polygon_dpoints[idx:] + polygon_dpoints[:idx]

        previous_point = polygon_dpoints[-1]
        previous_intersect = None
        for point in polygon_dpoints:
            # compute new intersecting point and add to list
            intersected_points, last_intersect = intersect(
                previous_point, point, x_bounds, y_bounds)
            if previous_intersect is not None and last_intersect is not None and \
                    last_intersect != previous_intersect:
                if check_within_bounds(point):
                    # this means that we are entering the box at a different edge
                    # need to add the edge points

                    # this assumes a certain polygon orientation
                    # assume points go counterlockwise, which means that
                    # from edge 0 to 2, it goes through 3
                    i = previous_intersect
                    while i % 4 != last_intersect:
                        polygon_dpoints_clipped.append(boundary_vertex(i, i - 1))
                        i = i - 1
            polygon_dpoints_clipped.extend(intersected_points)
            if check_within_bounds(point):
                polygon_dpoints_clipped.append(point)
            previous_point = point
            if last_intersect is not None:
                previous_intersect = last_intersect
        self.assign(pya.DSimplePolygon(polygon_dpoints_clipped))
        return self
Example #6
0
def layout_waveguide_angle(cell, layer, points_list, width, angle):
    """ Lays out a waveguide (or trace) with a certain width along
    given points and with fixed orientation at all points.

    This is very useful for laying out Bezier curves with or without adiabatic tapers.

    Args:
        cell: cell to place into
        layer: layer to place into. It is done with cell.shapes(layer).insert(pya.Polygon)
        points_list: list of pya.DPoint (at least 2 points)
        width (microns): constant or list. If list, then it has to have the same length as points
        angle (degrees)
    """
    if len(points_list) < 2:
        raise NotImplemented("ERROR: points_list too short")
        return

    def norm(self):
        return sqrt(self.x**2 + self.y**2)

    try:
        if len(width) == len(points_list):
            width_iterator = iter(width)
        elif len(width) == 2:
            # assume width[0] is initial width and
            # width[1] is final width
            # interpolate with points_list
            L = curve_length(points_list)
            distance = 0
            widths_list = [width[0]]
            widths_func = lambda t: (1 - t) * width[0] + t * width[1]
            old_point = points_list[0]
            for point in points_list[1:]:
                distance += norm(point - old_point)
                old_point = point
                widths_list.append(widths_func(distance / L))
            width_iterator = iter(widths_list)
        else:
            width_iterator = repeat(width[0])
    except TypeError:
        width_iterator = repeat(width)
    finally:
        points_iterator = iter(points_list)

    theta = angle * pi / 180

    points_low = list()
    points_high = list()

    point_width_list = list(zip(points_iterator, width_iterator))
    N = len(point_width_list)

    for i in range(0, N):
        point, width = point_width_list[i]
        point_high = (point + 0.5 * width *
                      pya.DPoint(cos(theta + pi / 2), sin(theta + pi / 2)))
        points_high.append(point_high)
        point_low = (point + 0.5 * width *
                     pya.DPoint(cos(theta - pi / 2), sin(theta - pi / 2)))
        points_low.append(point_low)

    polygon_points = points_high + list(reversed(points_low))

    poly = pya.DSimplePolygon(polygon_points)
    cell.shapes(layer).insert(poly)