want advice on Ruby scripting using LayoutView::SelectionMode and LayoutView::select_from

I have found an issue in my Ipc2581 import script where I need to change specific drill hole shapes from one layer to another...
the location of these shapes are stored in the array _tmp_pts
Below is the new code I have developed:

    if _layname.match(/BACKDRILL_/)
      ### the next 4 lines don't work correctly...
      _view = RBA::LayoutView::current
      _view.each_layer do |_lref|
         _lref.visible = false
      end
      #LayoutView::SelectionMode Reset 
      #LayoutView::SelectionMode Add
      #_tmp_pts.each {|_pt|
      #    LayoutView::select_from(_pt, LayoutView::SelectionMode mode = Add)
      #}
      _sel = _lv.object_selection
      _sel.each do |_s|
          _s.layer = _drl_lay
      end
      _lv.object_selection = _sel
      _tmp_pts.clear
      ### the next 4 lines don't work correctly...
      _view = RBA::LayoutView::current
      _view.each_layer do |_lref|
         _lref.visible = true
       end
    end

Comments

  • Hi @mtnhomecad,

    What exactly is the problem?

    You mention that the 4 lines do not work. Does it mean that layer are not made invisible or visible?

    I can't confirm this is not working.

    Matthias

  • Hi Matthias,
    I apologize for not including enough info for you to understand the issues I am seeing...
    First - the screen capture of the Macro Development window below shows that when I continue the breakpoint at line 483 goes to line 491, skipping line 484:

    Second - could you provide an script example of using
    LayoutView::select_from(_pt, LayoutView::SelectionMode mode = Add)

    Lastly, what is the correct to change a shape's layer?
    Below is my latest code, but fails at the layer assignment :(

              _layname = _drl_thmt
              _num_lay = 100 
              _layer_id = _layout.find_layer(_num_lay,0,_layname)
              _num_lay = _layout.layer(100,0) 
              _thmt_shapes = _top_cell.shapes(_num_lay)
              _shapes_to_change = []
              _tmp_pts.each do |_pt|
                 _thmt_shapes.each do |_ts|
                    _box = _ts.dbbox()
                    if _box.contains?(_pt)
                       _shapes_to_change.push(_ts)
                       break
                    end
                 end
              end
              _shapes_to_change.each do |_ts|
                _ts.layer=_drl_lay ### fails here
              end
    
  • Hi @mtnhomecad,

    About the debugger: it should stop at 484, unless you do not have any layers in your view:

    The "select_from" example is simple:

    x = 0.0
    x = 10.0
    view.select_from(RBA::DPoint::new(x, y), RBA::LayoutView::SelectionMode::Add)
    

    x and y are the coordinates where you want to select items from (in micrometer units).

    And finally regarding the layer assignment: you can't change the layer of a shape. You need to move the shape from one "Shapes" container to the other:

    _to_shapes = _top_cell.shapes(_drl_lay)
    _shapes_to_change.each do |_ts|
      _to_shapes.insert(_ts)
      _ts.delete
    end
    

    BTW: why the leading underscores?

    Matthias

  • Hi Matthias,
    Thank you for the feedback, which was very helpful.

    I just found a new issue where I need your advice:
    I am getting the error: NoMethodError: undefined method `position' for #
    however in the previous lines of code I have: if _ts.is_text?

    A screen capture is shown below:

  • How do you delete Path or Text object from a script, since neither have a delete method?

  • edited July 2024

    The Shape class does not have a "position" method.

    "Shape" is not a base class of "Text". Instead "Shape" is a generic shape. You can turn it into a Text object, and then use "position":

    shape.text.position
    

    But this shortcut is faster:

    shape.text_pos
    

    The concept is explained here: https://www.klayout.de/doc-qt5/programming/database_api.html#k_8

    To remove a shape from the database, use "shape.delete". The type of shape does not matter.

    However, doing this during iteration is not safe - in particular not in viewer mode. The recommended way is to collect the shapes for deletion first and then delete them:

    to_delete = []
    shapes.each do |shape|
      if shape_needs_to_be_deleted(shape)
        to_delete << shape
      end
    end
    
    # or short:
    # to_delete = shapes.each.select { |shape| shape_needs_to_be_deleted(shape) }
    
    to_delete.each do |shape|
      shape.delete
    end
    

    Matthias

  • Per your feedback I updated the code to move the shape from one "Shapes" container to another and delete the original shapes afterwards:

            if _layname.match(/BACKDRILL_/)
               _begin_cnt = 0
               _top_cell.each_shape(_drl_lay) do |_ts|
                   _begin_cnt +=1
               end
              _num_lay = _layout.layer(100,0) 
              _to_delete = []
              _tmp_pts.each do |_pt|
                 _top_cell.each_shape(_num_lay) do |_ts|
                    _box = _ts.bbox()
                    if _box.contains?(_pt)
                       _top_cell.shapes(_drl_lay).insert(_ts)
                       _to_delete << _ts
                    end
                 end
              end
              _to_delete.each do |_shape|
                 _shape.delete
              end
           #
              _end_cnt = 0
              _top_cell.each_shape(_drl_lay) do |_ts|
                   _end_cnt +=1
              end
              puts "drl_lay "  << "#{_drl_lay}" << " Begin cnt "  << " #{_begin_cnt}"  << " End cnt "  << " #{_end_cnt}"  
            end
    

    The 'Macro Development Console' shows that the shapes were copied:

    Reading layname BACKDRILL_12-4 number 101
    Creating layname DRILL_1-3 number 102
    drl_lay 102 Begin cnt  0 End cnt  22
    

    However the Layers tab in the resulting design shows the layer as being empty:

    Do you any idea why this is happening?

  • I am not sure if you are using the layer numbers correctly. I don't see the whole script.

    But here is a hint: "_drl_lay" has number 102, but it is not layer "102/0".

    When you use:

    _num_lay = _layout.layer(100,0) 
    

    then _num_lay can be any number, KLayout assigns to layer "102/0". "102/0" is the database "name" (in GDS). In other formats, this "name" is not numeric, but a string. In OASIS for example, it can be both.

    So: if you want "_drl_lay" to be layer 102/0, then you have to use something like

    _drl_lay = _layout.layer(102,0)
    

    Matthias

  • Matthias,

    Thank you for isolating the error in my code, per your advice it is working correctly now...

    I also made another code change by changing the '-' characters in the layer names to '_' after getting errors when loading the generated netlist .l2n files, they load correctly now :smile:

Sign In or Register to comment.