def transform_layer(self, layer_i, trans, trans_ports=False): """ Performs transofmation of the layer desired. Parameters ---------- layer_i : int layer index, >0 trans : Union[DcplxTrans, DTrans] transformation to perform trans_ports : bool If `True` also performs transform of `self.sonnet_ports` as they are vectors. Returns ------- None """ r_cell = Region(self.cell.begin_shapes_rec(layer_i)) r_cell.transform(trans) temp_i = self.cell.layout().layer(pya.LayerInfo(PROGRAM.LAYER1_NUM, 0)) self.cell.shapes(temp_i).insert(r_cell) self.cell.layout().clear_layer(layer_i) self.cell.layout().move_layer(temp_i, layer_i) self.cell.layout().delete_layer(temp_i) if trans_ports: self.sonnet_ports = list( DSimplePolygon( self.sonnet_ports).transform(trans).each_point())
class Element_Base(): def __init__(self, origin, trans_in=None): ## MUST BE IMPLEMENTED ## self.connections = [] # DPoint list with possible connection points self.angle_connections = [] #list with angle of connecting elements self.connection_ptrs = [ ] # pointers to connected structures represented by their class instances ## MUST BE IMLPEMENTED END ## self.origin = origin self.metal_region = Region() self.empty_region = Region() self.metal_region.merged_semantics = False self.empty_region.merged_semantics = False self.DCplxTrans_init = None self.ICplxTrans_init = None if (trans_in is not None): # if( isinstance( trans_in, ICplxTrans ) ): <==== FORBIDDEN if (isinstance(trans_in, DCplxTrans)): self.DCplxTrans_init = trans_in self.ICplxTrans_init = ICplxTrans().from_dtrans(trans_in) elif (isinstance(trans_in, CplxTrans)): self.DCplxTrans_init = DCplxTrans().from_itrans(trans_in) self.ICplxTrans_init = ICplxTrans().from_trans(trans_in) elif (isinstance(trans_in, DTrans)): self.DCplxTrans_init = DCplxTrans(trans_in, 1) self.ICplxTrans_init = ICplxTrans( Trans().from_dtrans(trans_in), 1) elif (isinstance(trans_in, Trans)): self.DCplxTrans_init = DCplxTrans( DTrans().from_itrans(trans_in), 1) self.ICplxTrans_init = ICplxTrans(trans_in, 1) self._init_regions_trans() def init_regions(self): raise NotImplementedError # first it makes trans_init displacement # then the rest of the trans_init # then displacement of the current state to the origin # after all, origin should be updated def _init_regions_trans(self): self.init_regions() # must be implemented in every subclass dr_origin = DSimplePolygon([DPoint(0, 0)]) if (self.DCplxTrans_init is not None): # constructor trans displacement dCplxTrans_temp = DCplxTrans(1, 0, False, self.DCplxTrans_init.disp) self.make_trans(dCplxTrans_temp) dr_origin.transform(dCplxTrans_temp) # rest of the constructor trans functions dCplxTrans_temp = self.DCplxTrans_init.dup() dCplxTrans_temp.disp = DPoint(0, 0) self.make_trans(dCplxTrans_temp) dr_origin.transform(dCplxTrans_temp) # translation to the old origin (self.connections are alredy contain proper values) self.make_trans(DCplxTrans(1, 0, False, self.origin)) # move to the origin self.origin += dr_origin.point(0) def make_trans(self, dCplxTrans): if (dCplxTrans is not None): iCplxTrans = ICplxTrans().from_dtrans(dCplxTrans) self.metal_region.transform(iCplxTrans) self.empty_region.transform(iCplxTrans) self._update_connections(dCplxTrans) self._update_alpha(dCplxTrans) def _update_connections(self, dCplxTrans): if (dCplxTrans is not None): # the problem is, if i construct polygon with multiple points # their order in poly_temp.each_point() doesn't coinside with the # order of the list that was passed to the polygon constructor # so, when i perform transformation and try to read new values through poly_temp.each_point() # they values are rearranged # solution is: i need to create polygon for each point personally, and the initial order presists for i, pt in enumerate(self.connections): poly_temp = DSimplePolygon([pt]) poly_temp.transform(dCplxTrans) self.connections[i] = poly_temp.point(0) def _update_alpha(self, dCplxTrans): if (dCplxTrans is not None): dCplxTrans_temp = dCplxTrans.dup() dCplxTrans_temp.disp = DPoint(0, 0) for i, alpha in enumerate(self.angle_connections): poly_temp = DSimplePolygon([DPoint(cos(alpha), sin(alpha))]) poly_temp.transform(dCplxTrans_temp) pt = poly_temp.point(0) self.angle_connections[i] = atan2(pt.y, pt.x) def _update_origin(self, dCplxTrans): if (dCplxTrans is not None): poly_temp = DSimplePolygon([self.origin]) poly_temp.transform(dCplxTrans) self.origin = poly_temp.point(0) def place(self, dest, layer_i=-1): r_cell = None if (layer_i != -1): r_cell = Region(dest.begin_shapes_rec(layer_i)) # how to interpret destination if (layer_i == -1): dest += self.metal_region dest -= self.empty_region else: temp_i = dest.layout().layer(pya.LayerInfo(PROGRAM.LAYER1_NUM, 0)) dest.shapes(temp_i).insert(r_cell + self.metal_region - self.empty_region) dest.layout().clear_layer(layer_i) dest.layout().move_layer(temp_i, layer_i) dest.layout().delete_layer(temp_i)
class Element_Base(): ''' @brief: base class for simple single-layer or multi-layer elements and objects that are consisting of several polygons. metal_region polygons will be added to the design empty_region polygons will be erased from the background with metal region polygons already added. ''' def __init__(self, origin, trans_in=None, inverse=False): ## MUST BE IMPLEMENTED ## self.connections = [] # DPoint list with possible connection points self.connection_edges = [ ] # indexes of edges that are intended to connect to other polygons # indexes in "self.connection_edges" where Sonnet ports # should be placed self.sonnet_port_connections = [] self.angle_connections = [] #list with angle of connecting elements ## MUST BE IMLPEMENTED END ## self.connection_ptrs = [ ] # pointers to connected structures represented by their class instances self.origin = origin self.inverse = inverse self.metal_region = Region() self.empty_region = Region() self.metal_regions = {} self.empty_regions = {} self.metal_regions["default"] = self.metal_region self.empty_regions["default"] = self.empty_region self.metal_region.merged_semantics = True self.empty_region.merged_semantics = True self.DCplxTrans_init = None self.ICplxTrans_init = None if (trans_in is not None): # if( isinstance( trans_in, ICplxTrans ) ): <==== FORBIDDEN if (isinstance(trans_in, DCplxTrans)): self.DCplxTrans_init = trans_in self.ICplxTrans_init = ICplxTrans().from_dtrans(trans_in) elif (isinstance(trans_in, CplxTrans)): self.DCplxTrans_init = DCplxTrans().from_itrans(trans_in) self.ICplxTrans_init = ICplxTrans().from_trans(trans_in) elif (isinstance(trans_in, DTrans)): self.DCplxTrans_init = DCplxTrans(trans_in, 1) self.ICplxTrans_init = ICplxTrans( Trans().from_dtrans(trans_in), 1) elif (isinstance(trans_in, Trans)): self.DCplxTrans_init = DCplxTrans( DTrans().from_itrans(trans_in), 1) self.ICplxTrans_init = ICplxTrans(trans_in, 1) self._init_regions_trans() def init_regions(self): raise NotImplementedError # first it makes trans_init displacement # then the rest of the trans_init # then displacement of the current state to the origin # after all, origin should be updated def _init_regions_trans(self): self.init_regions() # must be implemented in every subclass dr_origin = DSimplePolygon([DPoint(0, 0)]) if (self.DCplxTrans_init is not None): # constructor trans displacement dCplxTrans_temp = DCplxTrans(1, 0, False, self.DCplxTrans_init.disp) self.make_trans(dCplxTrans_temp) dr_origin.transform(dCplxTrans_temp) # rest of the constructor trans functions dCplxTrans_temp = self.DCplxTrans_init.dup() dCplxTrans_temp.disp = DPoint(0, 0) self.make_trans(dCplxTrans_temp) dr_origin.transform(dCplxTrans_temp) # translation to the old origin (self.connections are already contain proper values) self.make_trans(DCplxTrans(1, 0, False, self.origin)) # move to the origin self.origin += dr_origin.point(0) def make_trans(self, dCplxTrans): if (dCplxTrans is not None): iCplxTrans = ICplxTrans().from_dtrans(dCplxTrans) self.metal_region.transform(iCplxTrans) self.empty_region.transform(iCplxTrans) self._update_connections(dCplxTrans) self._update_alpha(dCplxTrans) def _update_connections(self, dCplxTrans): if (dCplxTrans is not None): # the problem is, if i construct polygon with multiple points # their order in poly_temp.each_point() doesn't coinside with the # order of the list that was passed to the polygon constructor # so, when i perform transformation and try to read new values through poly_temp.each_point() # they values are rearranged # solution is: i need to create polygon for each point personally, and the initial order presists for i, pt in enumerate(self.connections): poly_temp = DSimplePolygon([pt]) poly_temp.transform(dCplxTrans) self.connections[i] = poly_temp.point(0) def _update_alpha(self, dCplxTrans): if (dCplxTrans is not None): dCplxTrans_temp = dCplxTrans.dup() dCplxTrans_temp.disp = DPoint(0, 0) for i, alpha in enumerate(self.angle_connections): poly_temp = DSimplePolygon([DPoint(cos(alpha), sin(alpha))]) poly_temp.transform(dCplxTrans_temp) pt = poly_temp.point(0) self.angle_connections[i] = atan2(pt.y, pt.x) def _update_origin(self, dCplxTrans): if (dCplxTrans is not None): poly_temp = DSimplePolygon([self.origin]) poly_temp.transform(dCplxTrans) self.origin = poly_temp.point(0) def place(self, dest, layer_i=-1, region_name=None, merge=False): r_cell = None metal_region = None empty_region = None if (region_name == None): metal_region = self.metal_region empty_region = self.empty_region else: if (region_name in self.metal_regions): metal_region = self.metal_regions[region_name] else: metal_region = Region() if (region_name in self.empty_regions): empty_region = self.empty_regions[region_name] else: empty_region = Region() if (layer_i != -1): r_cell = Region(dest.begin_shapes_rec(layer_i)) temp_i = dest.layout().layer(pya.LayerInfo(PROGRAM.LAYER1_NUM, 0)) r_cell += metal_region r_cell -= empty_region if (merge is True): r_cell.merge() dest.shapes(temp_i).insert(r_cell) dest.layout().clear_layer(layer_i) dest.layout().move_layer(temp_i, layer_i) dest.layout().delete_layer(temp_i) if (layer_i == -1 ): # dest is interpreted as instance of Region() class dest += metal_region dest -= empty_region if (merge is True): dest.merge() def add_sonnet_port(self, connection_idx): ''' @brief: sets internal marker that during export to Sonnet the port should be placed at the connection edge with an index 'connection_idx' ''' print(self.connections) self.sonnet_port_connections.append(self.connections[connection_idx])
class Element_Base(): ''' @brief: base class for simple single-layer or multi-layer elements and objects that are consisting of several polygons. metal_region polygons will be added to the design empty_region polygons will be erased from the background with metal region polygons already added. ''' def __init__(self, origin, trans_in=None, inverse=False): ## MUST BE IMPLEMENTED ## self.connections = [] # DPoint list with possible connection points self.connection_edges = [ ] # indexes of edges that are intended to connect to other polygons # indexes in "self.connection_edges" where Sonnet ports # should be placed self.sonnet_port_connections = [] self.angle_connections = [] # list with angle of connecting elements ## MUST BE IMLPEMENTED END ## self.connection_ptrs = [ ] # pointers to connected structures represented by their class instances self.origin = origin self.inverse = inverse self.metal_region = Region() self.empty_region = Region() self.metal_regions = {} self.empty_regions = {} self.metal_regions["default"] = self.metal_region self.empty_regions["default"] = self.empty_region self.metal_region.merged_semantics = True self.empty_region.merged_semantics = True self.DCplxTrans_init = None self.ICplxTrans_init = None if (trans_in is not None): # if( isinstance( trans_in, ICplxTrans ) ): <==== FORBIDDEN if (isinstance(trans_in, DCplxTrans)): self.DCplxTrans_init = trans_in self.ICplxTrans_init = ICplxTrans().from_dtrans(trans_in) elif (isinstance(trans_in, CplxTrans)): self.DCplxTrans_init = DCplxTrans().from_itrans(trans_in) self.ICplxTrans_init = ICplxTrans().from_trans(trans_in) elif (isinstance(trans_in, DTrans)): self.DCplxTrans_init = DCplxTrans(trans_in, 1) self.ICplxTrans_init = ICplxTrans( Trans().from_dtrans(trans_in), 1) elif (isinstance(trans_in, Trans)): self.DCplxTrans_init = DCplxTrans( DTrans().from_itrans(trans_in), 1) self.ICplxTrans_init = ICplxTrans(trans_in, 1) self._geometry_parameters = OrderedDict() self._init_regions_trans() def get_geometry_params_dict(self, prefix="", postfix=""): """ Function return geometry parameters in format: dict[prefix + key + postfix, value] Parameters ---------- prefix : str postfix : str Returns ------- dict """ if hasattr(self, "_geometry_parameters"): tmp_dict = {} for key, item in self._geometry_parameters.items(): tmp_dict[prefix + key + postfix] = item return tmp_dict else: print("Geometry parameters for ", self.__class__, " does not implemented") return None def init_regions(self): raise NotImplementedError # first it makes trans_init displacement # then the rest of the trans_init # then displacement of the current state to the origin # after all, origin should be updated def _init_regions_trans(self): self.init_regions() # must be implemented in every subclass dr_origin = DSimplePolygon([DPoint(0, 0)]) if (self.DCplxTrans_init is not None): # constructor trans displacement dCplxTrans_temp = DCplxTrans(1, 0, False, self.DCplxTrans_init.disp) self.make_trans(dCplxTrans_temp) dr_origin.transform(dCplxTrans_temp) # rest of the constructor trans functions dCplxTrans_temp = self.DCplxTrans_init.dup() dCplxTrans_temp.disp = DPoint(0, 0) self.make_trans(dCplxTrans_temp) dr_origin.transform(dCplxTrans_temp) # translation to the old origin (self.connections are already contain proper values) self.make_trans(DCplxTrans(1, 0, False, self.origin)) # move to the origin self.origin += dr_origin.point(0) def make_trans(self, dCplxTrans): if (dCplxTrans is not None): iCplxTrans = ICplxTrans().from_dtrans(dCplxTrans) self.metal_region.transform(iCplxTrans) self.empty_region.transform(iCplxTrans) self._update_connections(dCplxTrans) self._update_alpha(dCplxTrans) def _update_connections(self, dCplxTrans): if (dCplxTrans is not None): # the problem is, if i construct polygon with multiple points # their order in poly_temp.each_point() doesn't coinside with the # order of the list that was passed to the polygon constructor # so, when i perform transformation and try to read new values through poly_temp.each_point() # they values are rearranged # solution is: i need to create polygon for each point personally, and the initial order presists for i, pt in enumerate(self.connections): poly_temp = DSimplePolygon([pt]) poly_temp.transform(dCplxTrans) self.connections[i] = poly_temp.point(0) self._refresh_named_connections() def _refresh_named_connections(self): """ if there is connections in `self.connections` that have specific class attribute e.g. `self.end` is assumed to coincide with `self.connections[1]`, then this function is used to update this correspondance after connections are changed due to call of `self.make_trans`. See ClassLib.Coplanars.CPW class for example. """ # can be implemented in child class # see ClassLib.Coplanars.CPW for example pass def _update_alpha(self, dCplxTrans): if (dCplxTrans is not None): dCplxTrans_temp = dCplxTrans.dup() dCplxTrans_temp.disp = DPoint(0, 0) for i, alpha in enumerate(self.angle_connections): poly_temp = DSimplePolygon([DPoint(cos(alpha), sin(alpha))]) poly_temp.transform(dCplxTrans_temp) pt = poly_temp.point(0) self.angle_connections[i] = atan2(pt.y, pt.x) self._refresh_named_angles() def _refresh_named_angles(self): """ If there is angles in `self.angle_connections` that have specific class attribute e.g. `self.end_angle` is assumed to coincide with `self.angle_connections[1]`, then this function is used to update this correspondance after connections are changed due to call of `self.make_trans`. See ClassLib.Coplanars.CPW class for example. """ pass def _update_origin(self, dCplxTrans): if (dCplxTrans is not None): poly_temp = DSimplePolygon([self.origin]) poly_temp.transform(dCplxTrans) self.origin = poly_temp.point(0) def place(self, dest, layer_i=-1, region_name=None, merge=False): r_cell = None metal_region = None empty_region = None if (region_name == None): metal_region = self.metal_region empty_region = self.empty_region else: if (region_name in self.metal_regions): metal_region = self.metal_regions[region_name] else: metal_region = Region() if (region_name in self.empty_regions): empty_region = self.empty_regions[region_name] else: empty_region = Region() if (layer_i != -1): r_cell = Region(dest.begin_shapes_rec(layer_i)) temp_i = dest.layout().layer(pya.LayerInfo(PROGRAM.LAYER1_NUM, 0)) r_cell += metal_region r_cell -= empty_region if (merge is True): r_cell.merge() dest.shapes(temp_i).insert(r_cell) dest.layout().clear_layer(layer_i) dest.layout().move_layer(temp_i, layer_i) dest.layout().delete_layer(temp_i) if (layer_i == -1 ): # dest is interpreted as instance of Region() class dest += metal_region dest -= empty_region if (merge is True): dest.merge()