Esempio n. 1
0
def bezier(
    name: None = None,
    width: float = 0.5,
    control_points: List[Tuple[float, float]] = [
        (0.0, 0.0),
        (5.0, 0.0),
        (5.0, 2.0),
        (10.0, 2.0),
    ],
    t: ndarray = np.linspace(0, 1, 201),
    layer: Tuple[int, int] = LAYER.WG,
    **extrude_path_params
) -> Component:
    """ bezier bend """

    def _fmt_f(x):
        return "{:.3f}".format(x).rstrip("0").rstrip(".")

    def _fmt_cp(cps):
        return "_".join(["({},{})".format(_fmt_f(p[0]), _fmt_f(p[1])) for p in cps])

    if name is None:
        points_hash = hashlib.md5(_fmt_cp(control_points).encode()).hexdigest()
        name = "bezier_w{}_{}_{}".format(int(width * 1e3), points_hash, layer)

    c = pp.Component(name=name)
    path_points = bezier_curve(t, control_points)
    polygon_points = extrude_path(path_points, width, **extrude_path_params)
    angles = angles_deg(path_points)

    c.info["start_angle"] = angles[0]
    c.info["end_angle"] = angles[-2]

    a0 = angles[0] + 180
    a1 = angles[-2]

    a0 = snap_angle(a0)
    a1 = snap_angle(a1)

    p0 = path_points[0]
    p1 = path_points[-1]
    c.add_polygon(polygon_points, layer=layer)
    c.add_port(name="0", midpoint=p0, width=width, orientation=a0, layer=layer)
    c.add_port(name="1", midpoint=p1, width=width, orientation=a1, layer=layer)

    c.info["length"] = path_length(path_points)
    curv = curvature(path_points, t)
    c.info["min_bend_radius"] = 1 / max(np.abs(curv))
    c.info["curvature"] = curv
    c.info["t"] = t

    return c
Esempio n. 2
0
def path_length_matched_points_modify_segment(list_of_waypoints,
                                              modify_segment_i, dL0):
    if type(list_of_waypoints) != list:
        raise ValueError("list_of_waypoints should be a list, got {}".format(
            type(list_of_waypoints)))
    list_of_waypoints = [
        remove_flat_angles(waypoints) for waypoints in list_of_waypoints
    ]
    lengths = [path_length(waypoints) for waypoints in list_of_waypoints]
    L0 = max(lengths)

    N = len(list_of_waypoints[0])

    # Find how many turns there are per path
    nb_turns = [len(waypoints) - 2 for waypoints in list_of_waypoints]

    # The paths have to have the same number of turns, otherwise this algo
    # cannot path length match
    if min(nb_turns) != max(nb_turns):
        raise ValueError("Number of turns in paths have to be identical got \
        {}".format(nb_turns))

    if modify_segment_i < 0:
        modify_segment_i = modify_segment_i + N + 1

    list_new_waypoints = []

    # For each list of waypoints, modify one segment in-place
    for i, waypoints in enumerate(list_of_waypoints):
        p_s0, p_s1, p_next = waypoints[modify_segment_i - 1:modify_segment_i +
                                       2]

        p_s0 = np.array(p_s0)
        p_s1 = np.array(p_s1)

        L = lengths[i]

        # Path length compensation length
        dL = (L0 - L) / 2

        # Additional fixed length
        dL = dL + dL0

        # Modify the segment to accomodate for path length matching
        # Two cases: vertical or horizontal segment
        if _is_vertical(p_s0, p_s1):
            sx = np.sign(p_next[0] - p_s1[0])

            dx = -sx * dL
            dp = (dx, 0)
            # Sequence of displacements to apply

        elif _is_horizontal(p_s0, p_s1):
            sy = np.sign(p_next[1] - p_s1[1])

            dy = -sy * dL
            dp = (0, dy)

        waypoints[modify_segment_i - 1] = p_s0 + dp
        waypoints[modify_segment_i] = p_s1 + dp

        list_new_waypoints += [waypoints]
    return list_new_waypoints
Esempio n. 3
0
 def f(y):
     control_points = get_control_pts(x0, y)
     t = np.linspace(0, 1, 51)
     path_points = bezier_curve(t, control_points)
     return path_length(path_points) - target_bend_length
Esempio n. 4
0
def path_length_matched_points_add_waypoints(
    list_of_waypoints,
    modify_segment_i=-2,
    bend_radius=10.0,
    margin=0.5,
    dL0=0.0,
    nb_loops=1,
):
    """
    Args:
        list_of_waypoints: a list of list_of_points:
            [[p1, p2, p3,...], [q1, q2, q3,...], ...]
            - the number of turns have to be identical
                (usually means same number of points. exception is if there are
                some flat angles)

        bend_radius: used to estimate the position of new waypoints to accommodate
                    bends with a given radius

        margin: some extra space to budget for in addition to the bend radius
            in most cases, the default is fine

        dL0: distance added to all path length compensation.
            Useful is we want to add space for extra taper on all branches

        modify_segment_i: index of the segment which accomodates the new turns
            default is next to last segment

        nb_loops: number of extra loops added in the path

    returns:
        another list of waypoints where:
            - the path_lenth of each waypoints list are identical
            - the number of turns are identical

    Several types of paths won't match correctly. We do not try to handle
    all the corner cases here. If the paths are not well behaved enough,
    the input list_of_waypoints needs to be modified.

    """

    print(list_of_waypoints[0])

    if type(list_of_waypoints) != list:
        raise ValueError("list_of_waypoints should be a list, got {}".format(
            type(list_of_waypoints)))
    list_of_waypoints = [
        remove_flat_angles(waypoints) for waypoints in list_of_waypoints
    ]
    lengths = [path_length(waypoints) for waypoints in list_of_waypoints]
    L0 = max(lengths)

    N = len(list_of_waypoints[0])

    # Find how many turns there are per path
    nb_turns = [len(waypoints) - 2 for waypoints in list_of_waypoints]

    # The paths have to have the same number of turns, otherwise cannot path-length
    # match with this algorithm
    if min(nb_turns) != max(nb_turns):
        raise ValueError("Number of turns in paths have to be identical got \
        {}".format(nb_turns))

    # To have flexibility in the path length, we need to add 4 bends
    """
    One path has to be converted in this way:

                      ----
                      |  |
                      |  |  This length is adjusted to make all path with the same length
                      |  |
    --------  ===> ---|  |---
    """

    # Get the points for the segment we need to modify
    a = margin + bend_radius
    if modify_segment_i < 0:
        modify_segment_i = modify_segment_i + N + 1
    list_new_waypoints = []

    for i, waypoints in enumerate(list_of_waypoints):
        p_s0, p_s1, p_next = waypoints[modify_segment_i - 2:modify_segment_i +
                                       1]

        p_s1 = np.array(p_s1)

        L = lengths[i]

        # Path length compensation length
        dL = (L0 - L) / (2 * nb_loops)

        # Additional fixed length
        dL = dL + dL0

        # Generate a new sequence of points which will replace this segment
        # Two cases: vertical or horizontal segment
        if _is_vertical(p_s0, p_s1):
            sx = np.sign(p_next[0] - p_s1[0])
            sy = np.sign(p_s1[1] - p_s0[1])

            dx = sx * (2 * a + dL)
            dy = sy * 2 * a

            # First new point to insert
            q0 = p_s1 + (0, -2 * nb_loops * dy)

            # Sequence of displacements to apply
            seq = [(dx, 0), (0, dy), (-dx, 0), (0, dy)] * nb_loops
            seq.pop()  # Remove last point to avoid flat angle with next point

        elif _is_horizontal(p_s0, p_s1):
            sy = np.sign(p_next[1] - p_s1[1])
            sx = np.sign(p_s1[0] - p_s0[0])

            dx = sx * 2 * a
            dy = sy * (2 * a + dL)

            q0 = p_s1 + (-2 * dx * nb_loops, 0)
            # Sequence of displacements to apply
            seq = [(0, dy), (dx, 0), (0, -dy), (dx, 0)] * nb_loops
            seq.pop()  # Remove last point to avoid flat angle with next point

        # Generate points to insert
        qs = [q0]
        for dp in seq:
            qs += [qs[-1] + dp]

        # print()
        # print(nb_loops)
        # for q in qs:
        # print(q)
        # print()
        inserted_points = np.stack(qs, axis=0)
        waypoints = np.array(waypoints)

        # Insert the points
        new_points = np.vstack([
            waypoints[:modify_segment_i - 1],
            inserted_points,
            waypoints[modify_segment_i - 1:],
        ])
        list_new_waypoints += [new_points]

    return list_new_waypoints
Esempio n. 5
0
def bezier(
    name: None = None,
    width: float = 0.5,
    control_points: List[Tuple[float, float]] = [
        (0.0, 0.0),
        (5.0, 0.0),
        (5.0, 2.0),
        (10.0, 2.0),
    ],
    t: ndarray = np.linspace(0, 1, 201),
    layer: Tuple[int, int] = LAYER.WG,
    with_manhattan_facing_angles: bool = True,
    spike_length: float = 0.0,
    start_angle: Optional[int] = None,
    end_angle: Optional[int] = None,
    grid: float = 0.001,
) -> Component:
    """Bezier bend
    We avoid autoname control_points and t spacing

    Args:
        width: waveguide width
        control_points: list of points
        t: 1D array of points varying between 0 and 1
        layer: layer
    """
    def format_float(x):
        return "{:.3f}".format(x).rstrip("0").rstrip(".")

    def _fmt_cp(cps):
        return "_".join(
            [f"({format_float(p[0])},{format_float(p[1])})" for p in cps])

    if name is None:
        points_hash = hashlib.md5(_fmt_cp(control_points).encode()).hexdigest()
        name = f"bezier_w{int(width*1e3)}_{points_hash}_{layer[0]}_{layer[1]}"

    c = pp.Component(name=name)
    c.ignore.add("control_points")
    c.ignore.add("t")
    path_points = bezier_curve(t, control_points)
    polygon_points = extrude_path(
        path_points,
        width=width,
        with_manhattan_facing_angles=with_manhattan_facing_angles,
        spike_length=spike_length,
        start_angle=start_angle,
        end_angle=end_angle,
        grid=grid,
    )
    angles = angles_deg(path_points)

    c.info["start_angle"] = pp.drc.snap_to_1nm_grid(angles[0])
    c.info["end_angle"] = pp.drc.snap_to_1nm_grid(angles[-2])

    a0 = angles[0] + 180
    a1 = angles[-2]

    a0 = snap_angle(a0)
    a1 = snap_angle(a1)

    p0 = path_points[0]
    p1 = path_points[-1]
    c.add_polygon(polygon_points, layer=layer)
    c.add_port(name="0", midpoint=p0, width=width, orientation=a0, layer=layer)
    c.add_port(name="1", midpoint=p1, width=width, orientation=a1, layer=layer)

    curv = curvature(path_points, t)
    c.info["length"] = pp.drc.snap_to_1nm_grid(path_length(path_points))
    c.info["min_bend_radius"] = pp.drc.snap_to_1nm_grid(1 / max(np.abs(curv)))
    # c.info["curvature"] = curv
    # c.info["t"] = t
    return c