Python: How to remove artifacts from using object.size() ?

edited September 2015 in Ruby Scripting
Hello,

I'm taking an octagon and shrinking it with the myShape.size( -int, var[6:0]) method

This understandably results in a folded shape with artifacts at the vertices outside of the desired final shape. I am not able to follow the existing documentation to figure out how to remove/clean the artifacts.

My Size function:
myinnerPolygon.size(-200000, 8) #I iteratively tried 0-8 for the angle operator

I tried this function which I thought would clean up the artifacts:
ep = pya.EdgeProcessor()
result = ep.simple_merge_p2p([ myinnerPolygon ], False, False, 1)

but did not see any improvement and I can't really follow the documentation well enough to understand the function.

Does anyone have a suggestion?

Comments

  • edited September 2015

    Hi,

    I don't see an issue with the solution you proposed.

    Here is a working example:

    import pya
    
    pts = []
    pts.append(pya.Point(-1000, 300))
    pts.append(pya.Point(-300, 1000))
    pts.append(pya.Point(300, 1000))
    pts.append(pya.Point(1000, 300))
    pts.append(pya.Point(1000, -300))
    pts.append(pya.Point(300, -1000))
    pts.append(pya.Point(-300, -1000))
    pts.append(pya.Point(-1000, -300))
    poly = pya.Polygon(pts)
    
    print("Original: "+str(poly))
    
    poly_sized_m100 = poly.sized(-100)
    print("Post size: "+str(poly_sized_m100))
    
    print("Post merge:")
    result = pya.EdgeProcessor().simple_merge_p2p([ poly_sized_m100 ], False, False, 1)
    for p in result:
      print(str(p))
    

    This prints:

    Original: (-300,-1000;-1000,-300;-1000,300;-300,1000;300,1000;1000,300;1000,-300;300,-1000)
    Post size: (-300,-1000;-229,-929;-929,-229;-1000,-300;-900,-300;-900,300;-1000,300;-929,229;-229,929;-300,1000;-300,900;300,900;300,1000;229,929;929,229;1000,300;900,300;900,-300;1000,-300;929,-229;229,-929;300,-1000;300,-900;-300,-900)
    Post merge:
    (-258,-900;-900,-258;-900,258;-258,900;258,900;900,258;900,-258;258,-900)
    

    That means: the original polygon is an octagon. After sizing the polygon is a complex one with the artefacts induced by the vertex treatment on negative sizing. So it's a bit more complex. After the merge step, the result is an array containing one polygon. That polygon again is an octagon. So from my point of view the solutions should work. The angle parameter should not matter in your case since octagon angles are not acute ones.

    I should mention that there is a better object available for doing geometrical computations: the Region class is basically a collection of polygons. Collections of polygons are more natural objects for doing computations. In the general case for example the sizing operation may render zero (if the polygon vanishes) to many polygons (if parts of the original polygons vanish). Hence, a sizing operation is not a natural operation to be performed on a single polygon. But on a collection of polygons it is. Since a single polygon is just a special case of a collection, the Region class can be used to implement your application too:

    import pya
    
    pts = []
    pts.append(pya.Point(-1000, 300))
    pts.append(pya.Point(-300, 1000))
    pts.append(pya.Point(300, 1000))
    pts.append(pya.Point(1000, 300))
    pts.append(pya.Point(1000, -300))
    pts.append(pya.Point(300, -1000))
    pts.append(pya.Point(-300, -1000))
    pts.append(pya.Point(-1000, -300))
    poly = pya.Polygon(pts)
    
    print("Original: "+str(poly))
    
    region = pya.Region(poly)
    print("Pre-size region: "+str(region))
    
    region_sized_m100 = region.sized(-100)
    print("Post-size region: "+str(region_sized_m100))
    

    Which immediately renders the octagon:

    Pre-size region: (-300,-1000;-1000,-300;-1000,300;-300,1000;300,1000;1000,300;1000,-300;300,-1000)
    Post-size region: (-258,-900;-900,-258;-900,258;-258,900;258,900;900,258;900,-258;258,-900)
    

    Begin capable of handling the potential change in number of polygons, the Region class directly implements the polygon merging in the sizing step.
    Plus, the Region class has a lot more features than just sizing ...

    Matthias

  • edited November -1
    Hello Matthias,

    >>poly = pya.Polygon(pts) needs to be part of the above posted solution before the first 'print' statement

    I'm not sure the implementation of the pya.EdgeProcessor().simple_merge_p2p() method is the most intuitive. I've implemented it correctly below starting from drawn polygon and finishing with shrunken drawn polygon.

    The syntax is not at all obvious without some debug and trial and error.


    # Enter your Python code here

    import pya
    layout = pya.Layout()
    cell = layout.create_cell("Octagon")
    l1 = layout.layer(1, 0)
    l2 = layout.layer(2, 0)
    l3 = layout.layer(3, 0)

    pts = []
    pts.append(pya.Point(-1000, 300))
    pts.append(pya.Point(-300, 1000))
    pts.append(pya.Point(300, 1000))
    pts.append(pya.Point(1000, 300))
    pts.append(pya.Point(1000, -300))
    pts.append(pya.Point(300, -1000))
    pts.append(pya.Point(-300, -1000))
    pts.append(pya.Point(-1000, -300))

    print("Type(pts): " + str( type(pts)))
    print((pts))

    poly = pya.Polygon(pts)
    print("Type(poly): " + str(type(poly)))
    print("Original: "+str(poly))

    poly_sized_m100 = poly.sized(-100)
    print("Type(poly_sized_m100): " + str( type(poly_sized_m100)))
    print("Post size: "+str(poly_sized_m100))

    result = pya.EdgeProcessor().simple_merge_p2p([ poly_sized_m100 ], False, False, 1)
    print ("Type(result): " + str(type(result))) #This returns a misleading result
    print ("Type(result[0]): " + str(type(result[0]))) #This is the object we're looking for, but a strange index location

    print("Post merge: ")
    #Correct Object access
    print(str(len(result)) + ": " + str(result[0]))

    #Incorrect object type access, because 'result' appears to be an object with a 'string' of points at index [0], not a general array of points
    for p in result:
    print(str(p))

    #It's not clear that EdgeProcessor should return a coordinates\
    # string at result[0] vs. a working Object.Polygon() or an explicit list of Object.Point()
    #I.e. it should operate more like a method or maybe the documentation should be more explicit

    #The following strings fail, but are intuitive next steps:
    #Fails: poly_sized_m100_clean = pya.Polygon(result)
    #Fails: cell.shapes(l3).insert(result)


    cell.shapes(l1).insert(poly)
    cell.shapes(l2).insert(poly_sized_m100)

    #This string is the implementation that works, although it is non-intuitive
    cell.shapes(l3).insert(result[0]) #works

    import os
    user_profile = os.environ['USERPROFILE']
    user_desktop = user_profile + "/Desktop/"
    layout.write(user_desktop + "octagon.gds")
  • edited September 2015

    Hi,

    you're right, the line was missing (lost in copy/paste) - I have edited the samples accordingly. Thanks for mentioning this.

    But I don't see your point. What's the problem? The documentation clearly says EdgeProcessor#simple_merge_p2p takes and returns an ARRAY of Polygon objects. Not single ones. Boolean operations in general won't work on single polygons. For the reasons see my explanations above. And a polygon is an object, not an array of points. If you convert it to a string, then it becomes a string which lists the points. What's wrong about that?

    I tried to explain, that the Region class is easier to use. For Region, the sizing and the Booleans are methods as you expect. Maybe you get happy with this one.

    Apart from that I never claimed the solution to be intuitive. What are you actually expecting? Free software, free support, top quality and performance, intuitive usage? Anything else? Maybe you should go for the commercial products like from the market leader: http://www.cadence.com (Dear CDS marketing department: this link is for free). Once you have signed their Platinum service contract, their AE's will be glad to help out. Plus they will be happy to offer trainings on their software. It's just a little more expensive than nothing.

    Matthias

  • edited November -1
    Hey Matthias,

    No offense intended. I'm just explaining my experience and trying to understand a new tool. I wouldn't have taken the time to debug and play with the scripts and write a post if I didn't like it.

    And I do have Cadence and Synopsys and Mentor and all the support I can ever need.

    The point is I like your tool and I'm trying to understand the nuances.

    If you say you return an array of points, but the data is not in an array, it's in a string at array[0], that's not intuitive. It's not a personal knock. It's just a different way of doing something and I'm trying to understand so that I can be self sufficient in the future. I assume if you didn't want feedback, you wouldn't have asked for feedback or opened a forum.

    Cheers.

    +
Sign In or Register to comment.