Selecting newly created shapes

edited November 2015 in Ruby Scripting

Hi Matthias,

My script creates some shapes, and I'd like to have them selected when finished (to make it obvious to the user which ones were just created).

The documentation describes how to find shapes to get their "ObjectInstPath":
http://www.klayout.de/doc/code/class_ObjectInstPath.html

But I don't see how to get this for a newly created shape.

    new_wg = cell.shapes(layer).insert(wg_path)

new_wg is a <pya.Shape object at 0x11cb50bd0>.

Is there a way to construct my own ObjectInstPath, so that I can select it?

    lv.object_selection = ObjectInstPath

In my case, my script starts off with a selected object (a PCell), and finishes with a newly created shape. Perhaps the "dup" method could be used, but I'm not sure if would work for mixing cells vs. shapes.

Also, is there any way to get a history of ObjectInstPath items that were added to a layout? Like a history? For example, if a script starts with nothing selected, could it automatically figure out which shape was added most recently?

Comments

  • edited November -1

    Hi Lukas,

    that should be possible.

    First of all, "object_selection" is an array of ObjectInstPath objects.

    An ObjectInstPath is - as the name applies - an instantiation path to an object. In the simple case, you refer to a shape in the top cell. You have to prepare an ObjectInstPath object with these attributes at least:

    • top: the cell index of the current cell (cell.cell_index)
    • cv_index: the cellview index you are working in (usually 0)
    • shape: the new shape's Shape object (new_wg)
    • layer: the layer index the shape is on (layer)

    So the code should look like (not tested):

    new_wg = cell.shapes(layer).insert(wg_path)
    
    p = RBA::ObjectInstPath::new
    p.layer = layer
    p.shape = new_wg
    p.top = cell.cell_index
    p.cv_index = 0      # may not be correct, if you have loaded more than one file into this view
    lv.object_selection = [ p ]
    

    Matthias

  • edited November 2015

    Thank you. I got it working for shapes, but not for cells / instances.

    In your ObjectInstPath documentation, http://www.klayout.de/doc/code/class_ObjectInstPath.html, you don't have cell_index= or inst=, as a settable item.

    Do I need to use append_path InstElement? If so, is it just the last instance, or do I need the whole hierarchy?

    I tried looking in the IDE debugger to see what an ObjectInstPath looks like, but all that is in the Local variables viewer is: cv_index, layer (Error: in the case of a selected ROUND_PATH PCell), seq, shape (Error: in the case of a selected ROUND_PATH PCell), and top. So I wasn't able to figure it out.

    Here's what I tried:

    # new objects will become selected
    new_selection = []
    
    for o in object_selection:
        # do things to selection
    
        pcell = ly.create_cell("ROUND_PATH", "Basic", param )
        t = pya.Trans(0, 0)
        new_cell = cell.insert(pya.CellInstArray(pcell.cell_index(), t))
    
        # Leave the newly created waveguide selected, to make it obvious to the user.
        # http://klayout.de/forum/comments.php?DiscussionID=747
        new_selectionN = len(new_selection)
        new_selection.append( pya.ObjectInstPath() )
        new_selection[new_selectionN].layer = LayerSiN
        new_selection[new_selectionN].cell_index = pcell.cell_index()
        # or try, new_selection[new_selectionN].cell_index = new_cell
        new_selection[new_selectionN].top = o.top
        new_selection[new_selectionN].cv_index = o.cv_index
    
    # Select the newly added objects
    lv.object_selection = new_selection
    

    For the shapes, the following worked, with the same wrapper:

    new_wg = cell.shapes(LayerSiN).insert(wg_path_trans)
    
    # Leave the newly created waveguide selected, to make it obvious to the user.
    # http://klayout.de/forum/comments.php?DiscussionID=747
    new_selectionN = len(new_selection)
    new_selection.append( pya.ObjectInstPath() )
    new_selection[new_selectionN].layer = LayerSiN
    new_selection[new_selectionN].shape = new_wg
    new_selection[new_selectionN].top = o.top
    new_selection[new_selectionN].cv_index = o.cv_index
    
  • edited November -1

    Hi Lukas,

    you're right, instance selections are formed by appending the instance to the path but not assigning a shape. This will implicitly make the selected object a cell instance selection:

    op = RBA::ObjectInstPath::new
    op.top = top_cell.cell_index
    op.append_path(RBA::InstElement::new(inst_to_select))     # must be a RBA::Instance taken from the top cell
    
    # now:
    op.is_cell_inst? # -> true
    

    Matthias

  • edited November -1

    As above, but changing to:

        new_cell = cell.insert(pya.CellInstArray(pcell.cell_index(), t))
    
        new_selectionN = len(new_selection)
    
        new_selection.append( pya.ObjectInstPath() )
        new_selection[new_selectionN].top = o.top
        new_selection[new_selectionN].append_path = pya.InstElement.new(new_cell)
    
        print (new_selection[new_selectionN].is_cell_inst() )
    

    The latest statement comes back as "True". But nothing appears selected. And when I Edit | Properties, I get an error:

    Internal error: /Users/sekigawakazunari/SVNWork/klayout-0.24.3/src/dbInstances.h:205 m_type == TInstance was not true
    

    followed by a crash.

    So I created a stand-alone script. I create a blank layout, and run the script. But I get the same behaviour / error message.

    import pya
    
    # Configure variables to draw structures in the presently selected cell:
    lv = pya.Application.instance().main_window().current_view()
    if lv == None:
      raise Exception("No view selected")
    # Find the currently selected layout.
    ly = pya.Application.instance().main_window().current_view().active_cellview().layout() 
    if ly == None:
      raise Exception("No layout")
    # find the currently selected cell:
    cell = pya.Application.instance().main_window().current_view().active_cellview().cell
    if cell == None:
      raise Exception("No cell")
    # fetch the database parameters
    dbu = ly.dbu
    
    
    layer = pya.LayerInfo(1, 0)
    t = pya.Trans(0, 0)
    
    points=([ [0,0], [15,0], [15,15] ])
    a1 = []
    for p in points:
      a1.append (pya.DPoint(p[0], p[1]))
    wg_path = pya.DPath(a1, 0.5)
    param = { "npoints": 100, "radius": 8, "path": wg_path, "layer": layer }
    pcell = ly.create_cell("ROUND_PATH", "Basic", param )
    new_cell = cell.insert(pya.CellInstArray(pcell.cell_index(), t))
    
    # Leave the newly created waveguide selected, to make it obvious to the user.
    # http://klayout.de/forum/comments.php?DiscussionID=747
    op = pya.ObjectInstPath()
    op.top = ly.top_cell().cell_index()
    op.append_path = pya.InstElement.new(new_cell)
    print ( op.is_cell_inst() )
    
    # Select the newly added objects
    lv.object_selection = [op]
    
  • edited November -1

    Hi Lukas,

    I think the proper way to write the above code is

    ...
    new_selection[new_selectionN].append_path(pya.InstElement(new_cell))
    ...
    

    I guess the previous code was changing the "append_path" attribute to an InstElement which basically removes the method, but does not call "append_path". I'm afraid the application is not really safe against unexpected conditions. But I wonder why internal errors crash the application ...

    I have confirmed that the following code (which adds an instance of a cell "A") works:

    import pya
    
    lv = pya.LayoutView.current()
    ly = pya.CellView.active().layout()
    
    cell = ly.cell("A")
    inst = ly.top_cell().insert(pya.CellInstArray(cell.cell_index(), pya.Trans()))
    
    sel_obj = pya.ObjectInstPath()
    sel_obj.top = ly.top_cell().cell_index()
    ie = pya.InstElement(inst)
    sel_obj.append_path(ie)
    
    lv.object_selection = [ sel_obj ]
    

    Best regards,

    Matthias

  • edited November -1

    works! thank you.

Sign In or Register to comment.