Boolean functions based on Regions ,Functions to add box ,circle, path and polygon

edited April 2021 in Python scripting

Adding to my toolbox
per discussion with @sebastian
on this thread

https://www.klayout.de/forum/discussion/1789/is-it-possible-to-filter-an-instance-on-a-circular-shape#latest
#Boolean functions based on Regions
#Functions to add box,circle, path and polygon
#Tracy Groller : 4/2/2021
#per discussion with sebastian
#on this thread 
#https://www.klayout.de/forum/discussion/1789/is-it-possible-to-filter-an-instance-on-a-circular-shape#latest
import pya
import array
import sys
import math
import time

mw = pya.Application.instance().main_window()
layout = pya.Application.instance().main_window().current_view().active_cellview().layout() 
topcell = pya.Application.instance().main_window().current_view().active_cellview().cell
lv = pya.Application.instance().main_window().current_view()

if layout == None:
  raise Exception("No layout")

cv = pya.Application.instance().main_window().current_view().active_cellview()

dbu =layout.dbu

cell = pya.Application.instance().main_window().current_view().active_cellview().cell
if cell == None:
  raise Exception("No cell")

n =   2000 # number of points
r =   2*2  # radius
da = 2 * math.pi / n


def coords(path):
    result = []
    for p in path:
      result.append(DPoint.new(p[0]/dbu,p[1]/dbu))
    return result

def create_path(crd,wd,lay):
  wdt = wd
  layer_info = LayerInfo.new(lay,0)
  layer_index = layout.layer(layer_info)
  cv.cell.shapes(layer_index).insert(Path.new(crd,wd/dbu))

def create_polygon(crd,lay):
  layer_info = LayerInfo.new(lay,0)
  layer_index = layout.layer(layer_info)
  cv.cell.shapes(layer_index).insert(Polygon.new(crd))

def create_box(crd,lay):
  layer_info = LayerInfo.new(lay,0)
  layer_index = layout.layer(layer_info)
  cv.cell.shapes(layer_index).insert(Box.new(crd[0],crd[1]))  

circle = []
for i in range(0, n):
   path = r * math.cos(i * da), r * math.sin(i * da)
   circle.append(path)

lay1 = 9  
lay2 = 5

pth = coords(circle)
#Uncomment to draw circle
#create_polygon(pth,lay1)

#Uncomment to draw boxes
box = [(-6.818,-1.185), (-5.195,3.591)]
crd = coords(box)
#create_box(crd,lay2)

box = [(5.742,-2.333), (7.674,2.771)]
crd = coords(box)
#create_box(crd,lay2)

box = [(-2.827,0.849), (-1.326,2.469)]
crd = coords(box)
#create_box(crd,lay2)

box = [(0.730,-2.708), (2.231,-1.088)]
crd = coords(box)
#create_box(crd,lay2)

def select_set(lay1,lay2,num):
  lv.transaction("Undo Select") 

  lif1 = LayerInfo.new(lay1,0)
  li1 = layout.layer(lif1)

  lif2 = LayerInfo.new(lay2,0)
  li2 = layout.layer(lif2)

  r1 = pya.Region(topcell.begin_shapes_rec(li1))
  r2 = pya.Region(topcell.begin_shapes_rec(li2))

  if num == 1:
     selection = r2.select_inside(r1)
  elif num == 2:
     selection = r2.select_interacting(r1)
  elif num == 3:
     selection = r2.select_not_inside(r1)
  elif num == 4:
     selection = r2.select_not_interacting(r1)
  elif num == 5:
     selection = r2.select_not_outside(r1)
  elif num == 6:
     selection = r2.select_not_overlapping(r1) 
  elif num == 7:
     selection = r2.select_outside(r1)
  elif num == 8:
     selection = r2.select_overlapping(r1)

  layout.clear_layer(li2)
  output = layout.layer(lif2)
  topcell.shapes(output).insert(selection)

  lv.commit()

def select_bool(lay1,lay2,out,num):
  lv.transaction("Undo Boolean") 
  out = LayerInfo.new(out,0)

  lif1 = LayerInfo.new(lay1,0)
  li1 = layout.layer(lif1)

  lif2 = LayerInfo.new(lay2,0)
  li2 = layout.layer(lif2)

  r1 = pya.Region(topcell.begin_shapes_rec(li1))
  r2 = pya.Region(topcell.begin_shapes_rec(li2))

  if num == 1:
     selection = r1 -  r2
  elif num == 2:
     selection = r1 + r2
  elif num == 3:
     selection = r1 & r2
  elif num == 4:
     selection = r1 ^ r2
  elif num == 5:
     selection = r1 | r2

  layout.clear_layer(li1)
  layout.clear_layer(li2)

  output = layout.layer(out)
  topcell.shapes(output).insert(selection)

  lv.commit()

#selections 
#1 select_inside
#2 select_interacting
#3 select_not_inside
#4 select_not_interacting
#5 select_not_outside
#6 select_not_overlapping
#7 select_outside
#8 select_overlapping
lay1 = 9  
lay2 = 5
num = 8 #based on number above 

#selections 
#select_set(lay1,lay2,num)

#Boolean Functions
#1  r1 -  r2
#2  r1 + r2
#3  r1 & r2
#4  r1 ^ r2
#5  r1 | r2
lay1 = 9  
lay2 = 5
num = 1 #Boolean based on number above 
out = 11 #layer to output results

select_bool(lay1,lay2,out,num)

Comments

  • Hi,
    I am new in Klayout and Klayout scripting world. I want to learn basic boolean operation in the layout and came accros this post. Thanks, this looks perfect. Only I tried this code to do OR operation of layer1 and layer2 shapes already exists in the cell and save it to layer3 (also delete layer1 and layer2); but I get an error message that 'LayerInfo' is not defined. I thought this is already a built-in class. The code is same as in the original post -

    import pya
    import array
    import sys
    import math
    import time
    
    
    mw = pya.Application.instance().main_window()
    layout = pya.Application.instance().main_window().current_view().active_cellview().layout() 
    topcell = pya.Application.instance().main_window().current_view().active_cellview().cell#
    #layout=pya.CellView.active().layout()      
    #topcell=layout.cell("main")
    lv = pya.Application.instance().main_window().current_view()
    
    lv.transaction("Undo Boolean")
    out = LayerInfo.new(3,0)
    #out=3
    #lif1=1
    #lif2=2
    lif1=LayerInfo.new(1,0)
    li1=layout.layer(lif1,0)
    lif2=LayerInfo.new(2,0)
    li2=layout.layer(lif2,0)
    
    r1=pya.Region(topcell.begin_shapes_rec(li1))
    r2=pya.Region(topcell.begin_shapes_rec(li2))
    
    selection=r1-r2
    layout.clear_layer(li1)
    layout.clear_layer(li2)
    
    output=layout.layer(out)
    topcell.shapes(output).insert(selection)
    
    lv.commit()
    # Enter your Python code here
    
    
    # Enter your Python code here
    
  • Try this
    Uncomment the Boxes to draw the boxes
    Comment the Boolean function
    Run the Code
    the comment the Boxes and uncomment the boolean function then run the code


    import pya import array import sys import math import time mw = pya.Application.instance().main_window() layout = pya.Application.instance().main_window().current_view().active_cellview().layout() topcell = pya.Application.instance().main_window().current_view().active_cellview().cell lv = pya.Application.instance().main_window().current_view() if layout == None: raise Exception("No layout") cv = pya.Application.instance().main_window().current_view().active_cellview() dbu =layout.dbu cell = pya.Application.instance().main_window().current_view().active_cellview().cell if cell == None: raise Exception("No cell") def coords(path): result = [] for p in path: result.append(DPoint.new(p[0]/dbu,p[1]/dbu)) return result def create_box(crd,lay): layer_info = LayerInfo.new(lay,0) layer_index = layout.layer(layer_info) cv.cell.shapes(layer_index).insert(Box.new(crd[0],crd[1])) def select_bool(lay1,lay2,out,num): lv.transaction("Undo Boolean") out = LayerInfo.new(out,0) lif1 = LayerInfo.new(lay1,0) li1 = layout.layer(lif1) lif2 = LayerInfo.new(lay2,0) li2 = layout.layer(lif2) r1 = pya.Region(topcell.begin_shapes_rec(li1)) r2 = pya.Region(topcell.begin_shapes_rec(li2)) if num == 1: selection = r1 - r2 elif num == 2: selection = r1 + r2 elif num == 3: selection = r1 & r2 elif num == 4: selection = r1 ^ r2 elif num == 5: selection = r1 | r2 layout.clear_layer(li1) layout.clear_layer(li2) output = layout.layer(out) topcell.shapes(output).insert(selection) lv.commit() #Uncomment to draw boxes box = [(0.877,1.154), (5.508,6.368)] crd = coords(box) #create_box(crd,lay1) box = [(1.208,4.912), (2.709,6.532)] crd = coords(box) #create_box(crd,lay2) box = [(3.486,2.634), (4.987,4.254)] crd = coords(box) #create_box(crd,lay2) #Boolean Functions #1 r1 - r2 #2 r1 + r2 #3 r1 & r2 #4 r1 ^ r2 #5 r1 | r2 lay1 = 1 lay2 = 2 num = 1 #Boolean based on number above out = 3 #layer to output results select_bool(lay1,lay2,out,num)
  • @sheikh_nir
    I modified your code this should work


    # Enter your Python code here mw = pya.Application.instance().main_window() layout = pya.Application.instance().main_window().current_view().active_cellview().layout() topcell = pya.Application.instance().main_window().current_view().active_cellview().cell# #layout=pya.CellView.active().layout() #topcell=layout.cell("main") lv = pya.Application.instance().main_window().current_view() out = 3 lay1 = 1 lay2 = 2 out = LayerInfo.new(out,0) lif1 = LayerInfo.new(lay1,0) li1 = layout.layer(lif1) lif2 = LayerInfo.new(lay2,0) li2 = layout.layer(lif2) lv.transaction("Undo Boolean") r1=pya.Region(topcell.begin_shapes_rec(li1)) r2=pya.Region(topcell.begin_shapes_rec(li2)) selection=r1-r2 layout.clear_layer(li1) layout.clear_layer(li2) output=layout.layer(out) topcell.shapes(output).insert(selection) lv.commit()
  • I have tried it.. but it still gives some error in LayerInfo class like this -

  • ok if I use "pya.LayerInfo.new(out,0)" instead of "LayerInfor.new(out,0)" then it finds the class. Thanks a lot for your help. It is now wo
    rking.

  • @sheikh_nir

    That's great not sure why I was not seeing the same error but, yes adding pya in front of the functions does work.

  • edited April 2021

    If it is needed to put the circle with a specified center, then it can be done like this with tagger5896's code-

    circle_center_x=200
    circle_center_y=220
    circle = []
    for i in range(0, n):
       path =circle_center_x+ r * math.cos(i * da),circle_center_y+ r * math.sin(i * da)
       circle.append(path)
    
    lay1 = 1  
    
    pth = coords(circle)
    #Uncomment to draw circle
    create_polygon(pth,lay1)
    
  • @sheikh_nir

    Very good I have made a function out of this along with the radius

    def create_circle(lay,cenx,ceny,r):
      circle = []
      for i in range(0, n):
        path = cenx + r * math.cos(i * da),ceny + r * math.sin(i * da)
        circle.append(path)
      pth = coords(circle)
      create_polygon(pth,lay)
    
    lay = 11
    cenx = 2
    ceny = 2
    r = 2.5
    create_circle(lay,cenx,ceny,r)
    
  • @tagger5896 Thanks a lot for sharing so much code :)

    I appreciate that!

    Best regards,

    Matthias

  • edited April 2021

    @Matthais

    Trying to help the user base by making thing's a bit simpler, these could be added as base functions to be loaded perhaps?
    Still working on the router. It's getting there but little gremlins here and there and no I did not give them water after midnight :)
    Tracy

  • @tagger5896 Well, actually "Polygon#ellipse" is already doing that but I enjoyed this conversation :)

    Here is an example (12-point circle with a diameter of 1000 DBU and centered around 500, 500):

    pya.Polygon.ellipse(pya.Box(0, 0, 1000, 1000), 12)
    

    Matthias

  • @Matthias
    Thanks , learn something new everyday will add this too my toolbox


    def create_circle_math(lay,org,r): layer_info = LayerInfo.new(lay,0) layer_index = layout.layer(layer_info) box = Box.new(0,0, org, org) cv.cell.shapes(layer_index).insert(Polygon.ellipse(box, r)) lay = 12 org = 1000 r = 2000 create_circle_math(lay,org,r)
  • I have tried it.. but it gives some error in LayerInfo class like this -
    'NoneType' object has no attribute 'active_cellview'

  • edited April 2021

    @szxahun
    see @sheikh_nir comment above

    Did you add the following above the code

    import pya
    import array
    import sys
    import math
    import time
    
  • @szxahun It looks like you don't have a layout opened. current_view() seems to be None which means that no layout is loaded.

    Matthias

Sign In or Register to comment.