GeometryHelper.PlaneGeometry
4.0.0
merge project
dotnet add package GeometryHelper.PlaneGeometry --version 4.0.0
NuGet\Install-Package GeometryHelper.PlaneGeometry -Version 4.0.0
<PackageReference Include="GeometryHelper.PlaneGeometry" Version="4.0.0" />
<PackageVersion Include="GeometryHelper.PlaneGeometry" Version="4.0.0" />
<PackageReference Include="GeometryHelper.PlaneGeometry" />
paket add GeometryHelper.PlaneGeometry --version 4.0.0
#r "nuget: GeometryHelper.PlaneGeometry, 4.0.0"
#:package GeometryHelper.PlaneGeometry@4.0.0
#addin nuget:?package=GeometryHelper.PlaneGeometry&version=4.0.0
#tool nuget:?package=GeometryHelper.PlaneGeometry&version=4.0.0
GeometryHelper.PlaneGeometry
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.Geometryalongside this library brings a secondToleranceinto 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 | Versions 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. |
-
.NETStandard 2.0
- GeometryHelper.CommonGeometry (>= 4.0.0)
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.