def _add_pin_square( component: Component, port: Port, pin_length: float = 0.1, layer: Tuple[int, int] = LAYER.PORT, label_layer: Optional[Tuple[int, int]] = LAYER.PORT, port_margin: float = 0.0, ) -> None: """Add half out pin to a component. Args: component: port: Port pin_length: length of the pin marker for the port layer: for the pin marker label_layer: for the label port_margin: margin to port edge .. code:: _______________ | | | | | | ||| | ||| | | | | __ | |_______________| __ """ p = port a = p.orientation ca = np.cos(a * np.pi / 180) sa = np.sin(a * np.pi / 180) rot_mat = np.array([[ca, -sa], [sa, ca]]) d = p.width / 2 + port_margin dbot = np.array([pin_length / 2, -d]) dtop = np.array([pin_length / 2, d]) dbotin = np.array([-pin_length / 2, -d]) dtopin = np.array([-pin_length / 2, +d]) p0 = p.position + _rotate(dbot, rot_mat) p1 = p.position + _rotate(dtop, rot_mat) ptopin = p.position + _rotate(dtopin, rot_mat) pbotin = p.position + _rotate(dbotin, rot_mat) polygon = [p0, p1, ptopin, pbotin] component.add_polygon(polygon, layer=layer) if label_layer: component.add_label( text=str(p.name), position=p.midpoint, layer=label_layer, )
def write_gds( component: Component, gdspath: Optional[PosixPath] = None, unit: float = 1e-6, precision: float = 1e-9, remove_previous_markers: bool = False, auto_rename: bool = False, with_settings_label: bool = conf.tech.with_settings_label, ) -> str: """write component to GDS and returs gdspath Args: component (required) gdspath: by default saves it into CONFIG['gds_directory'] auto_rename: False by default (otherwise it calls it top_cell) unit precission Returns: gdspath """ gdspath = gdspath or CONFIG["gds_directory"] / (component.name + ".gds") gdspath = pathlib.Path(gdspath) gdsdir = gdspath.parent gdspath = str(gdspath) gdsdir.mkdir(parents=True, exist_ok=True) if remove_previous_markers: # If the component HAS ports AND markers and we want to # avoid duplicate port markers, then we clear the previous ones port_layer = (LAYER.PORT, ) label_layer = (LAYER.TEXT, ) component.remove_layers([port_layer]) component.remove_layers([label_layer]) # write component settings into text layer if with_settings_label: settings = component.get_settings() for i, k in enumerate(sorted(list(settings.keys()))): v = clean_value(settings.get(k)) text = f"{k} = {clean_value(v)}" # print(text) component.add_label( text=text, position=component.center - [0, i * 1], layer=CONFIG["layers"]["TEXT"], ) component.write_gds( gdspath, precision=precision, auto_rename=auto_rename, ) component.path = gdspath return gdspath
def _add_settings_label( component: Component, reference: ComponentReference, label_layer: Tuple[int, int] = LAYER.LABEL_SETTINGS, ) -> None: """Add settings in label, ignores component.ignore keys.""" settings = reference.get_settings() settings_string = f"settings={json.dumps(settings, indent=2)}" component.add_label( position=reference.center, text=settings_string, layer=label_layer )
def _add_instance_label( component: Component, reference: ComponentReference, instance_name: Optional[str] = None, layer: Tuple[int, int] = LAYER.LABEL_INSTANCE, ) -> None: """Adds label to a reference in a component.""" instance_name = ( instance_name or f"{reference.parent.name},{int(reference.x)},{int(reference.y)}") component.add_label( text=instance_name, position=pp.drc.snap_to_1nm_grid((reference.x, reference.y)), layer=layer, )
def _add_pin_triangle( component: Component, port: Port, layer: Tuple[int, int] = LAYER.PORT, label_layer: Tuple[int, int] = LAYER.TEXT, ) -> None: """Add triangle pin with a right angle, pointing out of the port Args: component: port: Port layer: for the pin marker label_layer: for the label """ p = port a = p.orientation ca = np.cos(a * np.pi / 180) sa = np.sin(a * np.pi / 180) rot_mat = np.array([[ca, -sa], [sa, ca]]) d = p.width / 2 dbot = np.array([0, -d]) dtop = np.array([0, d]) dtip = np.array([d, 0]) p0 = p.position + _rotate(dbot, rot_mat) p1 = p.position + _rotate(dtop, rot_mat) ptip = p.position + _rotate(dtip, rot_mat) polygon = [p0, p1, ptip] component.add_label( text=p.name, position=p.midpoint, layer=label_layer, ) component.add_polygon(polygon, layer=layer)
def import_phidl_component(component: Device, **kwargs) -> Component: """ returns a gdsfactory Component from a phidl Device or function """ D = call_if_func(component, **kwargs) D_copy = Component(name=D._internal_name) D_copy.info = copy.deepcopy(D.info) for ref in D.references: new_ref = ComponentReference( device=ref.parent, origin=ref.origin, rotation=ref.rotation, magnification=ref.magnification, x_reflection=ref.x_reflection, ) new_ref.owner = D_copy D_copy.add(new_ref) for alias_name, alias_ref in D.aliases.items(): if alias_ref == ref: D_copy.aliases[alias_name] = new_ref for p in D.ports.values(): D_copy.add_port( port=Port( name=p.name, midpoint=p.midpoint, width=p.width, orientation=p.orientation, parent=p.parent, ) ) for poly in D.polygons: D_copy.add_polygon(poly) for label in D.labels: D_copy.add_label( text=label.text, position=label.position, layer=(label.layer, label.texttype), ) return D_copy
def import_gds( gdspath: Union[str, Path], cellname: None = None, flatten: bool = False, snap_to_grid_nm: Optional[int] = None, ) -> Component: """Returns a Componenent from a GDS file. Adapted from phidl/geometry.py Args: gdspath: path of GDS file cellname: cell of the name to import (None) imports top cell flatten: if True returns flattened (no hierarchy) snap_to_grid_nm: snap to different nm grid (does not snap if False) """ gdsii_lib = gdspy.GdsLibrary() gdsii_lib.read_gds(gdspath) top_level_cells = gdsii_lib.top_level() cellnames = [c.name for c in top_level_cells] if cellname is not None: if cellname not in gdsii_lib.cells: raise ValueError( f"cell {cellname} is not in file {gdspath} with cells {cellnames}" ) topcell = gdsii_lib.cells[cellname] elif cellname is None and len(top_level_cells) == 1: topcell = top_level_cells[0] elif cellname is None and len(top_level_cells) > 1: raise ValueError( f"import_gds() There are multiple top-level cells in {gdspath}, " f"you must specify `cellname` to select of one of them among {cellnames}" ) if not flatten: D_list = [] c2dmap = {} for cell in gdsii_lib.cells.values(): D = Component(name=cell.name) D.polygons = cell.polygons D.references = cell.references D.name = cell.name for label in cell.labels: rotation = label.rotation if rotation is None: rotation = 0 label_ref = D.add_label( text=label.text, position=np.asfarray(label.position), magnification=label.magnification, rotation=rotation * 180 / np.pi, layer=(label.layer, label.texttype), ) label_ref.anchor = label.anchor c2dmap.update({cell: D}) D_list += [D] for D in D_list: # First convert each reference so it points to the right Device converted_references = [] for e in D.references: ref_device = c2dmap[e.ref_cell] if isinstance(e, gdspy.CellReference): dr = DeviceReference( device=ref_device, origin=e.origin, rotation=e.rotation, magnification=e.magnification, x_reflection=e.x_reflection, ) dr.owner = D converted_references.append(dr) elif isinstance(e, gdspy.CellArray): dr = CellArray( device=ref_device, columns=e.columns, rows=e.rows, spacing=e.spacing, origin=e.origin, rotation=e.rotation, magnification=e.magnification, x_reflection=e.x_reflection, ) dr.owner = D converted_references.append(dr) D.references = converted_references # Next convert each Polygon # temp_polygons = list(D.polygons) # D.polygons = [] # for p in temp_polygons: # D.add_polygon(p) # Next convert each Polygon temp_polygons = list(D.polygons) D.polygons = [] for p in temp_polygons: if snap_to_grid_nm: points_on_grid = pp.drc.snap_to_grid( p.polygons[0], nm=snap_to_grid_nm ) p = gdspy.Polygon( points_on_grid, layer=p.layers[0], datatype=p.datatypes[0] ) D.add_polygon(p) topdevice = c2dmap[topcell] return topdevice if flatten: D = pp.Component() polygons = topcell.get_polygons(by_spec=True) for layer_in_gds, polys in polygons.items(): D.add_polygon(polys, layer=layer_in_gds) return D