Search for a specific sized feature

edited April 2011 in KLayout Development
Can you search for specific sized feature. i.e can I search to find in particular layer
all areas that are 0.7um x 0.7um or smaller? It would be nice to input the x and y size and
have Klayout highlight those features.

Thanks

Scott E.

Comments

  • edited April 2011

    Hi Scott,

    There is no built-in functionality of this kind (yet). However, Here is a script that searches the current layout for shapes with a size smaller than a given threshold. It will install itself in the layer list's context menu (right mouse button) as a menu item "Find Small Shapes On Selected Layers".

    When this menu item is selected, it will ask for a size and scan all selected layers for shapes with a bounding box which is smaller than the given size in both directions. When finished, it will open a marker browser containing all the found shapes.

    This version of the script will report shapes per cell. That means, if a cell is placed twice, a shape inside that cell will be reported only once. That reduces the number of reported items but since a cell can be placed in different orientations, the distinction of x and y size does not make sense then.

    Please also note that this script will report small areas on a per-shape basis. If an area is actually larger, because it is formed by two small adjacent or overlapping shapes, the smaller parts are still reported. The solution to that problem is to merge all shapes before using this function. That is currently not quite efficient for larger layouts and a efficient implementation for that case is the domain of real (expensive) DRC tools.

    Anyway, I hope that script is useful.

    Best regards,

    Matthias

    Here is the script:

    def find_small_shapes
    
      sz = RBA::InputDialog::get_double("Find Objects Smaller Than", "Enter the desired threshold size.\nObjects with a bounding box smaller than the given size (in both directions) are put into a marker DB.", 1.0, 6)
      if ! sz.has_value?
        return
      end
    
      app = RBA::Application.instance
      mw = app.main_window
      view = mw.current_view
      return unless view
    
      layers = view.selected_layers
      return unless layers.size > 0
    
      cv_index = -1
      view.selected_layers.each do |l|
        if cv_index >= 0 
          if l.current.source_cellview(true) >= 0 && cv_index != l.current.source_cellview(true)
            raise "Selected layers must originate from the same layout"
          end
        else
          cv_index = l.current.source_cellview(true)
        end
      end
    
      cv = view.cellview(cv_index)
      return unless cv.is_valid?
    
      layout = cv.layout
      sz_dbu = (sz.value / layout.dbu + 0.5).floor.to_i
    
      dbu_trans = RBA::CplxTrans::new(layout.dbu)
    
      # remove a RDB called "find_small_shapes"
      (0..(view.num_rdbs-1)).each do |rdb_index|
        if view.rdb(rdb_index).name == "find_small_shapes"
          view.remove_rdb(rdb_index)
          break
        end
      end
    
      rdb_index = view.create_rdb("find_small_shapes")
      rdb = view.rdb(rdb_index)
      rdb.top_cell_name = layout.cell_name(cv.cell_index)
    
      view.selected_layers.each do |l|
    
        if cv_index == l.current.source_cellview(true)
    
          layer_index = l.current.layer_index
          if layout.is_valid_layer?(layer_index)
    
            cat_name = l.current.source(true)
            rdb_cat = rdb.create_category(cat_name)
            rdb_cat_id = rdb_cat.rdb_id
    
            cells = layout.cell(cv.cell_index).called_cells
            cells.push(cv.cell_index) 
    
            cells.each do |ci|
    
              rdb_cell = rdb.create_cell(layout.cell_name(ci))
              rdb_cell_id = rdb_cell.rdb_id
    
              cell = layout.cell(ci)
              cell.shapes(layer_index).each do |shape|
    
                bbox = shape.bbox
                if (shape.is_box? || shape.is_polygon? || shape.is_path?) && bbox.width <= sz_dbu && bbox.height <= sz_dbu 
    
                  rdb_item = rdb.create_item(rdb_cell_id, rdb_cat_id)
    
                  if shape.is_box?
                    dbox = shape.box.transformed_cplx(dbu_trans)
                    rdb_item.add_value(RBA::RdbItemValue::new(dbox))
                  elsif shape.is_path?
                    # in 0.21 there are no path markers -> convert to polygon
                    dpath = shape.path.polygon.transformed_cplx(dbu_trans)
                    rdb_item.add_value(RBA::RdbItemValue::new(dpath))
                  elsif shape.is_polygon?
                    dpolygon = shape.polygon.transformed_cplx(dbu_trans)
                    rdb_item.add_value(RBA::RdbItemValue::new(dpolygon))
                  end
    
                end
    
              end
    
            end
    
          end
    
        end
    
      end
    
      # Hint a corresponding cm_... method is missing
      action_path = "tools_menu.browse_markers"
      if mw.menu.is_valid(action_path)
        mw.menu.action(action_path).trigger
      end
    
    end
    
    
    # A helper class for a menu bound action
    class MenuAction < RBA::Action
      def initialize( title, shortcut, &action ) 
        self.title = title
        self.shortcut = shortcut
        @action = action
      end
      def triggered 
        @action.call( self ) 
      end
    private
      @action
    end
    
    # register the function in the toolbar
    # TODO: add shortcut, correct title etc.
    app = RBA::Application.instance
    mw = app.main_window
    
    menu = mw.menu
    menu.insert_separator("@lcp_context_menu.end", "tb_separator")
    menu.insert_item("@lcp_context_menu.end", "find_small_shapes", MenuAction.new("Find Small Shapes On Selected Layers", "") { find_small_shapes })
    
Sign In or Register to comment.