Error Message merging shapes

edited February 2018 in Ruby Scripting

My target is to merge all shapes for each layer on the top level (merge all vertex).
I tried the DRC merge - works fine but destroys the hierarchy because it goes all the way up to the top.
Now I run a small script described by David - this works very well bu I end up with some strange Error Messags.

ERROR: ../../../src/tl/tl/tlReuseVector.h,277,mp_v->is_used (m_n)
ERROR: Internal error: ../../../src/tl/tl/tlReuseVector.h:277 mp_v->is_used (m_n) was not true


class Hash def push_val_safe(key,val) if self[key].nil? self[key] = [val] else self[key] << val end self end end include RBA app = Application.instance mw = app.main_window lv = mw.current_view raise "No view selected" if lv.nil? ly = lv.active_cellview.layout out_cell = lv.active_cellview.cell lv.transaction("Merge shapes on each layer") begin # Build a hash where they key is the layer and the val is an array of shapes. h = {} lv.each_object_selected { |obj| if !obj.is_cell_inst? h.push_val_safe(obj.layer,obj.shape) end } h.each { |li,shape_arr| selected = Region.new shape_arr.each { |sh| selected.insert(sh.polygon) # Add it to the region sh.shapes.erase(sh) # Delete the shape from the layout } selected.merge selected.each { |poly| out_cell.shapes(li).insert(poly) # Add the region to the layout } } ensure lv.commit end

Comments

  • edited February 2018

    Hi Andy,

    The Markdown version this forum uses is somewhat different from GitHub's ... please format code by using four blanks in front of the code lines.

    I like your monkey-patching approach with Hash#push_val_safe ... not something for the code purists, but IMHO that is what makes Ruby spicy :-)

    Nevertheless: regarding the error message, it basically says that you are trying to access (or delete) a shape that has already been deleted. I agree the message is confusing, but it's still better than crashing the application ... I can't tell which line number this message emerges from, but I have a theory: whenever the same shape is selected twice, this can happen since your code essentially accesses the object first, then deletes it and then tries to access it the next time again - then this message will be generated.

    How can it happen to have the same shape selected twice? The answer is that through hierarchy this may be the case: if you have a shape that sits in a child cell and this child cell is instantiated twice, selecting the shapes from both instances can cause this issue: in this case, the same shape is selected twice - once through child cell instance 1 and then through child cell instance 2.

    Am I guessing correctly?

    If so, the solution is for example, to iterate twice: once for collecting the merged shapes and then, once again, for deleting the shapes. You can use "sh.is_valid?" to check whether the shape is already deleted:

    h.each { |li,shape_arr|
    
      selected = Region.new
    
      shape_arr.each { |sh|
        selected.insert(sh.polygon) # Add it to the region
      }
    
      selected.merge
      selected.each { |poly|
        out_cell.shapes(li).insert(poly) # Add the region to the layout
      }
    
    }
    
    h.each { |li,shape_arr|
      shape_arr.each { |sh|
        sh.valid? && sh.shapes.erase(sh) # Delete the shape from the layout
      }
    }
    

    There is one more thing connected with hierarchy: the polygon needs to be transformed to the current cell if it sits in a child cell. The proper way of doing this is to use "obj.trans" which is the transformation to the current cell. But this means, the scheme has to be changed slightly. For example this way (sorry, not tested):

    # Build a hash where they key is the layer and the val is an array of polygons. 
    
    h = {}
    lv.each_object_selected { |obj|
      if !obj.is_cell_inst?
        # NOTE: the polygon is transformed into the current cell
        h.push_val_safe(obj.layer, obj.shape.polygon.transformed(obj.trans)) 
      end
    }
    
    # After this we can delete the shapes
    
    lv.each_object_selected { |obj|
      if !obj.is_cell_inst?
        obj.shape.is_valid? && obj.shape.delete
      end
    }
    
    # And clear the selection
    lv.cancel
    
    h.each { |li,poly_arr|
    
      selected = Region.new
      poly_arr.each { |p|
        selected.insert(p) # Add it to the region
      }
    
      selected.merge
    
      selected.each { |poly|
        out_cell.shapes(li).insert(poly) # Add the region to the layout
      }
    
    }
    

    Please also note "lv.cancel" which clears the selection. This makes the application is bit safer as the selection otherwise would refer to deleted shapes.

    Kind regards,

    Matthias

  • edited November -1
    Thanks a lot for your feedback - I spent 40 minutes trying different markdowns ...

    They basic request I face is to run a vertex merge (because of a reason mention in another discussion this forum).
    In case the customer missed to use OASIS they want to merge the layer but not destroy the hierarchy. Best solution would be to run ta merge in each hierarchy layer but it dsidn't work out that well yet. I started with DRC merge (very well performing) but this always work through the top layer. So we end up now with a compromise - merge only the layer on the top in one step and in case of use the Merge function from the Layer menu with the option for all subcells. So I try to rebuild your function by extending it from a single layer to all layer. Thanks to David's Red tool Box I now have a solution in place. I'll have a look to build in your feedback tomorrow.

    Best Regards,
    Andy
Sign In or Register to comment.