PolygonClipper 1.0.0 is out.
PolygonClipper is a new Six Labors geometry library for polygon boolean operations, self-intersection cleanup, and stroke-outline generation in .NET 8+. It exists because ImageSharp.Drawing needed a dedicated geometry engine for non-convex shapes, holes, multiple contours, overlapping edges, self-intersections, and imported vector input.
The public API is small: build Vertex, Contour, and Polygon values, then call PolygonClipper or PolygonStroker. The implementation uses double-precision coordinates, sweep-line boolean operations, an explicit normalization path, and reusable internal buffers behind the static entry points.
PolygonClipper is the geometry engine used by ImageSharp.Drawing 3 for boolean path work and stroke geometry generation. It now ships as a standalone package for applications that need that layer directly.
As with the other current Six Labors libraries, PolygonClipper 1.0 enforces a build-time license key for direct package dependencies. More on that below.
What's in PolygonClipper 1 #
- Polygon boolean operations for
Intersection,Union,Difference, andXor - A separate normalization pipeline for resolving self-intersections and overlaps into canonical positive-winding output
- Stroke-outline generation through
PolygonStroker - Support for non-convex polygons, holes, multiple disjoint regions, overlapping edges, and vertical segments
- Double-precision geometry without coordinate quantization
- An API built around
Vertex,Contour,Polygon,PolygonClipper, andPolygonStroker - Internal pooling and reusable instances behind the recommended static entry points
2D geometry workloads #
Polygon clipping has few options available to .NET developers. Existing libraries often come with trade-offs: coordinate quantization, native dependencies, complex APIs, or limited scope.
PolygonClipper is designed for geometry workloads that include:
- non-convex shapes
- nested contours and holes
- multiple islands in one result
- overlapping edges
- self-intersections
- stroke outlines with joins, caps, and miter rules
.NET applications doing map work, diagramming, CAD-adjacent processing, export pipelines, hit regions, tool-path preparation, vector cleanup, or generated graphics can use PolygonClipper directly.
The API stays small:
Vertexis one 2D pointContouris one ring of verticesPolygonis a collection of contours
From there, most applications either combine regions with PolygonClipper or generate filled outline geometry with PolygonStroker.
A quick primer on clipping #
At a high level, clipping means taking two input regions, usually called the subject and the clip, and combining them according to one of four rules:
Unionkeeps anything covered by either shapeIntersectionkeeps only the shared overlapDifferencesubtracts the clip shape from the subject shapeXorkeeps the non-overlapping parts and removes the shared middle
Difference is the one operation where argument order matters most. Difference(a, b) is not the same as Difference(b, a).
These images are a good way to visualize the four results using a star and a circle:
Union
Intersection
Difference
Xor
The library applies those operations to inputs more complex than a star and circle: overlapping edges, holes, self-intersections, and multiple contours.
Martínez 2013 for the boolean core #
The boolean-operation core is built on the Martínez 2013 algorithm, specifically a Martínez-Rueda-style sweep-line pipeline for polygon clipping. The paper we used as a key reference is A Simple Algorithm for Boolean Operations on Polygons.
That algorithm gives PolygonClipper a deterministic sweep-line boolean engine for complex input. It processes polygons with holes, multiple contours, and self-intersecting geometry, preserves contour hierarchy in the result, and handles overlapping or vertical segment relationships.
using SixLabors.PolygonClipper;
Polygon result = PolygonClipper.Union(subject, clip);
Polygon overlap = PolygonClipper.Intersection(subject, clip);
Polygon remaining = PolygonClipper.Difference(subject, clip);
Polygon exclusive = PolygonClipper.Xor(subject, clip);
Most users should stick to those static entry points. They route work through internal thread-local reusable instances, so callers get a small static API while the implementation reuses scratch storage under load.
Double-precision coordinates #
PolygonClipper works directly in double-precision geometry. There is no integer-grid conversion step and no quantization error. Your coordinates go in, the algorithm runs, and the result comes back in the same coordinate space. That matters in any pipeline where geometry arrives from transforms, imports, mixed scales, or floating-point layout.
Normalization is a first-class capability #
Boolean operations combine two inputs. Normalization solves a different problem: cleaning up one polygon so it becomes a canonical positive-winding result.
When your contour data self-intersects, overlaps itself, or needs to be prepared for a downstream renderer or exporter that expects positive-winding output, PolygonClipper.Normalize(...) gives you a dedicated path for that job.
using SixLabors.PolygonClipper;
Polygon clean = PolygonClipper.Normalize(input);
Under the hood, normalization is a separate pipeline from the Martínez boolean engine. In PolygonClipper it follows a Vatti/Clipper2-inspired cleanup path focused on resolving self-intersections and overlaps into positive-winding output.
Keeping normalization separate from boolean operations lets callers decide when to pay for input cleanup before export, rendering, or further processing.
Stroking is built in, not bolted on #
PolygonClipper also includes a dedicated stroker.
PolygonStroker takes path-like input and emits the filled polygon geometry that the stroke covers. That gives renderers, exporters, and geometry pipelines filled polygons rather than centerlines.
using SixLabors.PolygonClipper;
StrokeOptions options = new()
{
LineJoin = LineJoin.Round,
LineCap = LineCap.Round,
MiterLimit = 4,
ArcDetailScale = 1,
NormalizeOutput = true
};
Polygon outline = PolygonStroker.Stroke(source, 12, options);
Stroke options control:
- outer joins
- end caps
- miter limits
- arc detail
- whether the emitted result should be normalized before returning
NormalizeOutput is explicit because callers do not always need normalized stroke output. When it is disabled, callers should rasterize with a non-zero winding fill rule.
API and implementation #
You build Contour and Polygon values, call the static operations, and inspect the returned contours and hierarchy:
using SixLabors.PolygonClipper;
static Contour Rectangle(double x, double y, double width, double height)
{
Contour contour = new(4);
contour.Add(new Vertex(x, y));
contour.Add(new Vertex(x + width, y));
contour.Add(new Vertex(x + width, y + height));
contour.Add(new Vertex(x, y + height));
return contour;
}
Polygon subject = new();
subject.Add(Rectangle(0, 0, 80, 60));
Polygon clip = new();
clip.Add(Rectangle(40, 20, 80, 60));
Polygon result = PolygonClipper.Intersection(subject, clip);
The recommended entry points use thread-local reusable instances. Scratch buffers are reused. Large buffers are dropped instead of being retained forever. The stroker pools work by option set to reduce repeated setup for the same stroke configuration.
Already proven in the Six Labors stack #
ImageSharp.Drawing 3 uses PolygonClipper internally for boolean path work and stroke geometry generation. That integration shaped the API and the performance work.
The standalone package exists for applications that need polygon operations without the higher-level drawing system.
Breaking and operational notes #
This is a new library, so there is no previous stable major version to migrate from. The baseline target is .NET 8+.
There are two operational points to note:
- PolygonClipper 1.0 uses the Six Labors Split License
- direct package dependencies must provide a
sixlabors.licfile at build time
As with the other current Six Labors libraries, that enforcement applies to direct dependencies only. If you qualify for community licensing, you can apply via licensing.sixlabors.com.
Closing #
PolygonClipper 1.0 gives .NET developers a focused geometry library for polygon boolean operations, self-intersection cleanup, and stroke-outline generation. It uses double-precision input, keeps the public API small, and supplies the geometry layer used by ImageSharp.Drawing 3.
Explore the docs, try the package, and let us know what you build with it.
PolygonClipper 1.0.0 is licensed under the Six Labors Split License. This means that it is free to use in both non-commercial and certain commercial applications. However, if you are using it in a commercial application and your organization has annual gross revenue exceeding 1M USD per year, you must purchase a commercial license. Please see the Pricing page for more information.
- Previous: Announcing ImageSharp.Web 4.0.0