def extend_port(port, width, length, layer): '''Create a rectangle extending perpendicularly from the port. Attributes: ---------- port : dl.Port width : float length : float layer : int, tuple or set Returns: ------- dl.Device. ''' p1 = Point(port.midpoint) dir = Point(port.normal[1]) - Point(port.normal[0]) p2 = p1 + dir * length p = path.smooth(points=[p1.coord, p2.coord]) return p.extrude(width=width, layer=layer)
def get_corners(device: Device): ''' get corners of a device. Parameters --------- device : phidl.Device Returns: ll : pt.Point lower left lr : pt.Point lower right ul : pt.Point upper left ur : pt.Point c : pt.Point n : pt.point s : pt.point w : pt.Point e : pt.Point. ''' bbox = device.bbox ll = Point(bbox[0, 0], bbox[0, 1]) lr = Point(bbox[1, 0], bbox[0, 1]) ul = Point(bbox[0, 0], bbox[1, 1]) ur = Point(bbox[1, 0], bbox[1, 1]) n = Point(device.center[0], bbox[1, 1]) s = Point(device.center[0], bbox[0, 1]) w = Point(bbox[0, 0], device.center[1]) e = Point(bbox[1, 0], device.center[1]) c = Point(device.center) class ReferencePoints(): pass r = ReferencePoints() r.ll = ll r.lr = lr r.ul = ul r.ur = ur r.c = c r.n = n r.s = s r.w = w r.e = e return r
def move_relative_to_cell(cell_to_be_moved, cell_ref, anchor_source='ll', anchor_dest='ll', offset=(0, 0)): '''Move cell_to_be_moved relative to cell_ref, by specifying anchors. Anchors are specified as described in get_corners(). Offset is specified as normalized to cell_ref size. Attributes: --------- cell_to_be_moved: dl.Device cell_ref:dl.Device anchor_source: string anchor_dest: string offset : tuple. ''' a_origin = get_anchor(anchor_source, cell_to_be_moved) a_end = get_anchor(anchor_dest, cell_ref) dx = cell_ref.xmax - cell_ref.xmin dy = cell_ref.ymax - cell_ref.ymin offset = Point(dx * offset[0], dy * offset[1]) cell_to_be_moved.move(origin=a_origin.coord, destination=a_end.coord) cell_to_be_moved.move(destination=offset.coord)
def get_centroid_ports(*ports): '''Calculate port with matching orientation and with as input ports, and midpoint at the centroid of the input ports midpoint. Attributes: ---------- *ports : dl.Port Returns: ------- dl.Port. ''' if not ports: raise ValueError(f"st.get_centroid_ports(): no ports passed") if isinstance(ports, Port): return ports else: ports_centroid = get_centroid(*[Point(x.midpoint) for x in ports]) ports_width = np.average([x.width for x in ports]) ports_orientation = np.average([x.orientation for x in ports]) return Port(orientation=ports_orientation, width=ports_width, midpoint=ports_centroid.coord)
def shift_port(port, dist): '''Returns new port with translated midpoint. Attributes: ---------- port : dl.Port dist : float Returns: dl.Port. ''' port_mid_norm = Point(port.normal[1]) - Point(port.normal[0]) midpoint_projected = Point(port.midpoint) + port_mid_norm * dist new_port = Port(name=port.name + 'shifted', orientation=port.orientation, width=port.width, midpoint=midpoint_projected.coord) return new_port
def get_centroid(*points): ''' Calculates centroid of passed points. Arguments: --------- *points : pt.Point Returns: -------- pt.Point. ''' x_c = 0 y_c = 0 if isinstance(points, Point): return points for p in points: x_c = x_c + p.x y_c = y_c + p.y return Point(x_c, y_c) / len(points)
def connect_ports(cell: Device, tag: str = 'top', layers: tuple = (LayoutDefault.layerTop, ), distance: float = 10.0, metal_width: float = None): ''' connects all the ports in the cell with name matching a tag. Parameters: ----------- cell : Device tag: str conn_dist: pt.Point offset from port location layer : tuple. Returns: ---------- cell : Device contains routings and connection port ''' import pirel.pcells as pc ports = pt._find_ports(cell, tag, depth=0) ports.sort(key=lambda x: x.midpoint[0]) ports_centroid = pt._get_centroid_ports(ports) if len(ports) == 1: raise ValueError("pm.connect_ports() : len(ports) must be >1 ") if metal_width is None: metal_width = ports_centroid.width port_mid_norm = pt.Point(ports_centroid.normal[1]) - pt.Point( ports_centroid.normal[0]) midpoint_projected = Point( ports_centroid.midpoint) + port_mid_norm * (distance + metal_width) pad_side = ports_centroid.width new_port = Port(name=tag, orientation=ports_centroid.orientation, width=ports_centroid.width, midpoint=midpoint_projected.coord) output_cell = Device() for p in ports: straight_conn = output_cell << pt._draw_multilayer( 'compass', layers, size=(p.width, abs(midpoint_projected.y - p.midpoint[1]))) straight_conn.connect("S", p) cross_conn = output_cell << pt._draw_multilayer( 'compass', layers, size=(output_cell.xsize, metal_width)) cross_conn.connect('S', new_port, overlap=metal_width) output = pt.join(output_cell) output.add_port(new_port) return output
def draw_array( cell : Device, x : int, y : int, row_spacing : float = 0 , column_spacing : float = 0 ) -> Device: ''' returns a spaced matrix of identical cells, including ports in the output cell. Parameters ---------- cell : phidl.Device x : int columns of copies y : int rows of copies row_spacing: float column_spacing: float Returns ------- cell : phidl.Device. ''' new_cell=pg.Device(cell.name+"array") cell_size=Point(cell.size)+Point(column_spacing,row_spacing) for j in range(y): for i in range(x): if y==1 and x==1: ref=new_cell.add_ref(cell,alias=cell.name) elif y==1: ref=new_cell.add_ref(cell,alias=cell.name+'_'+str(i)) elif x==1: ref=new_cell.add_ref(cell,alias=cell.name+'_'+str(j)) else: ref=new_cell.add_ref(cell,alias=cell.name+'_'+str(i)+'_'+str(j)) ref.move( destination=(Point(cell_size.x*i,cell_size.y*j)).coord) if y==1 and x==1: ppt.copy_ports(ref,new_cell) elif y==1: ppt.copy_ports(ref,new_cell,suffix='_'+str(i)) elif x==1: ppt.copy_ports(ref,new_cell,suffix='_'+str(j)) else: ppt.copy_ports(ref,new_cell,suffix='_'+str(i)+'_'+str(j)) return new_cell