Skip to content

About

C# polygon area, intersection, IoU and coverage from double coordinates. Numeric results with no external runtime dependencies in Core.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

PolylineKit

.NET methods for numeric area and region overlap, with no external runtime dependencies in the core. Includes self-intersecting paths with explicit fill rules, plus normalization, resampling and alignment. Supports .NET Standard 2.0 and .NET 10. MIT licensed.

dotnet add package PolylineKit.Core --prerelease
using PolylineKit;

Point2[] first = [new(0, 0), new(2, 0), new(2, 2), new(0, 2)];
Point2[] second = [new(1, 0), new(3, 0), new(3, 2), new(1, 2)];
double? iou = PolylineArea.CompareRegions(first, second).IntersectionOverUnion; // 1/3

Trying it on your own polygons? Follow the short walkthrough and share your result, including where the input or API needs to be clearer.

PolylineKit, Clipper2 or NetTopologySuite?

You need Use
Area, intersection, IoU or coverage as numbers, with an explicit fill rule for self-intersecting input PolylineKit.Core
Output polygons, offsets or general Boolean geometry Clipper2, or the optional PolylineKit.Clipper adapter for its supported operations
A geometry model, topology validation, spatial predicates and geometry overlays NetTopologySuite

Recorded workloads give a guide, not a universal ranking: the building evaluator was 3.05× faster than its configured NTS backend and effectively tied with Clipper2; the complete county/district coverage took 24–25% less time than reusable Clipper2. At 1,024 rings per operand, warm Core comparisons were 18–34% slower than Clipper2. Selected warm geometry calls allocated 0 B; preparation, first calls, growth and oversized workspaces can allocate. These are historical measurements, not timings of the current package version. See the measured scopes and limits.

Applications

Developer task Result Runnable example
Check a model's building outlines against reference annotations Matched and missed buildings, false detections, IoU, missing/excess area and an interactive HTML review Building annotation evaluation
Calculate how much of one territory lies in another Shared square metres and the fraction of each county covered by a congressional district Territorial coverage
Simplify a contour within an area-change budget Draw, load JSON or choose a contour, inspect the changed fill, and export the selected SVG/JSON Interactive contour simplification; batch checks

Run the contour demo locally with dotnet run --project examples/ContourSimplificationDemo -c Release, then open http://127.0.0.1:5090/. It measures a finite series generated by Clipper2 and selects the fewest vertices within the chosen Jaccard-distance budget. Load one contour from an XY points array or the demo's own JSON export; see the input format and limits.

For annotations and territorial coverage, positions are part of the question: keep the supplied coordinates. RMS between boundary samples does not supply intersection, missing area or coverage. Normalization and alignment are separate tools for applications where moving or resizing a shape is intentional.

These are implemented integration examples with recorded checks and measurements; they do not establish external production adoption. The building evaluator shows the most complete review workflow. The territorial example has a recorded speed advantage for its coverage workload. See the scenario-specific evidence.

Building review with selected prediction, reference outline, IoU and area errors

Actual HTML review: prediction #3 against reference #15 in the supplied Las Vegas sample. IoU is 0.68774; missing area is 505.89 pixel² and excess area is 972.32 pixel². The view shows original contours, without an image raster.

Add to your application

Choose PolylineKit.Core for numeric areas, intersection and coverage. The command selects the latest prerelease available on NuGet.org:

dotnet add MyApp/MyApp.csproj package PolylineKit.Core --prerelease

The package guide covers installation and the optional adapter. Alpha.3 is published on NuGet.org: Core and the optional Clipper adapter. It delivers the guarded orientation optimization for the polygon-role factories; see the alpha.3 release notes. The GitHub prerelease preserves the verified original packages. Alpha.1 and alpha.2 package contents remain unchanged. Alpha.1 was unlisted on NuGet.org on 2026-10-14 and remains available through exact-version restore; use alpha.3 for new installations. The polygon-role factories were introduced in alpha.2.

Alternatively, use a project reference:

git clone https://github.com/bgtnt/polylinekit.git
dotnet add MyApp/MyApp.csproj reference polylinekit/src/PolylineKit.Core/PolylineKit.Core.csproj

PolylineKit.Core includes area methods, normalization, scaling, resampling and alignment. All use the PolylineKit namespace. Alpha status means the package has an API that may evolve, with numerical and input limits described below.

The optional PolylineKit.Clipper project adds Clipper2 for resolved output contours and the existing quantized PolylineComparison methods. Only reference it if you need those operations; see the adapter guide.

Measure zone coverage

using PolylineKit;

Point2[] zone = [new(0, 0), new(6, 0), new(6, 2),
                new(2, 2), new(2, 6), new(0, 6)];
Point2[] footprint = [new(1, 1), new(5, 1), new(5, 5), new(1, 5)];
const PathFillRule rule = PathFillRule.NonZero;

double zoneArea = PolylineArea.FilledArea(zone, rule); // 20; cache for this zone
double intersection = PolylineArea.IntersectionArea(zone, footprint, rule); // 7
double? coverage = zoneArea > 0 ? intersection / zoneArea : null; // 35%
var change = PolylineArea.CompareRegions(zone, footprint, rule);
// FirstArea = 20; SecondArea = 16; UnionArea = 29;
// SymmetricDifferenceArea = 22; IntersectionOverUnion = 7/29.

Paths close implicitly. Self-intersections and repeated edges are accepted. PathFillRule.NonZero is the default; pass PathFillRule.EvenOdd to use parity fill. Areas use squared coordinate units. These methods calculate values without producing output contours or quantizing input onto a decimal grid.

Coverage answers how much of the fixed zone is covered; IoU compares the shared area with the union of both regions. A zero-area zone has undefined coverage (null). Summing coverage from overlapping footprints can double-count area. This small example explains the result, not its speed. For a trusted simple ring's own area alone, a shoelace sum is cheaper than general fill-aware processing. Run the package-based example for checked results.

Choose a method

You need Method
Area filled by one closed path PolylineArea.FilledArea(path, fillRule)
Area shared by two single-walk regions PolylineArea.IntersectionArea(first, second, fillRule)
Single-walk region change, union, XOR, IoU or Jaccard distance PolylineArea.CompareRegions(first, second, fillRule)
Polygons with holes or disconnected components Preserve shell/hole roles with PreparedRegion.FromPolygon or FromPolygons; use RegionArea.FilledArea, IntersectionArea or Compare
Vertical separation between increasing-x graphs PolylineArea.BetweenGraphs(first, second)
Centering and scaling PolylineNormalization.ToUnitBounds(path) / MatchBounds(path, reference)
Equidistant samples along a path PolylineSampling.ResampleByArcLength(path)
Translation, rotation and optional uniform-scale alignment PolylineAlignment.FitSimilarity(moving, reference)
Resolved contours as well as area Optional Clipper adapter: PolylineComparison.EndpointBridgedArea(...) / FilledRegionDifference(...), with includeContours: true

FromPolygon and FromPolygons orient rings by their supplied shell/hole roles. FromRings preserves the supplied directions for raw winding input. Each ring closes independently; none of these methods repairs topology. See polygon input and the 100-versus-84 hole example.

Normalization, alignment and measurement are separate operations. For example:

Point2[] moving = AffineTransform2D.Scaling(2)
    .Then(AffineTransform2D.Translation(10, -5)).Apply(zone);
var fit = PolylineAlignment.FitSimilarity(moving, zone);
double rms = fit.RmsError;
var alignedChange = PolylineArea.CompareRegions(zone, fit.AlignedPoints);

Alignment minimizes sampled squared distances. Area measures accumulated region difference; it does not bound maximum boundary displacement or identify every distinct stroke. Choose invariances such as rotation or scaling to suit your data.

Performance by scenario

The complete county/district layers, including holes and disconnected components, took 24–25% less time than reusable prepared Clipper2 C# with preparation plus one full traversal. Warm prepared traversals were 1.44–1.49× faster and allocated 0 B on the measured thread. Preparation alone was slower. At 1,024 generated rings per operand, warm comparisons took 18–34% longer than Clipper (46–97% longer including preparation). Performance depends on component count, geometry and input reuse; there is no universal speed advantage. See the prepared-region assessment.

Earlier single-walk application measurements remain separate: Complete building-evaluator times were effectively tied, with 15.8% fewer allocated bytes; its prepared intersection batch was 12% slower than Clipper2. The complete evaluator was 3.05× faster than the configured NetTopologySuite backend. A nine-ring county own-area batch was about 1.3× faster than Clipper2.

Selected synthetic shapes show larger FilledArea wins over Clipper2: about 26× on a simple spiky star and 17–45× on a repeatedly traced square. A dense integer crossing grid shows a 1.65–3.03× advantage. These compare one area result with preloaded Clipper2 C# producing filled contours.

See the scenario table, reproduction commands and limits before choosing for your workload. A trusted simple ring needs only a shoelace sum; the star result does not establish an advantage for that narrower operation. Reducing the repeated square to a minimal path before clipping was not measured.

Input and numerical limits

  • PolylineArea filled-area methods accept one ordered walk per operand, with at least three vertices after consecutive duplicates and an optional closing duplicate are removed. Null, empty and too-short inputs throw; valid collinear walks can have zero area.
  • Coordinates must be finite and have magnitude at most 1e100. Keep input unchanged during a call. No method silently repairs invalid input.
  • Calculations use double. Exact geometric decisions do not make intersection positions or final areas exact. Tiny features near very large coordinates can lose precision. IoU/Jaccard are null when the union is not positive.
  • RegionArea accepts prepared collections of rings, including empty regions. Each nonempty collection's rings follow the same vertex and coordinate limits. Role-based factories orient ordinary holes; raw FromRings input requires deliberate orientation under NonZero.
  • These methods do not calculate geodesic areas or polygon offsets.

Read the area guide for fill rules, examples and contracts, or the transformation guide for normalization and alignment.

Examples and documentation

Original code is MIT licensed. Dependencies, data and algorithm attribution are documented in third-party notices.

About

C# polygon area, intersection, IoU and coverage from double coordinates. Numeric results with no external runtime dependencies in Core.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages