Boolean between different shapes rather than layers

edited January 2018 in Ruby Scripting
Hi,

In my Ruby code I am planning to do Boolean between different shapes. I know that Boolean between layers is straight forward and could be done by two lines of the code. However, is there an easy way of doing Boolean between shapes which are already specified by a shape index?

I was thinking of calling the shapes in a method, manually changing their layers (if similar), doing the Boolean and then converting the result to the original layer. Would that make sense?

Regards,
Hamedp

Comments

  • edited January 2018

    Hi Hamed,

    The recommended approach is to use the Region class:

    shape = ... the input shape 1 ...
    shape2 = ... the input shape 2 ...
    region = RBA::Region::new(shape1.polygon)
    region2 = RBA::Region::new(shape2.polygon)
    region &= region2   # or whichever operation you plan
    

    The result of an AND operation can be zero, one or many polygons. Hence there is no
    "polygon & polygon -> polygon" operation. The region object accommodates zero to many
    polygons, so it's the natural representation for input and output to an AND operation.

    Matthias

  • edited November -1
    Hi Matthias,

    Thank you so much for the hint.

    In order to test what you proposed, I am inserting a BOX into the layout:

    shape1 = lyo.layout.cell( @cell_index[@cell_name] ).shapes( call_layer( lyo, @layer_name,fab_name ) ).insert(RBA::Box::new(0, -50/0.001, 2000/0.001, 50/0.001))


    and then use:

    region = RBA::Region::new(shape1.to_polygon)

    for some reason I get an error "undefined method "to_polygon" for BOX(0,-50,100,50):RBA::Shape"

    Any idea what is causing the issue?

    Thank you,
    Haed
  • edited November -1

    Sorry, typo. Should be "shape1.polygon" (answer edited).

    Matthias

  • edited January 2018
    Hi Matthias,

    Thank you so much for looking into this.

    I really do not understand why but this is not working for me

    shape1 = lyo.layout.cell( @cell_index[@cell_name] ).shapes( call_layer( lyo, @layer_name,fab_name ) ).insert(RBA::Box::new(0, 80/0.001, 20/0.001, 100/0.001))
    region = RBA::Region::new(shape1.polygon)

    shape2 = lyo.layout.cell( @cell_index[@cell_name] ).shapes( call_layer( lyo, @layer_name,fab_name ) ).insert(RBA::Box::new(0, 90/0.001, 30/0.001, 120/0.001))
    region2 = RBA::Region::new(shape2.polygon)

    region &= region2
  • edited January 2018

    How should I?

    I can't see what call_layer will do, neither what @cell_index really contains ... if it's an array or a hash at all.

    And I don't print error messages just for fun. Don't be shy and tell me what they say.

  • edited November -1
    I totally understand Matthias. Sorry for sending you three lines of code. My program is quite long that's why I could not copy it here. If you do not mind I will attach it to an e-mail and send it to you.

    Regards,
    Hamed
  • edited November -1
    Problem is solved now.
  • edited September 2023

    Hi Matthias, hpishvai, reanimating a 5-year-old post, hopefully you could help me out here. There is a Macro I am currently working on, and part of it consists of Boolean operations between Polygons. For subtraction between two boxes and output as a polygon, I managed to put together a code based on this post that looks like this:

    box1 = frame_outline.shapes(layer_1).insert(RBA::Box::new(-mask_boundary/(2*dbu),-mask_boundary/(2*dbu),mask_boundary/(2*dbu),mask_boundary/(2*dbu)))
    box2 = frame_outline.shapes(layer_1).insert(RBA::Box::new(-210000/(2*dbu),-210000/(2*dbu),210000/(2*dbu),210000/(2*dbu)))
    region = RBA::Region::new(box1.polygon) - RBA::Region::new(box2.polygon)
    frame_outline.shapes(layer_1).insert(region)
    box1.delete
    box2.delete
    

    frame_outline is a cell where I want to see the result, and mask_boundary is a variable which I have defined in the Macro already. This code works.

    However, now I want to subtract two polygons that I have obtained by flattening two Circle PCells. Usually on the Klayout GUI, it works with Edit->Selection. I tried implementing the subtracting boxes idea but maybe I am missing something here, cos it isn't working:

    param = { "layer" => RBA::LayerInfo::new(1, 0), "actual_radius" => 102500 }
    pv = pcell_circle_decl.get_parameters.collect do |p|
      param[p.name] || p.default
    end
    
    pcell_circle = lay.add_pcell_variant(lib, pcell_circle_decl.id, pv)
    t = RBA::Trans::new(0, 0)
    circ1 = frame_ring.insert(RBA::CellInstArray::new(pcell_circle, t))
    
    param = { "layer" => RBA::LayerInfo::new(1, 0), "actual_radius" => 100000 }
    pv = pcell_circle_decl.get_parameters.collect do |p|
      param[p.name] || p.default
    end
    
    pcell_circle = lay.add_pcell_variant(lib, pcell_circle_decl.id, pv)
    t = RBA::Trans::new(0, 0)
    circ2 = frame_ring.insert(RBA::CellInstArray::new(pcell_circle, t))
    
    reg1 = circ1.flatten
    reg2 = circ2.flatten
    
    region = RBA::Region::new(reg1) - RBA::Region::new(reg2)
    

    Error:

    No overload with matching arguments in Region::initialize

    PS: reg1 and reg2 are Polygons with 64 points each, which is exactly how they turn out if I flatten the Pcells manually with the GUI.

  • edited September 2023

    Hi Aadoo,

    circ1.flatten provide void return to reg1, which causes the interpreter to complaint.

    region only can be initiallized with shape like object, which also cannot take a cell or flattened cell as input.

    to make the machine happy, you need to extract shapes from cells and feed into region for boolean

    Example:

    mainWindow = RBA::Application::instance::main_window
    layout     = mainWindow::current_view::active_cellview::layout
    ln, dt     = 1, 0
    
    def pCircleRegion(layout, ln, dt, radius)
        lib               = RBA::Library.library_by_name("Basic")
        pcell_circle_decl = lib.layout.pcell_declaration("CIRCLE")
    
        param  = { "layer" => RBA::LayerInfo::new(ln, dt), "actual_radius" => radius }
        pv     = pcell_circle_decl.get_parameters.collect { |p| param[p.name] || p.default }
        cellID = layout.add_pcell_variant(lib, pcell_circle_decl.id, pv)
        cell   = layout.cell(cellID)
        region = RBA::Region::new(cell.each_shape(layout.layer(ln, dt)).collect {|shape| shape.polygon})
        cell.delete
        return region
    end
    
    smallCircieReg = pCircleRegion(layout, ln, dt, 10000)
    largeCircieReg = pCircleRegion(layout, ln, dt, 15000)
    outRegion      = largeCircieReg - smallCircieReg
    layout.cell("TOP").shapes(layout.layer(ln, dt)).insert(outRegion)
    

    pCircleRegion function declars a pcell and list out all shapes in (1, 0) and feed into a region before it being deleted
    repeat this to get multiple region for boolean.

    Additionally, layer and datatype does not mean anything to region, consider region as a seperate layer that holds shapes, they exist in pCircleRegion function is just to satisfy the purpose of declaring circle pcell parameter.

  • Hi RawrRanger, for starters, I combined my code and yours, and it works perfectly! But I think you have made my life a lot easier cos this way I can create any PCell circle, and its corresponding region by defining the functions just once. I am still quite new to Ruby in general. But many many thanks for this!

  • edited September 2023

    Hi Aadoo,

    If the intension is to create a ring, the simplest way is to provide a polygon to the region.
    which skips the steps of to messing arond with pcell variables

    mainWindow = RBA::Application::instance::main_window
    layout     = mainWindow::current_view::active_cellview::layout
    ln, dt     = 1, 0
    
    def circleRegion(radius, points)
        da = Math::PI * 2 / points
        return RBA::Region::new(RBA::Polygon::new(
            (0..points).each.collect { |i| RBA::Point::new(radius * Math::cos(da * i), radius * Math::sin(da * i)) }
        ))
    end
    
    def ringRegion(radius, thicknes, points)
        return circleRegion( radius + thicknes, points) - circleRegion( radius, points)
    end
    
    layout.cell("TOP").shapes(layout.layer(ln, dt)).insert(ringRegion(10000, 5000, 32))
    

    or, use the donut pcell from the lib

Sign In or Register to comment.