simple merge of non-orientable polygons

edited August 2021 in General

Hi,
I want to clean up non-orientable parts of polygon, like

         |----->---|
         ^   B     v
|-----<--|----<----|
v   A    ^
|----->--|

part A of polygon is anticlockwise, part B of polygon is clockwise.

I want to clean up B while keep A in output result , and try command

EdgeProcessor.simple_merge_p2p ([P_in], resolve_holes= false, min_coherence=True, mode = 1)

However, in result , the remain part is dependent to area of A , B.
If area A > B, A will be remained, and if area B > A, B will be remained.

Is there a way to keep anticlockwise part A only even if area A < B ?

Thanks,
Dion

Comments

  • @dion The key is the mode you're using. In your case there is also the min_coherence parameter which is important.

    For the mode parameter the documentation says:

    The mode specifies the rule to use when producing output. A value of 0 specifies the even-odd rule. A positive value specifies the wrap count threshold (positive only). A negative value specifies the threshold of the absolute value of the wrap count (i.e. -1 is non-zero rule).

    KLayout tries to normalize polygons so they have a positive wrap count, but for non-orientable polygons like yours this is not possible. So one part have wrap count -1 and the other one has +1. To get both parts, you need to make "merge" produce polygon output where the wrap count is -1 or +1 - or more general not equal to zero. So you need the "non-zero rule" which corresponds to a mode of -1. This is also the mode used for drawing polygons, so you'll get what you see in this case.

    The resulting polygon can be represented by two boxes or a single polygon which two touching corners. The "min_coherence" parameter controls whether the polygons have minimum coherence - i.e. as many individual polygons as possible are produced. In this case, "min_coherence" set to True will give you two polygons.

    Here is a sample code which demonstrates that (Python):

    pts = [ 
      pya.Point(-100, -100),
      pya.Point(-100, 0),
      pya.Point(100, 0),
      pya.Point(100, 100),
      pya.Point(0, 100),
      pya.Point(0, -100)
    ]
    
    poly = pya.Polygon(pts)
    
    ep = pya.EdgeProcessor()
    
    print("mode = 1:")
    print("\n".join([ str (p) for p in ep.simple_merge_p2p([poly], False, True, 1)]))
    
    print("mode = 0:")
    print("\n".join([ str (p) for p in ep.simple_merge_p2p([poly], False, True, 0)]))
    
    print("mode = -1, min_coherence = True:")
    print("\n".join([ str (p) for p in ep.simple_merge_p2p([poly], False, True, -1)]))
    
    print("mode = -1, min_coherence = False:")
    print("\n".join([ str (p) for p in ep.simple_merge_p2p([poly], False, False, -1)]))
    

    with the following output:

    mode = 1:
    (-100,-100;-100,0;0,0;0,-100)
    mode = 0:
    (-100,-100;-100,0;0,0;0,-100)
    (0,0;0,100;100,100;100,0)
    mode = -1, min_coherence = True:
    (-100,-100;-100,0;0,0;0,-100)
    (0,0;0,100;100,100;100,0)
    mode = -1, min_coherence = False:
    (-100,-100;-100,0;0,0;0,100;100,100;100,0;0,0;0,-100)
    

    Matthias

  • edited August 2021

    Hi Matthias,

    Thank you for the reply verify much.
    I found the output of results is depend to the area.

    I modified the sample code. (only first point)
    Area of A is bigger in test 1.
    And area of A is smaller in test2.

    pts = [
      pya.Point(-101, -100),
      pya.Point(-100, 0),
      pya.Point(100, 0),
      pya.Point(100, 100),
      pya.Point(0, 100),
      pya.Point(0, -100)
    ]
    
    poly = pya.Polygon(pts)
    
    ep = pya.EdgeProcessor()
    
    print("test1, mode = 1:")
    print("\n".join([ str (p) for p in ep.simple_merge_p2p([poly], False, True, 1)]))
    
    pts = [
      pya.Point(-99, -100),
      pya.Point(-100, 0),
      pya.Point(100, 0),
      pya.Point(100, 100),
      pya.Point(0, 100),
      pya.Point(0, -100)
    ]
    
    poly = pya.Polygon(pts)
    
    ep = pya.EdgeProcessor()
    
    print("test2, mode = 1:")
    print("\n".join([ str (p) for p in ep.simple_merge_p2p([poly], False, True, 1)]))
    

    With same command ep.simple_merge_p2p([poly], False, True, 1),
    output of test1 is part A.
    However, output of test2 is part B ( I still want to output A in this case. ) My expected result is (-99,-100;-100,0;0,0;0,-100)

    test1, mode = 1:
    (-101,-100;-100,0;0,0;0,-100)
    test2, mode = 1:
    (0,0;0,100;100,100;100,0)  #how to still get  (-99,-100;-100,0;0,0;0,-100) here?
    

    Is there a way to always keep part A in results?

  • @dion KLayout tries to normalize the orientation of the incoming polygon, hence the area dependency. The part with the larger area will determine the orientation which is detected.

    There is no way to turn off that normalization from the Python or Ruby API. The only option you have for non-orientable polygons is to use mode -1 which delivers both parts - either individually or joined depending on the min_coherence argument.

    Matthias

  • Thank you very much.

    I check the source code to find a way to avoid area dependency.

    Is the related function in dbEdgeProcessor.cc?

    I found ProjectionCompare (e)) maybe relate to it, but no sure.

    Could you give me any suggestion?

    2319         if (cut_points->has_cutpoints && ! cut_points->cut_points.empty ()) {
    2320 
    2321           db::Edge e = ew;
    2322           property_type p = ew.prop;
    2323           std::sort (cut_points->cut_points.begin (), cut_points->cut_points.end (), ProjectionCompare (e));
    2324 
    2325           db::Point pll = e.p1 ();
    2326           db::Point pl = e.p1 ();
    
  • @dion I tried to explain that the reason for the area dependency isn't the processor, it's the polygon normalization. That is essentially happening in polygon_contour::assign (dbPolygon.h, line 247++) if the "normalize" argument is set to "true". This is the default mode in many applications and is vital for a lot a algorithms. So you should not simply set this argument to false unconditionally.

    Matthias

  • oh, Matthias, I understood, really thank you.

Sign In or Register to comment.