.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.
| 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 |
| Check a contour after simplification | Changed filled area and overlays of the original and simplified boundary | Simplification change |
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.
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.
Choose PolylineKit.Core for numeric areas, intersection and coverage. Version
0.1.0-alpha.1 is an alpha candidate; it has not been published on NuGet.org.
The package guide produces and verifies a local feed:
pwsh -File scripts/verify-packages.ps1
dotnet add MyApp/MyApp.csproj package PolylineKit.Core --version 0.1.0-alpha.1 --source /absolute/path/to/feedAlternatively, use a project reference:
git clone https://github.com/bgtnt/polylinekit.git
dotnet add MyApp/MyApp.csproj reference polylinekit/src/PolylineKit.Core/PolylineKit.Core.csprojPolylineKit.Core includes area methods, normalization, scaling, resampling and
alignment. All use the PolylineKit namespace. Alpha status means the package
is ready for evaluation, 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.
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.
| 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) |
| Regions with holes or disconnected components | Prepare rings with PreparedRegion.FromRings; 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 |
The prepared-region API is available in the current source; earlier verified alpha binaries predate it. Each ring closes independently, with explicit fill semantics and no automatic shell/hole orientation.
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.
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.
PolylineAreafilled-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 arenullwhen the union is not positive. RegionAreaaccepts prepared collections of rings, including empty regions. Each nonempty collection's rings follow the same vertex and coordinate limits; NonZero holes require deliberate orientation.- 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.
- Runnable quick start
- Install and run the coverage example from NuGet packages
- Optional contour output
- Measure change after contour simplification
- Measure how much of a region is covered
- Evaluate and visually review polygon annotations
- Documentation index
- Performance and memory
- Build, tests and contributing
- Alpha release notes
Original code is MIT licensed. Dependencies, data and algorithm attribution are documented in third-party notices.
