예제 #1
0
def curve_length(curve, t0=0, t1=1):
    """ Computes the total length of a curve.

    Args:
        curve: list of Points, or
            parametric function of points, to be computed from t0 to t1.
    """
    # TODO possible bug: if the curve is a loop, it will return 0 (BAD)
    if isinstance(curve, list):
        # assuming curve is a list of points
        scale = (curve[-1] - curve[0]).norm()
        if scale > 0:
            coords = np.array([[point.x, point.y] for point in curve]).T
            dp = np.diff(coords, axis=-1)
            ds = np.sqrt((dp**2).sum(axis=0))
            return ds.sum()
        else:
            return 0
    else:
        # assuming curve is a function.
        curve_func = curve
        scale = (curve_func(t1) - curve_func(t0)).norm()
        if scale > 0:
            coords = lambda t: np.array([curve_func(t).x, curve_func(t).y])
            _, sampled_coords = sample_function(
                coords, [t0, t1], tol=0.0001 / scale,
                min_points=100)  # 1000 times more precise than the scale
            dp = np.diff(sampled_coords, axis=-1)
            ds = np.sqrt((dp**2).sum(axis=0))
            return ds.sum()
        else:
            return 0
예제 #2
0
    def bezier_optimal(P0, P3, *args, **kwargs):
        """ If inside KLayout, return computed list of KLayout points.
        """
        P0 = _Point(P0.x, P0.y)
        P3 = _Point(P3.x, P3.y)
        scale = (P3 - P0).norm()  # rough length.
        # if scale > 1000:  # if in nanometers, convert to microns
        #     scale /= 1000
        # This function returns a np.array of Points.
        # We need to convert to array of Point coordinates
        new_bezier_line = _bezier_optimal_pure(P0, P3, *args, **kwargs)
        bezier_point_coordinates = lambda t: np.array(
            [new_bezier_line(t).x, new_bezier_line(t).y])

        t_sampled, bezier_point_coordinates_sampled = sample_function(
            bezier_point_coordinates, [0, 1],
            tol=0.005 / scale)  # tol about 5 nm

        # The following adds two points right after the first and before the last point
        # to guarantee that the first edge of the path goes out in the direction
        # of the 'port'.

        insert_at = np.argmax(0.001 / scale < t_sampled)
        t_sampled = np.insert(t_sampled, insert_at, 0.001 / scale)
        bezier_point_coordinates_sampled = np.insert(
            bezier_point_coordinates_sampled,
            insert_at,
            bezier_point_coordinates(0.001 / scale),
            axis=1,
        )  # add a point right after the first one
        insert_at = np.argmax(1 - 0.001 / scale < t_sampled)
        # t_sampled = np.insert(t_sampled, insert_at, 1 - 0.001 / scale)
        bezier_point_coordinates_sampled = np.insert(
            bezier_point_coordinates_sampled,
            insert_at,
            bezier_point_coordinates(1 - 0.001 / scale),
            axis=1,
        )  # add a point right before the last one
        # bezier_point_coordinates_sampled = \
        #     np.append(bezier_point_coordinates_sampled, np.atleast_2d(bezier_point_coordinates(1 + .001 / scale)).T,
        #               axis=1)  # finish the waveguide a little bit after

        return [
            pya.DPoint(x, y)
            for (x, y) in zip(*(bezier_point_coordinates_sampled))
        ]
예제 #3
0
    def get_points(self):
        from math import atan2, pi

        P1, C, P2 = self.P1, self.C, self.P2

        r = (P2 - C).norm()

        theta_start = atan2((P1 - C).y, (P1 - C).x)
        theta_end = atan2((P2 - C).y, (P2 - C).x)
        if self.ccw:
            theta_end = (theta_end - theta_start) % (2 * pi) + theta_start
        else:
            theta_start = (theta_start - theta_end) % (2 * pi) + theta_end
            theta_start, theta_end = theta_end, theta_start

        arc_function = lambda t: np.array([r * np.cos(t), r * np.sin(t)])

        # in the function below, theta_start must be smaller than theta_end
        t, coords = sample_function(arc_function, [theta_start, theta_end],
                                    tol=0.002 / r)

        # This yields a better polygon
        # The idea is to place a point right after the first one, to
        # make sure the arc starts in the right direction
        insert_at = np.argmax(theta_start + 0.001 <= t)
        t = np.insert(t, insert_at, theta_start + 0.001)
        coords = np.insert(coords,
                           insert_at,
                           arc_function(theta_start + 0.001),
                           axis=1)
        insert_at = np.argmax(theta_end - 0.001 <= t)
        coords = np.insert(coords,
                           insert_at,
                           arc_function(theta_end - 0.001),
                           axis=1)  # finish the waveguide a little bit after

        # create original waveguide poligon prior to clipping and rotation
        dpoints_list = [C + kdb.DPoint(x, y) for x, y in zip(*coords)]
        if not self.ccw:
            dpoints_list = list(reversed(dpoints_list))
        return dpoints_list