GeometryHelper.PlaneGeometry 4.0.0

Suggested Alternatives

GeometryHelper

Additional Details

merge project

The owner has unlisted this package. This could mean that the package is deprecated, has security vulnerabilities or shouldn't be used anymore.
dotnet add package GeometryHelper.PlaneGeometry --version 4.0.0
                    
NuGet\Install-Package GeometryHelper.PlaneGeometry -Version 4.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GeometryHelper.PlaneGeometry" Version="4.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="GeometryHelper.PlaneGeometry" Version="4.0.0" />
                    
Directory.Packages.props
<PackageReference Include="GeometryHelper.PlaneGeometry" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add GeometryHelper.PlaneGeometry --version 4.0.0
                    
#r "nuget: GeometryHelper.PlaneGeometry, 4.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package GeometryHelper.PlaneGeometry@4.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=GeometryHelper.PlaneGeometry&version=4.0.0
                    
Install as a Cake Addin
#tool nuget:?package=GeometryHelper.PlaneGeometry&version=4.0.0
                    
Install as a Cake Tool

GeometryHelper.PlaneGeometry

NuGet Version License: MIT

2D geometry for engineering drawings: points, vectors, lines, polylines, polygons, circles and oriented rectangles, with distance, projection, containment, intersection, collision, parallelism, parametrization, merging and splitting over them. Every comparison is tolerance-aware.

GeometryHelper.SolidGeometry is the 3D counterpart, built to the same design and sharing Tolerance, Angle and PointLocation through GeometryHelper.CommonGeometry.

Installation

dotnet add package GeometryHelper.PlaneGeometry

Namespaces

Namespace Holds
GeometryHelper.PlaneGeometry.Geometry GeoPoint2, GeoVector2, GeoLine2, GeoPolyline2, GeoPolygon2, GeoCircle2, GeoRectangle2
GeometryHelper.PlaneGeometry.Core Collision2, Containment2, Distance2, Intersection2, Merge2, Parallel2, Parametrization2, Projection2, Splition2
GeometryHelper.PlaneGeometry.Extension EnumerableExtension
GeometryHelper.CommonGeometry Tolerance
GeometryHelper.CommonGeometry.Datatype Angle
GeometryHelper.CommonGeometry.Enums PointLocation

Every type carries a 2, matching the 3 in GeometryHelper.SolidGeometry, so a program working in both dimensions can import both without aliasing anything.

Geometric Types

GeoPoint2, GeoVector2, GeoLine2, GeoCircle2, GeoRectangle2 (rotated rectangle — OBB), GeoPolygon2, GeoPolyline2.

Regions and curves

The shapes split into two families, and the distinction decides what you can ask of them:

Family Types Encloses an area
Region GeoCircle2, GeoRectangle2, GeoPolygon2 yes
Curve GeoLine2, GeoPolyline2 no

A GeoPolyline2 is always an open chain — it has no IsClosed flag and never joins its last vertex back to its first. Geometry meant to enclose something is a GeoPolygon2, and polyline.ToPolygon() converts between them.

That rule is what decides the answers below. A chain of vertices tracing a square still holds only the points on its path:

var traced = new GeoPolyline2(
    new GeoPoint2(0, 0), new GeoPoint2(10, 0),
    new GeoPoint2(10, 10), new GeoPoint2(0, 10), new GeoPoint2(0, 0));

traced.Locate(new GeoPoint2(5, 5));            // OutSide  — a curve has no interior
traced.DistanceTo(new GeoPoint2(5, 5));        // 5.0      — measured to the path
traced.ToPolygon().Locate(new GeoPoint2(5, 5)); // Inside  — now it is a region
traced.ToPolygon().DistanceTo(new GeoPoint2(5, 5)); // 0.0

Only regions offer Contains; every shape offers Locate, and curves report OnSide or OutSide.

Collision and intersection

CollidesWith answers whether two shapes overlap, GetIntersections returns the crossing points. Every pair is available from both directions, and each has an overload taking an explicit Tolerance:

rect.CollidesWith(line);        line.CollidesWith(rect);
rect.CollidesWith(poly);        poly.CollidesWith(rect);
circle.CollidesWith(polyline);  polyline.CollidesWith(circle);
rect.CollidesWith(otherRect);   poly.CollidesWith(otherPoly);   line.CollidesWith(otherLine);

GeoPoint2[] points = poly.GetIntersections(line);

Splitting

Splition2 cuts a GeoLine2 or a GeoPolyline2 — at a position along it, or wherever a cutter meets it. Pieces come back in order along the subject, so the first piece always holds its start point and the last holds its end point.

Cutting at a position:

Splition2.TrySplitBy(line, point, out GeoLine2 first, out GeoLine2 second);
Splition2.TrySplitAtDistance(polyline, 12.5, out GeoPolyline2 head, out GeoPolyline2 tail);

GeoLine2[] pieces = Splition2.SplitAtDistances(line, new[] { 2.0, 5.0, 8.0 });

Cutting with another shape. A single cutter that can only meet a segment once fills two pieces; anything that can meet it repeatedly fills an array:

Splition2.TrySplitBy(line, cutter, out GeoLine2 first, out GeoLine2 second);
Splition2.TrySplitBy(polyline, cutter, out GeoPolyline2[] pieces);

// Several cutters at once, and points already known to lie on the subject.
Splition2.TrySplitBy(line, new[] { cutterA, cutterB }, out GeoLine2[] byLines);
Splition2.TrySplitBy(polyline, new[] { new GeoPoint2(3, 0) }, out GeoPolyline2[] byPoints);

Splitting against a GeoPolygon2 sorts the result by which side of the boundary each part falls on, and keeps each run whole rather than breaking it into segments:

Splition2.TrySplitBy(line,     polygon, out GeoLine2[] inside,     out GeoLine2[] outside);
Splition2.TrySplitBy(polyline, polygon, out GeoPolyline2[] insideRuns, out GeoPolyline2[] outsideRuns);

// Several polygons behave as their union.
Splition2.TrySplitBy(polyline, new[] { polygonA, polygonB }, out GeoPolyline2[] within, out GeoPolyline2[] beyond);

Every split is also reachable from the shape being cut, which is usually how it reads better:

line.TrySplitBy(point, out GeoLine2 first, out GeoLine2 second);
line.TrySplitAtDistance(4.0, out first, out second);
line.TrySplitBy(polygon, out GeoLine2[] inside, out GeoLine2[] outside);
GeoLine2[] pieces = line.SplitAtDistances(new[] { 2.0, 5.0, 8.0 });

polyline.TrySplitBy(cutter, out GeoPolyline2[] parts);
polyline.TrySplitBy(polygon, out GeoPolyline2[] insideRuns, out GeoPolyline2[] outsideRuns);

The instance methods live on the shape being cut, not on the cutter: polygon.Split(line) would leave it unclear which of the two comes back in pieces.

What the return value means. false says nothing was cut, not that the call failed. The out parameters are always usable: an array form hands back the subject as a single piece, and a polygon form puts it in whichever of the two arrays matches the side it lies on, leaving the other empty.

What gets skipped. Cut positions outside the subject, or landing on one of its endpoints, are not splits. Positions closer together than the tolerance merge into one, and a position within a tolerance of an existing vertex snaps onto it, so no piece and no edge is ever shorter than the tolerance. A point that does not lie on the subject is refused rather than projected onto it — cutting at its projection would be cutting somewhere nobody asked for.

Against a polygon. A part running along the boundary counts as inside, matching Contains. A path that merely touches the boundary and turns back has not crossed it, so it comes back whole instead of split in two at the touch.

Point chains

GeometryHelper.PlaneGeometry.Extension covers the step before a polyline exists: a raw list of points, usually read out of a drawing and carrying more of them than the geometry needs.

using GeometryHelper.PlaneGeometry.Extension;

var traced = new List<GeoPoint2>
{
    new GeoPoint2(0, 0), new GeoPoint2(0.0001, 0), new GeoPoint2(5, 0), new GeoPoint2(5, 5),
};

// The second point is a hair away from the first and goes.
List<GeoPoint2> thinned = traced.RemoveConsecutiveNearPoints(new Tolerance(0.001, 0.001)); // 3 points

// One segment per consecutive pair.
List<GeoLine2> segments = thinned.ToGeoLine2s();                                           // 2 segments

RemoveConsecutiveNearPoints compares each point against the last one kept, not against its original neighbour, which is what guarantees no two points of the result are coincident within the tolerance. A huddle collapses onto its first point, and collapsing stops as soon as one point escapes the tolerance around that anchor, so a long run thins rather than vanishes.

The first point always survives; the last one is not privileged. A final point lying within the tolerance of the one kept before it is dropped like any other, so re-append it yourself when the endpoint matters.

ToGeoLine2s leaves the chain open — nothing joins the last point back to the first, so a ring has to repeat its first point at the end. It does not filter coincident neighbours either, so run RemoveConsecutiveNearPoints first if zero length segments would be a problem.

Tolerance

Tolerance and Tolerance.Global come from the GeometryHelper.CommonGeometry package, which GeometryHelper.SolidGeometry shares, so a program using both libraries sets one tolerance rather than two. See its README.

Tolerance.Global has a static setter, deliberately mirroring Autodesk.AutoCAD.Geometry.Tolerance.Global. Changing it affects the whole application, so set it once at startup.

Importing Autodesk.AutoCAD.Geometry alongside this library brings a second Tolerance into scope and the two tie, giving CS0104. Name the one you mean: using Tolerance = GeometryHelper.CommonGeometry.Tolerance;.

Build and Test

dotnet build Libraries/GeometryHelper.PlaneGeometry/GeometryHelper.PlaneGeometry.csproj
dotnet test  Tests/GeometryHelper.PlaneGeometry.UnitTest/GeometryHelper.PlaneGeometry.UnitTest.csproj

Licence

MIT.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated

2D geometry for engineering drawings, built to the same design as GeometryHelper.SolidGeometry
     and sharing Tolerance, Angle and PointLocation with it through GeometryHelper.CommonGeometry.

     GEOMETRY
     - Seven immutable types in two families. A curve (GeoLine2, GeoPolyline2) encloses nothing; a
       region (GeoCircle2, GeoRectangle2, GeoPolygon2) encloses an area. Only regions offer Contains,
       and GeoRectangle2 is an oriented rectangle that carries its own angle.
     - GeoPolyline2 is always an open chain and never joins its last vertex back to its first.
       Geometry meant to enclose something is a GeoPolygon2, and polyline.ToPolygon() converts.

     OPERATIONS
     - Nine Core classes: Collision2, Containment2, Distance2, Intersection2, Merge2, Parallel2,
       Parametrization2, Projection2, Splition2. Every one is mirrored as instance methods on the
       types it applies to, and splitting sits on the subject being cut rather than on the cutter.
     - Splition2 cuts at a position along the subject, by another shape, or against a polygon, which
       sorts the pieces by the side of the boundary they fall on and keeps each run whole.
     - Every comparison that floating point error can affect takes a Tolerance, and every such method
       has an overload without one that reads Tolerance.Global. Nothing compares coordinates with ==.

     EXTENSIONS
     - GeometryHelper.PlaneGeometry.Extension turns a list of points into the segments running
       through it, and thins a list that carries more points than the geometry needs.