def gen_sref(structure, rotation_angle, x_reflection, port_name, position): """ place sref of `port_name` of `structure` at `position` # Keep this convention, otherwise phidl port transform won't work # 1 ) Mirror # 2 ) Rotate # 3 ) Move """ position = np.array(position) if port_name is None: port_position = np.array([0, 0]) else: port_position = structure.ports[port_name].midpoint device_ref = pp.ComponentReference(device=structure, origin=(0, 0)) if x_reflection: # Vertical mirror: Reflection across x-axis y0 = port_position[1] device_ref.reflect(p1=(0, y0), p2=(1, y0)) device_ref.rotate(rotation_angle, center=port_position) device_ref.move(port_position, position) return device_ref
def gen_sref( structure: Component, rotation_angle: int, x_reflection: bool, port_name: str, position: ndarray, ) -> ComponentReference: """Place reference of `port_name` of `structure` at `position`. Keep this convention, otherwise phidl port transform won't work - 1 Mirror - 2 Rotate - 3 Move """ position = np.array(position) if port_name is None: port_position = np.array([0, 0]) else: port_position = structure.ports[port_name].midpoint ref = pp.ComponentReference(component=structure, origin=(0, 0)) if x_reflection: # Vertical mirror: Reflection across x-axis y0 = port_position[1] ref.reflect(p1=(0, y0), p2=(1, y0)) ref.rotate(rotation_angle, center=port_position) ref.move(port_position, position) return ref
def round_corners( points, bend90, straight_factory, taper=None, straight_factory_fall_back_no_taper=None, mirror_straight=False, straight_ports=None, ): """ returns a rounded waveguide route from a list of manhattan points Args: points: manhattan route defined by waypoints bend90: the bend to use for 90Deg turns straight_factory: the straight factory to use to generate straight portions taper: the taper to use in straight portion. If None, no tapering is done in straight portions straight_factory_fall_back_no_taper: factory to use for straights in case there is no space to put a pair of tapers straight_ports: port names for straights If not specified, will use some heuristic to find them """ ## If there is a taper, make sure its length is known if taper != None: if not "length" in taper.info: _taper_ports = list(taper.ports.values()) taper.info["length"] = _taper_ports[-1].x - _taper_ports[0].x if straight_factory_fall_back_no_taper is None: straight_factory_fall_back_no_taper = straight_factory ## Remove any flat angle, otherwise the algorithm won't work points = remove_flat_angles(points) cell_tmp_name = "connector_{}".format(uuid.uuid4()) cell = pp.Component(name=cell_tmp_name) points = np.array(points) straight_sections = [] # (p0, angle, length) p0_straight = points[0] p1 = points[1] total_length = 0 # Keep track of the total path length if "length" in bend90.info: bend_length = bend90.info["length"] else: bend_length = 0 dp = p1 - p0_straight a0 = None if _is_vertical(p0_straight, p1): if dp[1] > 0: a0 = 90 elif dp[1] < 0: a0 = 270 elif _is_horizontal(p0_straight, p1): if dp[0] > 0: a0 = 0 elif dp[0] < 0: a0 = 180 assert a0 != None, "Points should be manhattan, got {} {}".format( p0_straight, p1) pname_west, pname_north = [p.name for p in _get_bend_ports(bend90)] n_o_bends = points.shape[0] - 2 total_length += n_o_bends * bend_length # Add bend sections and record straight-section information for i in range(1, points.shape[0] - 1): bend_origin, rotation, x_reflection = _get_bend_reference_parameters( points[i - 1], points[i], points[i + 1], bend90) bend_ref = gen_sref(bend90, rotation, x_reflection, pname_west, bend_origin) cell.add(bend_ref) straight_sections += [(p0_straight, a0, get_straight_distance(p0_straight, bend_origin))] p0_straight = bend_ref.ports[pname_north].midpoint a0 = bend_ref.ports[pname_north].orientation straight_sections += [(p0_straight, a0, get_straight_distance(p0_straight, points[-1]))] wg_refs = [] for straight_origin, angle, length in straight_sections: with_taper = False wg_width = list(bend90.ports.values())[0].width total_length += length if taper != None and length > 2 * taper.info["length"] + 1.0: length = length - 2 * taper.info["length"] with_taper = True if with_taper: # First taper: # Taper starts where straight would have started taper_origin = straight_origin pname_west, pname_east = [ p.name for p in _get_straight_ports(taper) ] taper_ref = taper.ref(position=taper_origin, port_id=pname_west, rotation=angle) wg_width = taper.ports[pname_east].width cell.add(taper_ref) wg_refs += [taper_ref] # Update start straight position straight_origin = taper_ref.ports[pname_east].midpoint # Straight waveguide if with_taper or taper is None: wg = straight_factory(length=length, width=wg_width) else: wg = straight_factory_fall_back_no_taper(length=length, width=wg_width) if straight_ports is None: straight_ports = [p.name for p in _get_straight_ports(wg)] pname_west, pname_east = straight_ports wg.move(wg.ports[pname_west], (0, 0)) wg_ref = pp.ComponentReference(wg) if mirror_straight: wg_ref.reflect_v(list(wg_ref.ports.values())[0].name) wg_ref.rotate(angle) wg_ref.move(straight_origin) cell.add(wg_ref) wg_refs += [wg_ref] port_index_out = 1 if with_taper: # Second taper: # Origin at end of straight waveguide, starting from east side of taper taper_origin = wg_ref.ports[pname_east] pname_west, pname_east = [ p.name for p in _get_straight_ports(taper) ] taper_ref = taper.ref(position=taper_origin, port_id=pname_east, rotation=angle + 180) cell.add(taper_ref) wg_refs += [taper_ref] port_index_out = 0 cell.add_port(name="input", port=list(wg_refs[0].ports.values())[0]) cell.add_port(name="output", port=list(wg_refs[-1].ports.values())[port_index_out]) """ # Update name with uuid - too expensive to compute geometrical hash every time # Prefix with zz to make connectors appear at end of cell lists # The geometrical hash lacks caching right now and ends up taking a # lot of time to compute on every single connector """ cell_name = "zz_conn_{}".format(uuid.uuid4()) cell.name = cell_name cell.info["length"] = total_length return cell
def round_corners( points, bend90, straight_factory, taper=None, straight_factory_fall_back_no_taper=None, mirror_straight=False, straight_ports=None, ): """Return dict with reference list with rounded waveguide route from a list of manhattan points. Also returns a dict of ports As well as settings Args: points: manhattan route defined by waypoints bend90: the bend to use for 90Deg turns straight_factory: the straight factory to use to generate straight portions taper: taper for straight portions. If None, no tapering straight_factory_fall_back_no_taper: factory to use for straights in case there is no space to put a pair of tapers mirror_straight: mirror_straight waveguide straight_ports: port names for straights. If not specified, will use some heuristic to find them """ references = [] ports = dict() settings = dict() # If there is a taper, make sure its length is known if taper: if "length" not in taper.info: _taper_ports = list(taper.ports.values()) taper.info["length"] = _taper_ports[-1].x - _taper_ports[0].x if straight_factory_fall_back_no_taper is None: straight_factory_fall_back_no_taper = straight_factory # Remove any flat angle, otherwise the algorithm won't work points = remove_flat_angles(points) points = np.array(points) straight_sections = [] # (p0, angle, length) p0_straight = points[0] p1 = points[1] total_length = 0 # Keep track of the total path length if "length" in bend90.info: bend_length = bend90.info["length"] else: bend_length = 0 dp = p1 - p0_straight a0 = None if _is_vertical(p0_straight, p1): if dp[1] > 0: a0 = 90 elif dp[1] < 0: a0 = 270 elif _is_horizontal(p0_straight, p1): if dp[0] > 0: a0 = 0 elif dp[0] < 0: a0 = 180 assert a0 is not None, "Points should be manhattan, got {} {}".format( p0_straight, p1 ) pname_west, pname_north = [p.name for p in _get_bend_ports(bend90)] n_o_bends = points.shape[0] - 2 total_length += n_o_bends * bend_length # Add bend sections and record straight-section information for i in range(1, points.shape[0] - 1): bend_origin, rotation, x_reflection = _get_bend_reference_parameters( points[i - 1], points[i], points[i + 1], bend90 ) bend_ref = gen_sref(bend90, rotation, x_reflection, pname_west, bend_origin) references.append(bend_ref) straight_sections += [ (p0_straight, a0, get_straight_distance(p0_straight, bend_origin)) ] p0_straight = bend_ref.ports[pname_north].midpoint a0 = bend_ref.ports[pname_north].orientation straight_sections += [ (p0_straight, a0, get_straight_distance(p0_straight, points[-1])) ] wg_refs = [] for straight_origin, angle, length in straight_sections: with_taper = False wg_width = list(bend90.ports.values())[0].width total_length += length if taper is not None and length > 2 * taper.info["length"] + 1.0: length = length - 2 * taper.info["length"] with_taper = True if with_taper: # Taper starts where straight would have started taper_origin = straight_origin pname_west, pname_east = [p.name for p in _get_straight_ports(taper)] taper_ref = taper.ref( position=taper_origin, port_id=pname_west, rotation=angle ) wg_width = taper.ports[pname_east].width references.append(taper_ref) wg_refs += [taper_ref] # Update start straight position straight_origin = taper_ref.ports[pname_east].midpoint # Straight waveguide if with_taper or taper is None: wg = straight_factory(length=length, width=wg_width) else: wg = straight_factory_fall_back_no_taper(length=length, width=wg_width) if straight_ports is None: straight_ports = [p.name for p in _get_straight_ports(wg)] pname_west, pname_east = straight_ports wg.move(wg.ports[pname_west], (0, 0)) wg_ref = pp.ComponentReference(wg) if mirror_straight: wg_ref.reflect_v(list(wg_ref.ports.values())[0].name) wg_ref.rotate(angle) wg_ref.move(straight_origin) references.append(wg_ref) wg_refs += [wg_ref] port_index_out = 1 if with_taper: # Second taper: # Origin at end of straight waveguide, starting from east side of taper taper_origin = wg_ref.ports[pname_east] pname_west, pname_east = [p.name for p in _get_straight_ports(taper)] taper_ref = taper.ref( position=taper_origin, port_id=pname_east, rotation=angle + 180 ) references.append(taper_ref) wg_refs += [taper_ref] port_index_out = 0 ports["input"] = list(wg_refs[0].ports.values())[0] ports["output"] = list(wg_refs[-1].ports.values())[port_index_out] settings["length"] = snap_to_1nm_grid(float(total_length)) return dict(references=references, ports=ports, settings=settings)