It looks like you're new here. If you want to get involved, click one of these buttons!
Hello,
I'm testing the different functions available for manipulating polygons. I need one to resize the perimeter of the polygons and "size/sized" would do the trick. In docs it's commented that it would require an EdgeProcessor step to fix self-intersections.
When doing so I discovered a weird behavior involving polygon type conversion and resizing magnitude. Here's a tested script:
ly = pya.Application.instance().main_window().current_view().active_cellview().layout()
c = ly.top_cell()
c.clear_shapes()
if c == None:
raise Exception("No valid top cell")
l1 = pya.LayerInfo(1,0)
l2 = pya.LayerInfo(2,0)
l3 = pya.LayerInfo(3,0)
l4 = pya.LayerInfo(4,0)
poly = pya.DPolygon([
pya.DPoint(-0.4,-0.45),
pya.DPoint(-0.4, 0.45),
pya.DPoint( 0.4, 0.45),
pya.DPoint( 0.4,-0.45)
])
# First size then convert
polySmall1 = pya.EdgeProcessor().simple_merge_p2p([ poly.sized(-0.06, -0.06).to_itype(0.001) ], False, False, 1)[0].to_dtype(0.001)
polyMid1 = pya.EdgeProcessor().simple_merge_p2p([ poly.sized(-0.21, -0.21).to_itype(0.001) ], False, False, 1)[0].to_dtype(0.001)
polyBig1 = pya.EdgeProcessor().simple_merge_p2p([ poly.sized(-0.22, -0.22).to_itype(0.001) ], False, False, 1)[0].to_dtype(0.001)
# First convert then size
polySmall2 = pya.EdgeProcessor().simple_merge_p2p([ poly.to_itype( 0.001 ).sized(-60, -60) ], False, False, 1)[0].to_dtype(0.001)
polyMid2 = pya.EdgeProcessor().simple_merge_p2p([ poly.to_itype( 0.001 ).sized(-210, -210) ], False, False, 1)[0].to_dtype(0.001)
polyBig2 = pya.EdgeProcessor().simple_merge_p2p([ poly.to_itype( 0.001 ).sized(-220, -220) ], False, False, 1)[0].to_dtype(0.001)
#####################
# Base shape
c.shapes(l1).insert(poly)
# Small resizing is consistent
c.shapes(l2).insert(polySmall1)
c.shapes(l2).insert(polySmall2)
# Mid resizing is still consistent
c.shapes(l3).insert(polyMid1)
c.shapes(l3).insert(polyMid2)
# Big resizing is inconsistent: polyBig1 behavior is expected, polyBig2 returns a corner rectangle
c.shapes(l4).insert(polyBig1)
c.shapes(l4).insert(polyBig2)
I wanted to ask what's the correct approach to always get the expected result and have no surprises down the line (I'm guessing one is to always use Polygon instead of DPolygon).
Thank you,
Gerard
Comments
Hi @Tabra,
My first advice is not to use this outdated part of the API. A much better option is the Region class. It's a collection of polygons. A sizing operation in the general case produces multiple polygons (think of a negative sizing that makes a larger polygon fall apart). Hence the natural way to doing such an operation is on polygon sets.
Here is your sample with a Region:
which gives you:
Region is only available to integer-type objects, so there is no question whether to use DPolygon. On the plus side, Region is a swiss army knife - in fact, the polygon part of the DRC engine is mostly based on Region. Region offers boolean, DRC functions and much more. It can digest original layers from a Layout and even operator in hierarchical mode, while still being a lean container for simple applications.
The reason you got the fail before (actually polyBig1 was wrong) is the following: "sized" will deliver a polygon with inverted "ears" that need to be normalized by using the merge. This is a compromise imposed by the single-polygon API: "sized" this way will always deliver one polygon for one input polygon, but the price to pay is that the resulting polygon is self-overlapping, i.e. non-orientable. As "to_itype" tries to orient the polygon, this will screw up the orientation and give you the "ears" only. As you are taking the 0th element, the first "ear" is delivered. Not using "to_itype" prevents this issue.
The normalization during "to_itype" can be disputed. There is no real reason for that, so I think I will supress this in future releases. This would make your samples work, but I would recommend using the "Region" API.
BTW: when you use sizing with two values, better use the version with the Vector argument. The other version may be mistaken as a call to the "size(d, mode)" variant.
Matthias
Hi Matthias,
Aah I see, yes I remember this class from my tests with DRCs.
I tried it and works like a charm.
Thanks!
Gerard