@@ -54,18 +54,60 @@ public static ComplexPolygon GenerateClippedShapes(
5454 int index = 0 ;
5555 for ( int i = 0 ; i < result . Count ; i ++ )
5656 {
57- Contour contour = result [ i ] ;
58- PointF [ ] points = new PointF [ contour . Count ] ;
57+ shapes [ index ++ ] = new Polygon ( CreateContourPoints ( result , i ) ) ;
58+ }
59+
60+ return new ( shapes ) ;
61+ }
5962
60- for ( int j = 0 ; j < contour . Count ; j ++ )
63+ /// <summary>
64+ /// Converts a PolygonClipper contour to ImageSharp points and normalizes winding for parent/child rings.
65+ /// </summary>
66+ /// <param name="polygon">The polygon containing the contour hierarchy.</param>
67+ /// <param name="contourIndex">The contour index to convert.</param>
68+ /// <returns>The converted point array.</returns>
69+ private static PointF [ ] CreateContourPoints ( PCPolygon polygon , int contourIndex )
70+ {
71+ Contour contour = polygon [ contourIndex ] ;
72+ PointF [ ] points = new PointF [ contour . Count ] ;
73+ bool reverse = ShouldReverseForNonZeroWinding ( polygon , contourIndex ) ;
74+
75+ if ( ! reverse )
76+ {
77+ for ( int i = 0 ; i < contour . Count ; i ++ )
6178 {
62- Vertex vertex = contour [ j ] ;
63- points [ j ] = new PointF ( ( float ) vertex . X , ( float ) vertex . Y ) ;
79+ Vertex vertex = contour [ i ] ;
80+ points [ i ] = new PointF ( ( float ) vertex . X , ( float ) vertex . Y ) ;
6481 }
6582
66- shapes [ index ++ ] = new Polygon ( points ) ;
83+ return points ;
6784 }
6885
69- return new ( shapes ) ;
86+ for ( int sourceIndex = contour . Count - 1 , targetIndex = 0 ; sourceIndex >= 0 ; sourceIndex -- , targetIndex ++ )
87+ {
88+ Vertex vertex = contour [ sourceIndex ] ;
89+ points [ targetIndex ] = new PointF ( ( float ) vertex . X , ( float ) vertex . Y ) ;
90+ }
91+
92+ return points ;
93+ }
94+
95+ /// <summary>
96+ /// Ensures child contours (holes/islands) use opposite winding to their direct parent.
97+ /// This keeps clipped output deterministic when consumed with the NonZero fill rule.
98+ /// </summary>
99+ /// <param name="polygon">The polygon containing contour hierarchy information.</param>
100+ /// <param name="contourIndex">The contour index to inspect.</param>
101+ /// <returns><see langword="true"/> when the contour should be reversed.</returns>
102+ private static bool ShouldReverseForNonZeroWinding ( PCPolygon polygon , int contourIndex )
103+ {
104+ Contour contour = polygon [ contourIndex ] ;
105+ if ( contour . ParentIndex is not int parentIndex || ( uint ) parentIndex >= ( uint ) polygon . Count )
106+ {
107+ return false ;
108+ }
109+
110+ Contour parentContour = polygon [ parentIndex ] ;
111+ return contour . IsCounterClockwise ( ) == parentContour . IsCounterClockwise ( ) ;
70112 }
71113}
0 commit comments