ImageSharp/ImageSharp.Drawing/PolygonGeometry/PolygonClipperFactory.cs
2026-08-03 22:31:27 +02:00

82 lines
2.8 KiB
C#

// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.PolygonClipper;
using System;
using System.Collections.Generic;
using PCPolygon = SixLabors.PolygonClipper.Polygon;
namespace SixLabors.ImageSharp.Drawing.PolygonGeometry {
/// <summary>
/// Builders for <see cref="PCPolygon"/> from ImageSharp paths.
/// Converts ImageSharp paths to the format required by PolygonClipper.
/// </summary>
/// <remarks>
/// PolygonClipper computes parent-child relationships, depth, and orientation during its
/// sweep line algorithm, so we only need to provide contours with vertices.
/// </remarks>
internal static class PolygonClipperFactory
{
/// <summary>
/// Creates a polygon from multiple paths.
/// </summary>
/// <param name="paths">The paths to convert.</param>
/// <returns>A <see cref="PCPolygon"/> containing all flattened paths as contours.</returns>
public static PCPolygon FromClosedPaths(IEnumerable<IPath> paths)
{
PCPolygon polygon = [];
foreach (IPath path in paths)
{
polygon = FromSimpleClosedPaths(path.Flatten(), polygon);
}
return polygon;
}
/// <summary>
/// Converts closed simple paths to PolygonClipper contours.
/// </summary>
/// <param name="paths">Closed simple paths.</param>
/// <param name="polygon">Optional existing polygon to populate.</param>
/// <returns>The constructed <see cref="PCPolygon"/>.</returns>
/// <remarks>
/// This method simply converts ImageSharp paths to PolygonClipper contours by copying vertices.
/// PolygonClipper's sweep line algorithm will determine parent-child relationships, depth,
/// and proper orientation during clipping operations. We only need to ensure paths are
/// closed and have sufficient vertices.
/// </remarks>
public static PCPolygon FromSimpleClosedPaths(IEnumerable<ISimplePath> paths, PCPolygon? polygon = null)
{
polygon ??= [];
foreach (ISimplePath p in paths)
{
if (!p.IsClosed)
{
continue;
}
ReadOnlySpan<PointF> points = p.Points.Span;
if (points.Length < 3)
{
continue;
}
Contour contour = [];
// Copy all vertices
for (int i = 0; i < points.Length; i++)
{
contour.Add(new Vertex(points[i].X, points[i].Y));
}
// Add the contour - PolygonClipper will determine parent/depth/orientation during sweep
polygon.Add(contour);
}
return polygon;
}
}
}