Iteration through all instances and remove if in polygon

edited April 2024 in Python scripting

Hi Matthias, Hi KLayout community,

I'd like to iterate through all instances of "baseCell" in the "top" cell and remove the instance from the "top" cell if the bounding box of the instance crosses the hull of a polygon "poly2".

Example code:

import pya
import math
import numpy as np

layout = pya.Application.instance().main_window().current_view().active_cellview().create_layout() 
top = pya.Application.instance().main_window().current_view().active_cellview().create_cell()
L1 = layout.layer(1, 0)
dbu = layout.dbu

poly = pya.DPolygon.new([pya.DPoint(-5,-5),pya.DPoint(-5,-5),pya.DPoint(-5,-5), pya.DPoint(-5,-5)])
poly.round_corners(1,1,32)

baseCell = layout.create_cell('baseCell')
baseCell.shapes(L1).insert(poly)

transl = pya.DCplxTrans(15/dbu,  15/dbu)
# create an array instance of baseCells
instArray = pya.CellInstArray.new(baseCell.cell_index(), transl, 20, 20)
# insert the instance into "top" layer
top.insert(instArray)

# create a polygon for the instance removal
poly2 = pya.DPolygon.new([pya.DPoint(0,0),pya.DPoint(200,0),pya.DPoint(200,200), pya.DPoint(0,200)])
poly2.round_corners(10,10,32)
# insert the polygon into "top" cell
top.shapes(L1).insert(poly2)

# all the instances of baseCell in the the "top" cell should now be removed if the bounding box of the instance crosses the hull of poly2
#....

I'd very much appreciate if someone could help to solve this problem.
Maybe looping through dpoly.each_point() to check, whether the instance crosses the hull points of the polygon "poly2", could do the trick. However I can't figure out the implementation of a loop through all the instances.

Additionally, running the code above as is does nothing. Do macros always have to be included in a library and instantiated as a new instance to create a layout in KLayout?

Comments

  • edited April 2024

    Hi @Sepbe,

    The solution gets somewhat difficult if you consider the case of array instances: if one instance of an array cross the polygon boundary, you first need to flatten the array.

    Without considering array instances, here is some code. It uses Region objects and specifically a combination of "not_inside" and "not_outside" to check if an instance is on the boundary:

    layout = pya.CellView.active().layout()
    top_cell = layout.top_cell()
    
    # NOTE: we use the selectors from layer 2/0 in this example
    selector_polygons = pya.Region(top_cell.begin_shapes_rec(layout.layer(2, 0)))
    
    # It is advisable to first collect and then delete 
    to_remove = []
    for inst in top_cell.each_inst():
    
      inst_bbox = pya.Region(inst.bbox())
      on_selector_boundary = inst_bbox.not_inside(selector_polygons).not_outside(selector_polygons)
    
      if not on_selector_boundary.is_empty():
        to_remove.append(inst)
    
    for inst in to_remove:
      inst.delete()
    

    And here is the effect:

    Before:

    After:

    If you want to consider arrays, you can add a selective explode step before the collection of the "to_remove" instances:

    # Explode arrays where needed
    to_explode = []
    for inst in top_cell.each_inst():
    
      if len(inst) > 1: 
    
        # we have an array
        inst_bbox = pya.Region(inst.bbox())
        on_selector_boundary = inst_bbox.not_inside(selector_polygons).not_outside(selector_polygons)
    
        if not on_selector_boundary.is_empty():
          to_explode.append(inst)
    
    for inst in to_explode:
      inst.explode()
    

    Matthias

  • Hi @Matthias,

    the instances in my application are actually single instances and are not array instances.
    Therefore, your code works perfectly, thank you so much.

    Kind regards
    Sepbe

Sign In or Register to comment.