@@ -146,7 +146,9 @@ public virtual LinearGeometry ToLinearGeometry()
146146 Bounds = RectangleF . Empty ,
147147 ContourCount = 0 ,
148148 PointCount = 0 ,
149- SegmentCount = 0
149+ SegmentCount = 0 ,
150+ NonHorizontalSegmentCountPixelBoundary = 0 ,
151+ NonHorizontalSegmentCountPixelCenter = 0
150152 } ,
151153 [ ] ,
152154 [ ] ) ;
@@ -173,6 +175,8 @@ public virtual LinearGeometry ToLinearGeometry()
173175 float minY = float . MaxValue ;
174176 float maxX = float . MinValue ;
175177 float maxY = float . MinValue ;
178+ int nonHorizontalSegmentCountPixelBoundary = 0 ;
179+ int nonHorizontalSegmentCountPixelCenter = 0 ;
176180 int pointIndex = 0 ;
177181 lastEndPoint = null ;
178182
@@ -200,6 +204,7 @@ public virtual LinearGeometry ToLinearGeometry()
200204 }
201205
202206 int segmentCount = pointCount == 0 ? 0 : this . IsClosed ? pointCount : pointCount - 1 ;
207+ CountNonHorizontalSegments ( points , pointCount , this . IsClosed , ref nonHorizontalSegmentCountPixelBoundary , ref nonHorizontalSegmentCountPixelCenter ) ;
203208
204209 if ( pointCount > 0 )
205210 {
@@ -221,7 +226,9 @@ public virtual LinearGeometry ToLinearGeometry()
221226 Bounds = bounds ,
222227 ContourCount = contours . Length ,
223228 PointCount = points . Length ,
224- SegmentCount = segmentCount
229+ SegmentCount = segmentCount ,
230+ NonHorizontalSegmentCountPixelBoundary = nonHorizontalSegmentCountPixelBoundary ,
231+ NonHorizontalSegmentCountPixelCenter = nonHorizontalSegmentCountPixelCenter
225232 } ,
226233 contours ,
227234 points ) ;
@@ -257,12 +264,68 @@ private RectangleF CalculateBounds()
257264 return bounds ;
258265 }
259266
267+ /// <summary>
268+ /// Materializes the segment sequence into the retained array used by the path.
269+ /// </summary>
270+ /// <param name="segments">The segment sequence to materialize.</param>
271+ /// <returns>The retained segment array.</returns>
260272 private static ILineSegment [ ] GetSegmentArray ( IEnumerable < ILineSegment > segments )
261273 {
262274 Guard . NotNull ( segments , nameof ( segments ) ) ;
263275 return segments as ILineSegment [ ] ?? [ .. segments ] ;
264276 }
265277
278+ /// <summary>
279+ /// Counts how many derived segments survive as non-horizontal raster work for each sampling origin.
280+ /// </summary>
281+ /// <param name="points">The retained contour point run.</param>
282+ /// <param name="pointCount">The number of retained points in the contour.</param>
283+ /// <param name="isClosed">Whether the contour closes back to its first point.</param>
284+ /// <param name="nonHorizontalSegmentCountPixelBoundary">The accumulated pixel-boundary count to update.</param>
285+ /// <param name="nonHorizontalSegmentCountPixelCenter">The accumulated pixel-center count to update.</param>
286+ private static void CountNonHorizontalSegments (
287+ ReadOnlySpan < PointF > points ,
288+ int pointCount ,
289+ bool isClosed ,
290+ ref int nonHorizontalSegmentCountPixelBoundary ,
291+ ref int nonHorizontalSegmentCountPixelCenter )
292+ {
293+ if ( pointCount <= 1 )
294+ {
295+ return ;
296+ }
297+
298+ int segmentCount = isClosed ? pointCount : pointCount - 1 ;
299+ for ( int i = 0 ; i < segmentCount ; i ++ )
300+ {
301+ PointF start = points [ i ] ;
302+ PointF end = points [ ( i + 1 ) == pointCount ? 0 : i + 1 ] ;
303+ if ( ToFixedBoundary ( start . Y ) != ToFixedBoundary ( end . Y ) )
304+ {
305+ nonHorizontalSegmentCountPixelBoundary ++ ;
306+ }
307+
308+ if ( ToFixedCenter ( start . Y ) != ToFixedCenter ( end . Y ) )
309+ {
310+ nonHorizontalSegmentCountPixelCenter ++ ;
311+ }
312+ }
313+ }
314+
315+ /// <summary>
316+ /// Converts a coordinate to the fixed-point row space used by boundary-sampled raster work.
317+ /// </summary>
318+ /// <param name="value">The coordinate to convert.</param>
319+ /// <returns>The rounded 24.8 fixed-point value.</returns>
320+ private static int ToFixedBoundary ( float value ) => ( int ) MathF . Round ( value * 256F ) ;
321+
322+ /// <summary>
323+ /// Converts a coordinate to the fixed-point row space used by center-sampled raster work.
324+ /// </summary>
325+ /// <param name="value">The coordinate to convert.</param>
326+ /// <returns>The rounded 24.8 fixed-point value after the half-pixel sampling offset is applied.</returns>
327+ private static int ToFixedCenter ( float value ) => ( int ) MathF . Round ( ( value + 0.5F ) * 256F ) ;
328+
266329 /// <summary>
267330 /// Converts an SVG path string into an <see cref="IPath"/>.
268331 /// </summary>
0 commit comments