def run_script(self, filename, p1=None, p2=None): """ Run .pyxs script filename : str path to the .pyxs script """ view = Application.instance().main_window().current_view() if not view: raise UserWarning("No view open for running the pyxs script") if p1 is None or p2 is None: app = Application.instance() scr_view = app.main_window().current_view() # type: LayoutView scr_view_idx = app.main_window().current_view_index if not scr_view: MessageBox.critical( "Error", "No view open for creating the cross-" "section from", MessageBox.b_ok(), ) return False rulers = [] for a in scr_view.each_annotation(): rulers.append(a) if len(rulers) == 0: MessageBox.critical( "Error", "No ruler present for the cross " "section line", MessageBox.b_ok(), ) return None p1_arr, p2_arr, ruler_text_arr = [], [], [] for ruler in rulers: p1_arr.append(ruler.p1) p2_arr.append(ruler.p2) ruler_text_arr.append(ruler.text().split('.')[0]) else: p1_arr, p2_arr, ruler_text_arr = [p1], [p2], [''] scr_view_idx = None target_views = [] for p1_, p2_, text_ in zip(p1_arr, p2_arr, ruler_text_arr): if scr_view_idx: # return to the original view to run it again app.main_window().select_view(scr_view_idx) view = XSectionGenerator(filename).run(p1_, p2_, text_) target_views.append(view) return target_views
def run(self, p1, p2, ruler_text=None): """ Parameters ---------- ruler_text : str identifier to be used to name a new cross-section cell Returns ------- LayoutView """ self._target_view = None self._target_cell_name = "PYXS: " + ruler_text if ruler_text else "XSECTION" self._cell_file_name = "PYXS_" + ruler_text if ruler_text else "XSECTION" self._setup(p1, p2) self._update_basic_regions() text = None try: with open(self._file_name, 'r') as file: text = file.read() except Exception as e: MessageBox.critical("Error", "Error reading file {}. \n\nError: {}" .format(self._file_name, e), MessageBox.b_ok()) return None if text is None: MessageBox.critical("Error", "Error reading file {}." .format(self._file_name), MessageBox.b_ok()) return None # prepare variables to be visible in the script locals_ = dir(self) locals_dict = {} for attr in locals_: if attr[0] != '_': locals_dict.update({attr: getattr(self, attr)}) try: exec(text, locals_dict) except Exception as e: # For development # print(e.__traceback__.) # print(dir(e)) MessageBox.critical("Error", str(e), MessageBox.b_ok()) # pass return None Application.instance().main_window().cm_lv_add_missing() # @@@ self._finalize_view() return self._target_view
def _setup(self, p1, p2): """ Parameters ---------- p1 : Point first point of the ruler p2 : Point second point of the ruler """ # locate the layout app = Application.instance() view = app.main_window().current_view() # LayoutView if not view: MessageBox.critical( "Error", "No view open for creating the cross-" "section from", MessageBox.b_ok(), ) return False cv = view.cellview(view.active_cellview_index()) # CellView if not cv.is_valid(): MessageBox.critical("Error", "The selected layout is not valid", MessageBox.b_ok()) return False self._cv = cv # CellView self._layout = cv.layout() # Layout self._dbu = self._layout.dbu self._cell = cv.cell_index # int # get the start and end points in database units and micron p1_dbu = Point.from_dpoint(p1 * (1.0 / self._dbu)) p2_dbu = Point.from_dpoint(p2 * (1.0 / self._dbu)) self._line_dbu = Edge(p1_dbu, p2_dbu) # Edge describing the ruler # initialize height and depth self._extend = int_floor(2.0 / self._dbu + 0.5) # 2 um in dbu self._delta = 10 self._height = int_floor(2.0 / self._dbu + 0.5) # 2 um in dbu self._depth = int_floor(2.0 / self._dbu + 0.5) # 2 um in dbu self._below = int_floor(2.0 / self._dbu + 0.5) # 2 um in dbu info(' XSG._dbu is: {}'.format(self._dbu)) info(' XSG._extend is: {}'.format(self._extend)) info(' XSG._delta is: {}'.format(self._delta)) info(' XSG._height is: {}'.format(self._height)) info(' XSG._depth is: {}'.format(self._depth)) info(' XSG._below is: {}'.format(self._below)) return True
def run(self): """ The basic generation method """ if not self._setup(): return None self._update_basic_regions() text = None with open(self._file_path) as file: text = file.read() if not text: MessageBox.critical("Error", "Error reading file #{self._file_path}", MessageBox.b_ok()) return None # prepare variables to be visible in the script locals_ = dir(self) locals_dict = {} for attr in locals_: if attr[0] != '_': locals_dict.update({attr: getattr(self, attr)}) try: exec(text, locals_dict) except Exception as e: # For development # print(e.__traceback__.) # print(dir(e)) MessageBox.critical("Error", str(e), MessageBox.b_ok()) # pass return None Application.instance().main_window().cm_lv_add_missing() # @@@ if self._lyp_file: self._target_view.load_layer_props(self._lyp_file) self._target_view.zoom_fit() self._target_layout.write(self._target_gds_file_name) info(' len(bulk.data) = {}'.format(len(self._bulk.data))) self._tech_str = '# This file was generated automatically by pyxs.\n\n'\ + layer_to_tech_str(255, self._bulk.data[0], 'Substrate') + self._tech_str with open(self._target_tech_file_name, 'w') as f: f.write(self._tech_str) return None
def _on_triggered_callback(): """ Load pyxs script menu action. Load new .pyxs file and run it. """ view = Application.instance().main_window().current_view() if not view: MessageBox.critical( "Error", "No view open for creating the cross-" "section from", MessageBox.b_ok(), ) return None filename = FileDialog.get_open_file_name( "Select cross-section script", "", "XSection Scripts (*.pyxs);;All Files (*)", ) # run the script and save it if filename.has_value(): self.run_script(filename.value()) self.make_mru(filename.value())
def _setup(self): # locate the layout app = Application.instance() view = app.main_window().current_view() # LayoutView if not view: MessageBox.critical( "Error", "No view open for creating the cross " "section from", MessageBox.b_ok()) return False # locate the (single) ruler rulers = [] n_rulers = 0 for a in view.each_annotation(): # Use only rulers with "plain line" style # print(a.style) # print(Annotation.StyleLine) # if a.style == Annotation.StyleLine: rulers.append(a) n_rulers += 1 # if n_rulers == 0 or n_rulers >= 2: # MessageBox.info("No rulers", # "Number of rulers is not equal to one. " # "Will be exporting the whole layout", # pya.MessageBox.b_ok()) # if n_rulers == 1: # MessageBox.info( # "Box export", "One ruler is present for the cross " # "section line. Will be exporting only shapes in the box", # pya.MessageBox.b_ok()) cv = view.cellview(view.active_cellview_index()) # CellView if not cv.is_valid(): MessageBox.critical("Error", "The selected layout is not valid", MessageBox.b_ok()) return False self._cv = cv # CellView self._layout = cv.layout() # Layout self._dbu = self._layout.dbu self._cell = cv.cell_index # int if n_rulers == 1: # get the start and end points in database units and micron p1_dbu = Point.from_dpoint(rulers[0].p1 * (1.0 / self._dbu)) p2_dbu = Point.from_dpoint(rulers[0].p2 * (1.0 / self._dbu)) self._box_dbu = Box(p1_dbu, p2_dbu) # box describing the ruler else: # TODO: choose current cell, not top cell top_cell = self._layout.top_cell() p1_dbu = (top_cell.bbox().p1 * (1.0 / self._dbu)).dup() p1_dbu = top_cell.bbox().p1.dup() p2_dbu = (top_cell.bbox().p2 * (1.0 / self._dbu)).dup() p2_dbu = top_cell.bbox().p2.dup() self._box_dbu = Box(p1_dbu, p2_dbu) # box describing the top cell info('XSG._box_dbu to be used is: {}'.format(self._box_dbu)) # create a new layout for the output cv = app.main_window().create_layout(1) cell = cv.layout().add_cell("XSECTION") self._target_view = app.main_window().current_view() self._target_view.select_cell(cell, 0) self._target_layout = cv.layout() self._target_layout.dbu = self._dbu self._target_cell = cell # initialize height and depth self._extend = int_floor(2.0 / self._dbu + 0.5) # 2 um in dbu self._delta = 10 self._height = int_floor(2.0 / self._dbu + 0.5) # 2 um in dbu self._depth = int_floor(2.0 / self._dbu + 0.5) # 2 um in dbu self._below = int_floor(2.0 / self._dbu + 0.5) # 2 um in dbu info(' XSG._dbu is: {}'.format(self._dbu)) info(' XSG._extend is: {}'.format(self._extend)) info(' XSG._delta is: {}'.format(self._delta)) info(' XSG._height is: {}'.format(self._height)) info(' XSG._depth is: {}'.format(self._depth)) info(' XSG._below is: {}'.format(self._below)) return True
def output_all(self, output_layers=None, script_globals=None, new_target_layout=True, step_name=None, save_png=None, *args): """Output a list of material objects to the output layout A list of materials is passed through an output_layers dictionary. Parameters ---------- output_layers : Dict[LayoutData, str] or Dict[str, str] Key is either LayoutData instance, or a name of such instance instance in script_globals. Value is the layer specification (see layer_spec in output()). script_globals : Dict[str, Any] globals() dictionary new_target_layout : bool if True, a new target layout will be created step_name : str name extension for the newly created layout save_png : bool if True, the resulting view will be saved as an image in the gds file folder """ if script_globals is None: script_globals = {} if new_target_layout: if self._is_target_layout_created: self._finalize_view() self._create_new_layout(cell_name_extension=step_name) if output_layers: ol = output_layers elif self._output_all_parameters['output_layers']: ol = self._output_all_parameters['output_layers'] else: return None for ld, ls in ol.items(): if isinstance(ld, str): if ld == 'air': a = self.air() self.output(layer_spec=ls, layer_data=a) # elif ld in list(globals.keys()): # print('yes', ld, 'in globals') # self.output(layer_spec=ls, # layer_data=globals[ld]) elif ld in list(script_globals.keys()): self.output(layer_spec=ls, layer_data=script_globals[ld]) else: # skip a non-existing (yet) material continue else: self.output(layer_spec=ls, layer_data=ld) if save_png is not None: sp = save_png else: sp = self._output_all_parameters['save_png'] if sp: self._finalize_view() if step_name: file_name = '{} ({}).png'.format(self._cell_file_name, step_name) else: file_name = '{}.png'.format(self._cell_file_name) if self._output_all_parameters['png_path']: file_name = os.path.join( self._output_all_parameters['png_path'], file_name) else: file_name = os.path.join(self._file_path, file_name) try: self._target_view.save_image( file_name, self._area.width() / 100, self._area.height() / 100, ) except Exception as e: if not self._hide_png_save_error: MessageBox.critical( "Error", "Error saving png file {}. \n\n Error: {}. \n\n" "Further error messages will not be displayed.".format( file_name, e), MessageBox.b_ok(), ) self._hide_png_save_error = True return None