def test_2_DTrans(self): a = pya.DTrans() b = pya.DTrans(pya.DTrans.M135, pya.DPoint(17, 5)) ma = pya.DCplxTrans(a, 0.5) mb = pya.DCplxTrans(b, 2.0) u = pya.DCplxTrans(a) self.assertEqual(str(ma), "r0 *0.5 0,0") self.assertEqual(str(mb), "m135 *2 17,5") self.assertEqual(ma == mb, False) self.assertEqual(ma == ma, True) self.assertEqual(ma != mb, True) self.assertEqual(ma != ma, False) i = mb.inverted() self.assertEqual(str(i), "m135 *0.5 2.5,8.5") self.assertEqual(str(pya.DCplxTrans.from_s(str(i))), str(i)) self.assertEqual(i * mb == u, True) self.assertEqual(mb * i == u, True) self.assertEqual(str(mb.trans(pya.DPoint(1, 0))), "17,3") self.assertEqual(str(mb.ctrans(2)), "4.0") self.assertEqual(str(i.ctrans(2)), "1.0")
def test_5_Trans_Hash(self): t1 = pya.DTrans(pya.DTrans.M135, pya.DPoint(17, 5)) t2 = pya.DTrans(pya.DTrans.M135, pya.DPoint(17 + 1e-7, 5)) t3 = pya.DTrans(pya.DTrans.M135, pya.DPoint(17 + 1e-4, 5)) t4a = pya.DTrans(pya.DTrans.M135, pya.DPoint(18, 5)) t4b = pya.DTrans(pya.DTrans.R90, pya.DPoint(18, 5)) self.assertEqual(t1.hash() == t2.hash(), True) self.assertEqual(t1.hash() == t3.hash(), False) self.assertEqual(t1.hash() == t4a.hash(), False) self.assertEqual(t1.hash() == t4b.hash(), False) self.assertEqual(hash(t1) == hash(t2), True) self.assertEqual(hash(t1) == hash(t3), False) self.assertEqual(hash(t1) == hash(t4a), False) self.assertEqual(hash(t1) == hash(t4b), False) self.assertEqual(t1.__hash__() == t2.__hash__(), True) self.assertEqual(t1.__hash__() == t3.__hash__(), False) self.assertEqual(t1.__hash__() == t4a.__hash__(), False) self.assertEqual(t1.__hash__() == t4b.__hash__(), False) # Transformations can't be used as hash keys currently if False: h = {t1: "t1", t3: "t3", t4a: "t4a", t4b: "t4b"} self.assertEqual(h[t1], "t1") self.assertEqual(h[t2], "t1") self.assertEqual(h[t3], "t3") self.assertEqual(h[t4a], "t4a") self.assertEqual(h[t4b], "t4b")
def test_5_Trans_FuzzyCompare(self): t1 = pya.DTrans(pya.DTrans.M135, pya.DPoint(17, 5)) t2 = pya.DTrans(pya.DTrans.M135, pya.DPoint(17 + 1e-7, 5)) t3 = pya.DTrans(pya.DTrans.M135, pya.DPoint(17 + 1e-4, 5)) t4a = pya.DTrans(pya.DTrans.M135, pya.DPoint(18, 5)) t4b = pya.DTrans(pya.DTrans.R90, pya.DPoint(18, 5)) self.assertEqual(t1 == t2, True) self.assertEqual(t1 != t2, False) self.assertEqual(t1 < t2, False) self.assertEqual(t2 < t1, False) self.assertEqual(t1 == t3, False) self.assertEqual(t1 != t3, True) self.assertEqual(t1 < t3, True) self.assertEqual(t3 < t1, False) self.assertEqual(t1 == t4a, False) self.assertEqual(t1 != t4a, True) self.assertEqual(t1 < t4a, True) self.assertEqual(t4a < t1, False) self.assertEqual(t1 == t4b, False) self.assertEqual(t1 != t4b, True) self.assertEqual(t1 < t4b, False) self.assertEqual(t4b < t1, True)
def pcell(self, layout, cell=None, params=None): if cell is None: cell = layout.create_cell(self.name) cp = self.parse_param_args(params) origin, _, _ = CellWithPosition.origin_ex_ey(self, params, multiple_of_90=True) if from_library is not None: # Topcell must be same as filename gdscell = get_lib_cell(layout, cell_name, from_library) else: # BUG loading this file twice segfaults klayout layout2 = pya.Layout() layout2.read(os.path.join(gds_dir, filename)) gdscell2 = layout2.cell(cell_name) gdscell = layout.create_cell(cell_name) gdscell.copy_tree(gdscell2) del gdscell2 del layout2 rot_DTrans = pya.DTrans.R0 angle_multiple_90 = cp.angle_ex // 90 rot_DTrans.rot = (angle_multiple_90) % 4 cell.insert( pya.DCellInstArray(gdscell.cell_index(), pya.DTrans(rot_DTrans, origin))) return cell, {}
def test_2_DPolygon(self): pts = [pya.DPoint(0, 0)] p = pya.DPolygon(pts, True) self.assertEqual(str(p), "(0,0)") arr = [] for e in p.each_edge(): arr.append(str(e)) self.assertEqual(arr, ["(0,0;0,0)"]) p = pya.DPolygon(pya.DBox(0, 0, 100, 100)) p.insert_hole([pya.DPoint(0, 0), pya.DPoint(10, 0)], True) self.assertEqual(str(p), "(0,0;0,100;100,100;100,0/0,0;10,0)") p.assign_hole(0, [pya.DPoint(0, 0), pya.DPoint(10, 0)]) self.assertEqual(str(p), "(0,0;0,100;100,100;100,0/0,0;10,0)") p.assign_hole(0, [pya.DPoint(0, 0), pya.DPoint(10, 0)], True) self.assertEqual(str(p), "(0,0;0,100;100,100;100,0/0,0;10,0)") pts = [pya.DPoint(0, 0), pya.DPoint(10, 0)] p = pya.DPolygon(pts, True) self.assertEqual(str(p), "(0,0;10,0)") self.assertEqual(str(pya.Polygon(p)), "(0,0;10,0)") p.hull = [] self.assertEqual(str(p), "()") p.hull = [pya.DPoint(0, 0), pya.DPoint(10, 0)] self.assertEqual(str(p), "(0,0;10,0)") p.assign_hull([pya.DPoint(0, 0), pya.DPoint(10, 0)], True) self.assertEqual(str(p), "(0,0;10,0)") arr = [] for e in p.each_edge(): arr.append(str(e)) self.assertEqual(arr, ["(0,0;10,0)", "(10,0;0,0)"]) self.assertEqual(str(p.moved(1, 2)), "(1,2;11,2)") self.assertEqual(str(p.sized(2)), "(0,-2;0,2;10,2;10,-2)") self.assertEqual(str(p * 2), "(0,0;20,0)") self.assertEqual(str(p.transformed(pya.DTrans(pya.DTrans.R90))), "(0,0;0,10)") pp = p.dup() pp.transform(pya.DTrans(pya.DTrans.R90)) self.assertEqual(str(pp), "(0,0;0,10)")
def test_1_Trans(self): a = pya.Trans() b = pya.Trans( pya.Trans.M135, pya.Point( 17, 5 )) c = pya.Trans( 3, True, pya.Point( 17, 5 )) d = pya.Trans( pya.Point( 17, 5 )) e = pya.Trans( pya.Trans.M135 ) e2 = pya.Trans.from_dtrans( pya.DTrans.M135 ) f = pya.Trans( pya.DTrans( pya.DTrans.M135, pya.DPoint( 17, 5 )) ) self.assertEqual( str(a), "r0 0,0" ) self.assertEqual( str(pya.Trans.from_s(str(a))), str(a) ) self.assertEqual( str(b), "m135 17,5" ) self.assertEqual( str(c), "m135 17,5" ) self.assertEqual( str(d), "r0 17,5" ) self.assertEqual( str(e), "m135 0,0" ) self.assertEqual( str(e2), "m135 0,0" ) self.assertEqual( str(f), "m135 17,5" ) self.assertEqual( str(pya.Trans.from_s(str(f))), str(f) ) self.assertEqual( str(b.trans( pya.Point( 1, 0 ))), "17,4" ) self.assertEqual( a == b, False ) self.assertEqual( a == a, True ) self.assertEqual( a != b, True ) self.assertEqual( a != a, False ) self.assertEqual( (d * e) == b, True ) self.assertEqual( (e * d) == b, False ) i = c.inverted() self.assertEqual( str(i), "m135 5,17" ) self.assertEqual( (i * b) == a, True ) self.assertEqual( (b * i) == a, True ) c = pya.Trans( 3, True, pya.Point( 17, 5 )) self.assertEqual( str(c), "m135 17,5" ) c.disp = pya.Point(1, 7) self.assertEqual( str(c), "m135 1,7" ) c.angle = 1 self.assertEqual( str(c), "m45 1,7" ) c.rot = 3 self.assertEqual( str(c), "r270 1,7" ) c.mirror = True self.assertEqual( str(c), "m135 1,7" ) self.assertEqual( str(e.trans( pya.Edge(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(( e * pya.Edge(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(e.trans( pya.Box(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(( e * pya.Box(0, 1, 2, 3) )), "(-3,-2;-1,0)" ) self.assertEqual( str(e.trans( pya.Text("text", pya.Vector(0, 1)) )), "('text',m135 -1,0)" ) self.assertEqual( str(( e * pya.Text("text", pya.Vector(0, 1)) )), "('text',m135 -1,0)" ) self.assertEqual( str(e.trans( pya.Polygon( [ pya.Point(0, 1), pya.Point(2, -3), pya.Point(4, 5) ] ) )), "(-5,-4;-1,0;3,-2)" ) self.assertEqual( str(( e * pya.Polygon( [ pya.Point(0, 1), pya.Point(2, -3), pya.Point(4, 5) ] ) )), "(-5,-4;-1,0;3,-2)" ) self.assertEqual( str(e.trans( pya.Path( [ pya.Point(0, 1), pya.Point(2, 3) ], 10 ) )), "(-1,0;-3,-2) w=10 bx=0 ex=0 r=false" ) self.assertEqual( str(( e * pya.Path( [ pya.Point(0, 1), pya.Point(2, 3) ], 10 ) )), "(-1,0;-3,-2) w=10 bx=0 ex=0 r=false" )
def test_4_Trans(self): a = pya.Trans() m = pya.CplxTrans(a, 1.1) da = pya.DTrans() dm = pya.DCplxTrans(da, 1.1) self.assertEqual(str(m), "r0 *1.1 0,0") self.assertEqual(str(pya.DCplxTrans.from_s(str(m))), str(m)) self.assertEqual(str(m.trans(pya.Point(5, -7))), "5.5,-7.7") im = pya.ICplxTrans(a, 0.5) im_old = im.dup() self.assertEqual(str(im), "r0 *0.5 0,0") self.assertEqual(str(pya.ICplxTrans.from_s(str(im))), str(im)) self.assertEqual(str(im.trans(pya.Point(5, -7))), "3,-4") im = pya.ICplxTrans(m) self.assertEqual(str(im), "r0 *1.1 0,0") self.assertEqual(str(im.trans(pya.Point(5, -7))), "6,-8") im = pya.ICplxTrans(dm) self.assertEqual(str(im), "r0 *1.1 0,0") self.assertEqual(str(im.trans(pya.Point(5, -7))), "6,-8") im.assign(im_old) self.assertEqual(str(im), "r0 *0.5 0,0") self.assertEqual(str(im.trans(pya.Point(5, -7))), "3,-4") self.assertEqual(str(pya.ICplxTrans(5, -7)), "r0 *1 5,-7") self.assertEqual(str(pya.ICplxTrans(pya.ICplxTrans.R180, 1.5, 5, -7)), "r180 *1.5 5,-7") self.assertEqual( str(pya.ICplxTrans(pya.ICplxTrans.R180, 1.5, pya.Point(5, -7))), "r180 *1.5 5,-7") self.assertEqual( str(pya.ICplxTrans(pya.ICplxTrans.R180, 1.5, pya.Vector(5, -7))), "r180 *1.5 5,-7") self.assertEqual( str(pya.ICplxTrans(pya.ICplxTrans.R180, 1.5, pya.DVector(5, -7))), "r180 *1.5 5,-7") self.assertEqual(str(pya.ICplxTrans(pya.ICplxTrans.R180, 1.5)), "r180 *1.5 0,0") c = pya.ICplxTrans.from_dtrans(pya.DCplxTrans.M135) self.assertEqual(str(c), "m135 *1 0,0") c = pya.ICplxTrans.from_trans(pya.CplxTrans.M135) self.assertEqual(str(c), "m135 *1 0,0")
def place_cell(parent_cell, pcell, ports_dict, placement_origin, relative_to=None, transform_into=False): """ Places an pya cell and return ports with updated positions Args: parent_cell: cell to place into pcell, ports_dict: result of KLayoutPCell.pcell call placement_origin: pya.Point object to be used as origin relative_to: port name the cell is placed so that the port is located at placement_origin transform_into: if used with relative_into, transform the cell's coordinate system so that its origin is in the given port. Returns: ports(dict): key:port.name, value: geometry.Port with positions relative to parent_cell's origin """ offset = pya.DVector(0, 0) port_offset = placement_origin if relative_to is not None: offset = ports_dict[relative_to].position port_offset = placement_origin - offset if transform_into: # print(type(pcell)) offset_transform = pya.DTrans(pya.DTrans.R0, -offset) for instance in pcell.each_inst(): instance.transform(offset_transform) pcell.transform_into(offset_transform) else: placement_origin = placement_origin - offset transformation = pya.DTrans(pya.Trans.R0, placement_origin) instance = pya.DCellInstArray(pcell.cell_index(), transformation) parent_cell.insert(instance) for port in ports_dict.values(): port.position += port_offset return ports_dict
def test_5_CplxTrans_Hash(self): t1 = pya.DCplxTrans(pya.DTrans(pya.DTrans.M135, pya.DPoint(17, 5)), 1.0) t2a = pya.DCplxTrans( pya.DTrans(pya.DTrans.M135, pya.DPoint(17 + 1e-7, 5)), 1.0) t2b = pya.DCplxTrans(pya.DTrans(pya.DTrans.M135, pya.DPoint(17, 5)), 1.0 + 1e-11) t2c = pya.DCplxTrans(pya.DTrans(pya.DTrans.M135, pya.DPoint(17, 5)), 1.0) t2c.angle = t2c.angle + 1e-11 t3a = pya.DCplxTrans( pya.DTrans(pya.DTrans.M135, pya.DPoint(17 + 1e-4, 5)), 1.0) t3b = pya.DCplxTrans(pya.DTrans(pya.DTrans.M135, pya.DPoint(17, 5)), 1.0 + 1e-4) t3c = pya.DCplxTrans(pya.DTrans(pya.DTrans.M135, pya.DPoint(17, 5)), 1.0) t3c.angle = t3c.angle + 1e-4 t4 = pya.DCplxTrans(pya.DTrans(pya.DTrans.R90, pya.DPoint(18, 5)), 1.0) self.assertEqual(t1.hash() == t2a.hash(), True) self.assertEqual(t1.hash() == t2b.hash(), True) self.assertEqual(t1.hash() == t2c.hash(), True) self.assertEqual(t1.hash() == t3a.hash(), False) self.assertEqual(t1.hash() == t3b.hash(), False) self.assertEqual(t1.hash() == t3c.hash(), False) self.assertEqual(t3a.hash() == t3b.hash(), False) self.assertEqual(t3a.hash() == t3c.hash(), False) self.assertEqual(t3b.hash() == t3c.hash(), False) self.assertEqual(t1.hash() == t4.hash(), False) # Transformations can't be used as hash keys currently if False: h = {t1: "t1", t3a: "t3a", t3b: "t3b", t3c: "t3c", t4: "t4"} self.assertEqual(h[t1], "t1") self.assertEqual(h[t2a], "t1") self.assertEqual(h[t2b], "t1") self.assertEqual(h[t2c], "t1") self.assertEqual(h[t3a], "t3a") self.assertEqual(h[t3b], "t3b") self.assertEqual(h[t3c], "t3c") self.assertEqual(h[t4], "t4")
def wrapper_pcell(self, layout, cell=None, params=None): global layer_map_dict try: layer_map_dict[layout] except KeyError: layer_map_dict[layout] = pya.LayerMap() if cell is None: # copy source code of class and all its ancestors source_code = "".join( [inspect.getsource(klass) for klass in self.__class__.__mro__ if issubclass(klass, KLayoutPCell)]) # Default params before instantiation original_default_params = {name: value["default"] for name, value in self.param_definition.items()} # Updated params after instantiation and placement # (could be bigger than the original default) if params is not None: default_params = dict(self.default_params, **params) else: default_params = self.default_params # Differential parameters (non-default) diff_params = {} for name, value in original_default_params.items(): if default_params[name] != value: diff_params[name] = default_params[name] long_hash_pcell = sha256((source_code + str(diff_params) + self.name).encode()).hexdigest() short_hash_pcell = long_hash_pcell[0:7] cache_fname = f'cache_{self.__class__.__qualname__}_{short_hash_pcell}' # if short_hash_pcell in cell_cache.keys(): # already loaded # print(f"Preloaded {self.__class__.__name__}: {diff_params}") # cached_cell, ports_bytecode, cellname = cell_cache[short_hash_pcell] # ports = pickle.loads(ports_bytecode) # # print('read:', cell_index, ports, cellname) # newcell = layout.create_cell(cellname) # newcell.copy_tree(cached_cell) # # newcell.insert(pya.DCellInstArray(cell.cell_index(), # # pya.DTrans(pya.Trans.R0, pya.DPoint(0, 0)))) # return newcell, deepcopy(ports) def read_layout(layout, gds_filename): global layer_map_dict load_options = pya.LoadLayoutOptions() load_options.text_enabled = True load_options.set_layer_map(layer_map_dict[layout], True) # store and take away the cell names of all cells read so far # (by setting the cell name to "" the cells basically become invisible for # the following read) # take out the pcells cell_list = [cell for cell in layout.each_cell()] cell_indices = {cell.name: cell.cell_index() for cell in cell_list} for i in cell_indices.values(): layout.rename_cell(i, "") lmap = layout.read(gds_filename, load_options) # in the new layout, get all cells names cell_names2 = [(cell.cell_index(), cell.name) for cell in layout.each_cell()] # make those cells point to older cells prune_cells_indices = [] for i_duplicate, name_cached_cell in cell_names2: if name_cached_cell in cell_indices.keys(): if name_cached_cell.startswith('cache_'): for parent_inst_array in layout.cell(i_duplicate).each_parent_inst(): cell_instance = parent_inst_array.child_inst() cell_instance.cell = layout.cell( cell_indices[name_cached_cell]) prune_cells_indices.append(i_duplicate) else: # print('RENAME', name_cached_cell) k = 1 while (name_cached_cell + f"_{k}") in cell_indices.keys(): k += 1 layout.rename_cell(i_duplicate, name_cached_cell + f"_{k}") for i_pruned in prune_cells_indices: # print('deleting cell', layout.cell(i_pruned).name) layout.prune_cell(i_pruned, -1) # every conflict should have been caught above for name, i in cell_indices.items(): layout.rename_cell(i, name) layer_map_dict[layout] = lmap return lmap cache_fname_gds = cache_fname + '.gds' cache_fname_pkl = cache_fname + '.klayout.pkl' os.makedirs(cache_dir, mode=0o775, exist_ok=True) cache_fpath_gds = os.path.join(cache_dir, cache_fname_gds) cache_fpath_pkl = os.path.join(cache_dir, cache_fname_pkl) if os.path.isfile(cache_fpath_gds) and os.path.isfile(cache_fpath_pkl): with open(cache_fpath_pkl, 'rb') as file: ports, read_short_hash_pcell, cellname = pickle.load(file) if debug: print(f"Reading from cache: {cache_fname}: {diff_params}, {cellname}") else: print('r', end='', flush=True) if not layout.has_cell(cache_fname): read_layout(layout, cache_fpath_gds) retrieved_cell = layout.cell(cache_fname) cell = layout.create_cell(cellname) cell.insert(pya.DCellInstArray(retrieved_cell.cell_index(), pya.DTrans(pya.Trans.R0, pya.DPoint(0, 0)))) # cell.move_tree(retrieved_cell) else: if layout.has_cell(cache_fname): print(f"WARNING: {cache_fname_gds} does not exist but {cache_fname} is in layout.") # populating .gds and .pkl empty_layout = pya.Layout() compiled_cell, ports = pcell( self, empty_layout, cell=None, params=params) if debug: print(f"Writing to cache: {cache_fname}: {diff_params}, {compiled_cell.name}") else: print('w', end='', flush=True) cellname, compiled_cell.name = compiled_cell.name, cache_fname compiled_cell.write(cache_fpath_gds) with open(cache_fpath_pkl, 'wb') as file: pickle.dump((ports, short_hash_pcell, cellname), file) read_layout(layout, cache_fpath_gds) retrieved_cell = layout.cell(cache_fname) cell = layout.create_cell(cellname) cell.insert(pya.DCellInstArray(retrieved_cell.cell_index(), pya.DTrans(pya.Trans.R0, pya.DPoint(0, 0)))) else: cell, ports = pcell(self, layout, cell=cell, params=params) return cell, ports
def test_5_CplxTrans_FuzzyCompare(self): t1 = pya.DCplxTrans(pya.DTrans(pya.DTrans.M135, pya.DPoint(17, 5)), 1.0) t2a = pya.DCplxTrans( pya.DTrans(pya.DTrans.M135, pya.DPoint(17 + 1e-7, 5)), 1.0) t2b = pya.DCplxTrans(pya.DTrans(pya.DTrans.M135, pya.DPoint(17, 5)), 1.0 + 1e-11) t2c = pya.DCplxTrans(pya.DTrans(pya.DTrans.M135, pya.DPoint(17, 5)), 1.0) t2c.angle = t2c.angle + 1e-11 t3a = pya.DCplxTrans( pya.DTrans(pya.DTrans.M135, pya.DPoint(17 + 1e-4, 5)), 1.0) t3b = pya.DCplxTrans(pya.DTrans(pya.DTrans.M135, pya.DPoint(17, 5)), 1.0 + 1e-4) t3c = pya.DCplxTrans(pya.DTrans(pya.DTrans.M135, pya.DPoint(17, 5)), 1.0) t3c.angle = t3c.angle + 1e-4 t4 = pya.DCplxTrans(pya.DTrans(pya.DTrans.R90, pya.DPoint(18, 5)), 1.0) self.assertEqual(t1 == t2a, True) self.assertEqual(t1 != t2a, False) self.assertEqual(t1 < t2a, False) self.assertEqual(t2a < t1, False) self.assertEqual(t1 == t2b, True) self.assertEqual(t1 != t2b, False) self.assertEqual(t1 < t2b, False) self.assertEqual(t2b < t1, False) self.assertEqual(t1 == t2c, True) self.assertEqual(t1 != t2c, False) self.assertEqual(t1 < t2c, False) self.assertEqual(t2c < t1, False) self.assertEqual(t1 == t3a, False) self.assertEqual(t1 != t3a, True) self.assertEqual(t1 < t3a, True) self.assertEqual(t3a < t1, False) self.assertEqual(t1 == t3b, False) self.assertEqual(t1 != t3b, True) self.assertEqual(t1 < t3b, False) self.assertEqual(t3b < t1, True) self.assertEqual(t1 == t3c, False) self.assertEqual(t1 != t3c, True) self.assertEqual(t1 < t3c, True) self.assertEqual(t3c < t1, False) self.assertEqual(t3a == t3b, False) self.assertEqual(t3a != t3b, True) self.assertEqual(t3a < t3b, False) self.assertEqual(t3b < t3a, True) self.assertEqual(t3a == t3c, False) self.assertEqual(t3a != t3c, True) self.assertEqual(t3a < t3c, False) self.assertEqual(t3c < t3a, True) self.assertEqual(t3b == t3c, False) self.assertEqual(t3b != t3c, True) self.assertEqual(t3b < t3c, True) self.assertEqual(t3c < t3b, False) self.assertEqual(t1 == t4, False) self.assertEqual(t1 != t4, True) self.assertEqual(t1 < t4, True) self.assertEqual(t4 < t1, False)
def test_3_DTrans(self): c = pya.DCplxTrans(5.0, -7.0) self.assertEqual(str(c), "r0 *1 5,-7") c = pya.DCplxTrans(pya.DCplxTrans.M135) self.assertEqual(str(c), "m135 *1 0,0") self.assertEqual(c.is_unity(), False) self.assertEqual(c.is_ortho(), True) self.assertEqual(c.is_mag(), False) self.assertEqual(c.is_mirror(), True) self.assertEqual(c.rot(), pya.DCplxTrans.M135.rot()) self.assertEqual(str(c.s_trans()), "m135 0,0") self.assertAlmostEqual(c.angle, 270) self.assertEqual(str(c.trans(pya.DEdge(0, 1, 2, 3))), "(-3,-2;-1,0)") self.assertEqual(str((c * pya.DEdge(0, 1, 2, 3))), "(-3,-2;-1,0)") self.assertEqual(str(c.trans(pya.DBox(0, 1, 2, 3))), "(-3,-2;-1,0)") self.assertEqual(str((c * pya.DBox(0, 1, 2, 3))), "(-3,-2;-1,0)") self.assertEqual(str(c.trans(pya.DText("text", pya.DVector(0, 1)))), "('text',m135 -1,0)") self.assertEqual(str((c * pya.DText("text", pya.DVector(0, 1)))), "('text',m135 -1,0)") self.assertEqual( str( c.trans( pya.DPolygon([ pya.DPoint(0, 1), pya.DPoint(2, -3), pya.DPoint(4, 5) ]))), "(-5,-4;-1,0;3,-2)") self.assertEqual( str((c * pya.DPolygon( [pya.DPoint(0, 1), pya.DPoint(2, -3), pya.DPoint(4, 5)]))), "(-5,-4;-1,0;3,-2)") self.assertEqual( str(c.trans(pya.DPath( [pya.DPoint(0, 1), pya.DPoint(2, 3)], 10))), "(-1,0;-3,-2) w=10 bx=0 ex=0 r=false") self.assertEqual( str((c * pya.DPath( [pya.DPoint(0, 1), pya.DPoint(2, 3)], 10))), "(-1,0;-3,-2) w=10 bx=0 ex=0 r=false") c = pya.DCplxTrans.from_itrans(pya.CplxTrans.M135) self.assertEqual(str(c), "m135 *1 0,0") c = pya.DCplxTrans(1.5) self.assertEqual(str(c), "r0 *1.5 0,0") self.assertEqual(c.is_unity(), False) self.assertEqual(c.is_ortho(), True) self.assertEqual(c.is_mag(), True) self.assertEqual(c.is_mirror(), False) self.assertEqual(c.rot(), pya.DCplxTrans.R0.rot()) self.assertEqual(str(c.s_trans()), "r0 0,0") self.assertAlmostEqual(c.angle, 0) c = pya.DCplxTrans(0.75, 45, True, 2.5, -12.5) self.assertEqual(str(c), "m22.5 *0.75 2.5,-12.5") c = pya.DCplxTrans(0.75, 45, True, pya.DPoint(2.5, -12.5)) self.assertEqual(str(c), "m22.5 *0.75 2.5,-12.5") self.assertEqual(c.is_unity(), False) self.assertEqual(c.is_ortho(), False) self.assertEqual(c.is_mag(), True) self.assertEqual(c.rot(), pya.DCplxTrans.M0.rot()) self.assertEqual(str(c.s_trans()), "m0 2.5,-12.5") self.assertAlmostEqual(c.angle, 45) self.assertEqual(str(c.ctrans(5)), "3.75") self.assertEqual(str(c.trans(pya.DPoint(12, 16))), "17.3492424049,-14.6213203436") self.assertEqual(str(pya.DCplxTrans()), "r0 *1 0,0") self.assertEqual(pya.DCplxTrans().is_unity(), True) self.assertEqual((c * c.inverted()).is_unity(), True) c.mirror = False self.assertEqual(str(c), "r45 *0.75 2.5,-12.5") c.mag = 1.5 self.assertEqual(str(c), "r45 *1.5 2.5,-12.5") c.disp = pya.DPoint(-1.0, 5.5) self.assertEqual(str(c), "r45 *1.5 -1,5.5") self.assertEqual(c.mag, 1.5) c.angle = 60 self.assertEqual(str(c), "r60 *1.5 -1,5.5") self.assertEqual(("%g" % c.angle), "60") # Constructor variations self.assertEqual(str(pya.ICplxTrans()), "r0 *1 0,0") self.assertEqual(str(pya.ICplxTrans(1.5)), "r0 *1.5 0,0") self.assertEqual(str(pya.ICplxTrans(pya.Trans(1, False, 10, 20), 1.5)), "r90 *1.5 10,20") self.assertEqual(str(pya.ICplxTrans(pya.Trans(1, False, 10, 20))), "r90 *1 10,20") self.assertEqual( str(pya.ICplxTrans(1.5, 80, True, pya.Vector(100, 200))), "m40 *1.5 100,200") self.assertEqual(str(pya.ICplxTrans(1.5, 80, True, 100, 200)), "m40 *1.5 100,200") self.assertEqual(str(pya.ICplxTrans(pya.Vector(100, 200))), "r0 *1 100,200") self.assertEqual(str(pya.ICplxTrans(100, 200)), "r0 *1 100,200") self.assertEqual(str(pya.ICplxTrans(pya.ICplxTrans(100, 200))), "r0 *1 100,200") self.assertEqual(str(pya.ICplxTrans(pya.ICplxTrans(100, 200), 1.5)), "r0 *1.5 150,300") self.assertEqual( str( pya.ICplxTrans(pya.ICplxTrans(100, 200), 1.5, pya.Vector(10, 20))), "r0 *1.5 160,320") self.assertEqual( str(pya.ICplxTrans(pya.ICplxTrans(100, 200), 1.5, 10, 20)), "r0 *1.5 160,320") self.assertEqual(str(pya.DCplxTrans()), "r0 *1 0,0") self.assertEqual(str(pya.DCplxTrans(1.5)), "r0 *1.5 0,0") self.assertEqual( str(pya.DCplxTrans(pya.DTrans(1, False, 0.01, 0.02), 1.5)), "r90 *1.5 0.01,0.02") self.assertEqual(str(pya.DCplxTrans(pya.DTrans(1, False, 0.01, 0.02))), "r90 *1 0.01,0.02") self.assertEqual( str(pya.DCplxTrans(1.5, 80, True, pya.DVector(0.1, 0.2))), "m40 *1.5 0.1,0.2") self.assertEqual(str(pya.DCplxTrans(1.5, 80, True, 0.1, 0.2)), "m40 *1.5 0.1,0.2") self.assertEqual(str(pya.DCplxTrans(pya.DVector(0.1, 0.2))), "r0 *1 0.1,0.2") self.assertEqual(str(pya.DCplxTrans(0.1, 0.2)), "r0 *1 0.1,0.2") self.assertEqual(str(pya.DCplxTrans(pya.DCplxTrans(0.1, 0.2))), "r0 *1 0.1,0.2") self.assertEqual(str(pya.DCplxTrans(pya.DCplxTrans(0.1, 0.2), 1.5)), "r0 *1.5 0.15,0.3") self.assertEqual( str( pya.DCplxTrans(pya.DCplxTrans(0.1, 0.2), 1.5, pya.DVector(0.01, 0.02))), "r0 *1.5 0.16,0.32") self.assertEqual( str(pya.DCplxTrans(pya.DCplxTrans(0.1, 0.2), 1.5, 0.01, 0.02)), "r0 *1.5 0.16,0.32")
def layout_text(cell, layer_text, position, text_string, size): ''' Layout documentation text in layer_text. Not a polygon. Will not be printed. ''' dtext = pya.DText(str(text_string), pya.DTrans( pya.DTrans.R0, position.x, position.y)) dtext.size = size cell.shapes(layer_text).insert(dtext)
CARAVEL_GDS_PATH = "./gds/caravel.gds" USER_GDS_PATH = "./gds/user_project_wrapper.gds" # ly = pya.CellView.active().cell.layout ly = pya.Layout() ly.read(CARAVEL_GDS_PATH) TOP = ly.cell("caravel") # x, y = 326.38500, 1382.01000 for each in TOP.each_inst(): if "user_project_wrapper" in (each.cell.name): x, y = each.dtrans.disp.x, each.dtrans.disp.y print("Placing module at (%f,%f)" % (x, y)) ly.delete_cell(ly.cell_by_name("user_project_wrapper")) ly.read(USER_GDS_PATH) tiles = ly.cell('user_project_wrapper') TOP.insert( pya.DCellInstArray(tiles.cell_index(), pya.DTrans(pya.DTrans.R0, pya.DPoint(x, y)))) for c in ly.top_cells(): if c.name != "caravel": print("removing cell " + c.name) ly.delete_cell(c.cell_index()) ly.write("./gds/caravel_merged.gds")
horizontal = np.concatenate(( np.array([0, 4, 4]), np.full(6, 4))) # Pad to total length 9 with 4's vertical = np.concatenate(( np.array([16, 20, 20]), np.full(6, 20))) # Pad to total length 9 with 20's # Generate the spiral and instantiate its cell paths.delay_spiral_geo(layout, rib, sp, turns=4, spacing=2.5, vertical=vertical, horizontal=horizontal, horizontal_mode='symmetric', vertical_mode='symmetric', quad_shift=0, start_turn=1, start_angle=0, end_angle=0, radial_shift=4.80, n_pts=5000) top.insert(pya.DCellInstArray( sp.cell_index(), pya.DTrans(pya.DVector(0, 30)) )) layout.write(my_constants.gds_models_path + 'test_spiral.gds')
def test_1_DPolygon(self): a = pya.DPolygon() self.assertEqual( str(a), "()" ) self.assertEqual( str(pya.DPolygon.from_s(str(a))), str(a) ) self.assertEqual( a.is_box(), False ) b = a.dup() a = pya.DPolygon( [ pya.DPoint( 0, 1 ), pya.DPoint( 1, 5 ), pya.DPoint( 5, 5 ) ] ) self.assertEqual( str(a), "(0,1;1,5;5,5)" ) self.assertEqual( str(a * 2), "(0,2;2,10;10,10)" ) self.assertEqual( str(pya.DPolygon.from_s(str(a))), str(a) ) self.assertEqual( a.is_box(), False ) self.assertEqual( a.num_points_hull(), 3 ) c = a.dup() self.assertEqual( a == b, False ) self.assertEqual( a == c, True ) self.assertEqual( a != b, True ) self.assertEqual( a != c, False ) a = pya.DPolygon( pya.DBox( 5, -10, 20, 15 ) ) self.assertEqual( a.is_box(), True ) self.assertEqual( str(a), "(5,-10;5,15;20,15;20,-10)" ) self.assertEqual( str(pya.Polygon(a)), "(5,-10;5,15;20,15;20,-10)" ) self.assertEqual( a.num_points_hull(), 4 ) self.assertEqual( a.area(), 15*25 ) self.assertEqual( a.perimeter(), 80 ) self.assertEqual( a.inside( pya.DPoint( 10, 0 ) ), True ) self.assertEqual( a.inside( pya.DPoint( 5, 0 ) ), True ) self.assertEqual( a.inside( pya.DPoint( 30, 0 ) ), False ) arr = [] for p in a.each_point_hull(): arr.append( str(p) ) self.assertEqual( arr, ["5,-10", "5,15", "20,15", "20,-10"] ) b = a.dup() self.assertEqual( str(a.moved( pya.DPoint( 0, 1 ) )), "(5,-9;5,16;20,16;20,-9)" ) self.assertEqual( str(a.moved( 0, 1 )), "(5,-9;5,16;20,16;20,-9)" ) aa = a.dup() aa.move( 1, 0 ) self.assertEqual( str(aa), "(6,-10;6,15;21,15;21,-10)" ) a.move( pya.DPoint( 1, 0 ) ) self.assertEqual( str(a), "(6,-10;6,15;21,15;21,-10)" ) b = b.transformed( pya.DTrans( pya.DTrans.R0, pya.DPoint( 1, 0 )) ) self.assertEqual( str(b), "(6,-10;6,15;21,15;21,-10)" ) m = pya.DCplxTrans( pya.DTrans(), 1.5 ) self.assertEqual( type(a.transformed(m)).__name__, "DPolygon" ) self.assertEqual( str(a.transformed(m)), "(9,-15;9,22.5;31.5,22.5;31.5,-15)" ) m = pya.VCplxTrans( 1000.0 ) self.assertEqual( type(a.transformed(m)).__name__, "Polygon" ) self.assertEqual( str(a.transformed(m)), "(6000,-10000;6000,15000;21000,15000;21000,-10000)" ) a.hull = [ pya.DPoint( 0, 1 ), pya.DPoint( 1, 1 ), pya.DPoint( 1, 5 ) ] self.assertEqual( str(a.bbox()), "(0,1;1,5)" ) self.assertEqual( a.holes(), 0 ) a.insert_hole( [ pya.DPoint( 1, 2 ), pya.DPoint( 2, 2 ), pya.DPoint( 2, 6 ) ] ) self.assertEqual( str(a), "(0,1;1,5;1,1/1,2;2,2;2,6)" ) self.assertEqual( str(pya.DPolygon.from_s(str(a))), str(a) ) self.assertEqual( a.area(), 0 ) self.assertEqual( a.num_points_hole(0), 3 ) self.assertEqual( a.holes(), 1 ) self.assertEqual( str(a.point_hull(1)), "1,5" ) self.assertEqual( str(a.point_hull(0)), "0,1" ) self.assertEqual( str(a.point_hull(100)), "0,0" ) self.assertEqual( str(a.point_hole(0, 100)), "0,0" ) self.assertEqual( str(a.point_hole(0, 1)), "2,2" ) self.assertEqual( str(a.point_hole(1, 1)), "0,0" ) a.compress(False); self.assertEqual( str(a), "(0,1;1,5;1,1/1,2;2,2;2,6)" ) a.compress(True); self.assertEqual( str(a), "(0,1;1,5;1,1/1,2;2,2;2,6)" ) b = a.dup() b.assign_hole(0, pya.DBox( 10, 20, 20, 60 )) self.assertEqual( str(b), "(0,1;1,5;1,1/10,20;20,20;20,60;10,60)" ) b.insert_hole(pya.DBox( 10, 20, 20, 60 )) self.assertEqual( str(b), "(0,1;1,5;1,1/10,20;20,20;20,60;10,60/10,20;20,20;20,60;10,60)" ) self.assertEqual( b.is_box(), False ) b = a.dup() b.assign_hole(0, [ pya.DPoint( 10, 20 ), pya.DPoint( 20, 20 ), pya.DPoint( 20, 60 ) ]) self.assertEqual( str(b), "(0,1;1,5;1,1/10,20;20,20;20,60)" ) b.assign_hole(1, [ pya.DPoint( 15, 25 ), pya.DPoint( 25, 25 ), pya.DPoint( 25, 65 ) ]) self.assertEqual( str(b), "(0,1;1,5;1,1/10,20;20,20;20,60)" ) b.insert_hole( [ pya.DPoint( 1, 2 ), pya.DPoint( 2, 2 ), pya.DPoint( 2, 6 ) ] ) self.assertEqual( str(b), "(0,1;1,5;1,1/1,2;2,2;2,6/10,20;20,20;20,60)" ) b.assign_hole(0, [ pya.DPoint( 15, 25 ), pya.DPoint( 25, 25 ), pya.DPoint( 25, 65 ) ]) self.assertEqual( str(b), "(0,1;1,5;1,1/15,25;25,25;25,65/10,20;20,20;20,60)" ) arr = [] for p in a.each_point_hole(0): arr.append( str(p) ) self.assertEqual( arr, ["1,2", "2,2", "2,6"] ) arr = [] for p in a.each_edge(): arr.append( str(p) ) self.assertEqual( arr, ["(0,1;1,5)", "(1,5;1,1)", "(1,1;0,1)", "(1,2;2,2)", "(2,2;2,6)", "(2,6;1,2)"] ) # Ellipse constructor p = pya.DPolygon.ellipse( pya.DBox(-10000, -20000, 30000, 40000), 200 ) self.assertEqual(p.num_points(), 200) self.assertEqual(str(p.bbox()), "(-10000,-20000;30000,40000)") self.assertEqual(int(p.area()), 1884645544) # roughly box.area*PI/4 p = pya.DPolygon.ellipse( pya.DBox(-10000, -20000, 30000, 40000), 4 ) self.assertEqual(str(p), "(10000,-20000;-10000,10000;10000,40000;30000,10000)")
pya.DPoint(50, 50), pya.DPoint(40.5, 60.6), pya.DPoint(0, 50) ] dpath1 = pya.DPath(dpts, 4, 5, 0, True) top.shapes(l1).insert(pya.Path.from_dpath(dpath1)) #DCplxTrans #倍数,逆时针度数,是否绕x翻转,平移x,平移y tr = pya.DCplxTrans(10, 45, False, 1000, 1000) #xxx.transform(tr)#本身改变 #xxx.transformed(tr)本身不变返回新的 #对一个点pt做变换的方法 #pya.DEdge(pya.DPoint(),pt).transformed(DCplxTrans).p2 #DText text1 = pya.DText("TEST_Text", pya.DTrans(-10, -10), 100, 1) top.shapes(l1).insert(pya.Text.from_dtext(text1)) #a text can be printed @ruby #it dose not work in python #lib.layout.pcell_declaration can't be found ''' begin ly = RBA::Layout.new top = ly.add_cell("TOP") # find the lib lib = RBA::Library.library_by_name("Basic") lib || raise("Unknown lib 'Basic'") # find the pcell pcell_decl = lib.layout.pcell_declaration("TEXT")
sp = layout.create_cell("spiral") # create cell for a delay spiral rib = layout.layer(1, 0) # create strip waveguide layer horizontal = np.concatenate( (np.array([0, 4, 8]), np.full(6, 8))) # Pad to total length 9 with 8's vertical = np.concatenate( (np.array([16, 20, 24]), np.full(6, 24))) # Pad to total length 9 with 24's # Generate the spiral and instantiate its cell paths.delay_spiral_geo(layout, rib, sp, turns=4, spacing=2.5, vertical=vertical, horizontal=horizontal, horizontal_mode='symmetric', vertical_mode='symmetric', quad_shift=0, start_turn=1, start_angle=0, end_angle=0, radial_shift=4.80, n_pts=5000) top.insert(pya.DCellInstArray(sp.cell_index(), pya.DTrans(pya.DVector(0, 30)))) layout.write(my_constants.gds_models_path + 'test_spiral.gds')