Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Getting interacting shapes from "touching" ones

I'd like to filter the output of Cell.each_touching_shape(layer_index, box) or Cell.each_overlapping_shape(layer_index, box)so that I only get the shapes that actually interact with the box, not just if their bounding boxes touch/overlap.

What's the cleanest way to do this, non-recursively?

Comments

  • After playing around with the different APIs, I think I'm reasonably happy with the following approach:

    1. Since I'm interested in shapes from a single cell (i.e. not hierarchical), I'm using Cell.shapes to get my selection candidates.
    2. There's a Polygon.touches? method which appears to be geometrically equivalent to the Region.interacting method but actually returns a boolean. Luckily, shape can be converted to a polygon.
    3. Because I'd like to use a rectangle or a point to select the shape(s), and Polygon.touches? doesn't support points, I'll have to make an Edge from a Point selection.
    4. To limit my initial set of shapes to test for Polygon.touches?, I'm using Shapes.each_touching to filter out shapes that aren't in the vicinity. Note that even though it's called touching, it actually only tests the bounding boxes of the shapes, not the actual geometry (i.e. interaction), so I'll have to use point 2 above with the resulting set.

    Here's my complete test code:

    # setting up the environment and creating a top cell
    main_window = RBA::Application::instance.main_window
    cellview = main_window.create_layout(my_tech, 1)
    layout = cellview.layout
    cell = layout.create_cell('top')
    
    # selecting the layer we're interested in
    layer_index = layout.layer(RBA::LayerInfo.new(10,0))
    shapes = cell.shapes(layer_index)
    
    # adding shapes to the layer
    path_pts = [[2,2],[2,20],[20,20],[20,2]].collect{|x,y| RBA::Point.new(x,y)}
    path = RBA::Path.new(path_pts, 4)
    shapes.insert(path)
    
    pt1 = RBA::Text.new("pt1", 10,10)
    shapes.insert(pt1)
    pt2 = RBA::Text.new("pt2", 19,19)
    shapes.insert(pt2)
    
    # GUI code to see what we've created
    cellview.cell = cell
    cellview.view.max_hier_levels = 1
    cellview.view.zoom_fit
    
    # setting up selector objects
    pt1 = RBA::Point.new(pt1.x,pt1.y)
    pt2 = RBA::Point.new(pt2.x,pt2.y)
    pt12_box = RBA::Box.new(pt1,pt2)
    
    selectors = [pt1, pt2, pt12_box]
    
    # main selection tester
    selectors.each do |sel|
      puts "sel = #{sel}"
    
      # have to convert sel to a Box for shapes.each_touching
      sel_bbox = sel.is_a?(RBA::Box) ? sel : RBA::Edge.new(sel,sel).bbox
      shapes.each_touching(RBA::Shapes::SAll, sel_bbox) do |shp_candidate|
        # shp_candidate may or may not interact with sel
        puts "  shp_candidate = #{shp_candidate}"
        # convert candidate to a polygon for interaction testing
        candidate_poly = shp_candidate.polygon
        if candidate_poly.nil?
          puts "  shp_candidate can't be converted to a Polygon"
        else
          puts "  Polygon.touches? = #{candidate_poly.touches?(sel_bbox)}"
        end
      end
    end
    
    puts "Done."
    

    To further optimise the results of the shapes.each_touching call, it probably makes sense to limit the types to SBoxes, SPaths and SPolygons since only those can be converted to polygons.

  • Hi,

    sorry for the delayed reply.

    Your solution isn't bad although I'd say the Ruby loop is probably going to be a bit slow.

    The solution I'd suggest is to use Region objects. Regions are the basic building blocks of DRC scripts and they provide an "interacting" selector. Regions can be made from shape iterators and boxes, so you have everything you need:

    ly = ... # your layout
    layer = ly.layer(8, 0)  # for example
    cell = ly.top_cell  # for example
    
    box = RBA::Box::new(5000, 0, 6000, 2500)   # for example
    
    si = cell.begin_shapes_rec(layer)
    region_a = RBA::Region::new(si)
    region_b = RBA::Region::new(box)
    
    result = region_a.interacting(region_b)
    
    result.each do |p|
      puts p.to_s
    end
    

    Regards,

    Matthias

  • Hi Matthias, thanks for the Region code.

    I had looked into Regions, but I couldn't think of a way to get the original shapes back from the resulting Region of "selected" objects.

    To explain, I want to manipulate/delete (via Ruby code) the Shapes after "selecting" them from a given Cell. But since I read Regions merge all geometric shapes of the same layer, I'm not sure this is possible.

  • Hi,

    you can try using "region_a.merged_semantics = false". This should leave the shapes unmerged.

    But regions are collections of polygons and everything will be polygonized. If you want to the other shape types such as paths your code is better.

    Kind regards,

    Matthias

Sign In or Register to comment.