Thunder.UnitsNET.Vectors.Geometry
0.7.0
dotnet add package Thunder.UnitsNET.Vectors.Geometry --version 0.7.0
NuGet\Install-Package Thunder.UnitsNET.Vectors.Geometry -Version 0.7.0
<PackageReference Include="Thunder.UnitsNET.Vectors.Geometry" Version="0.7.0" />
<PackageVersion Include="Thunder.UnitsNET.Vectors.Geometry" Version="0.7.0" />
<PackageReference Include="Thunder.UnitsNET.Vectors.Geometry" />
paket add Thunder.UnitsNET.Vectors.Geometry --version 0.7.0
#r "nuget: Thunder.UnitsNET.Vectors.Geometry, 0.7.0"
#:package Thunder.UnitsNET.Vectors.Geometry@0.7.0
#addin nuget:?package=Thunder.UnitsNET.Vectors.Geometry&version=0.7.0
#tool nuget:?package=Thunder.UnitsNET.Vectors.Geometry&version=0.7.0
Thunder.UnitsNET.Vectors.Geometry
Unit-aware 2D geometry library built on Thunder.UnitsNET.Vectors. Shapes, directions, and spatial primitives where all distances are Length, all areas are Area, and all angles are Angle — dimensional errors in geometric code are impossible by construction.
Supported frameworks: net8.0, net10.0
Quick start
// dotnet add package Thunder.UnitsNET.Vectors.Geometry
using Thunder.UnitsNET.Vectors.Geometry;
using UnitsNet;
// Circle
var circle = new Circle2(LengthPoint2.FromMeters(0, 0), Radius.FromMeters(5));
bool hit = circle.Contains(LengthPoint2.FromMeters(3, 4)); // true
// Direction2 — a unit-magnitude direction
var dir = Direction2.FromDegrees(45); // North-East
var rotated = dir.Rotate(Angle.FromDegrees(90)); // North-West (135°)
// Collision manifold — penetration depth, contact normal, contact point
var a = Rectangle2.FromCenterAndSize(LengthPoint2.Origin, Length.FromMeters(2), Length.FromMeters(2));
var b = Rectangle2.FromCenterAndSize(LengthPoint2.FromMeters(1, 0), Length.FromMeters(2), Length.FromMeters(2));
if (a.TryGetManifold(b, out var manifold))
{
Length depth = manifold.PenetrationDepth;
Direction2 normal = manifold.ContactNormal;
LengthPoint2 contact = manifold.ContactPoint;
}
// Raycasting
var ray = new LengthRay2(LengthPoint2.FromMeters(-10, 0), Direction2.East);
if (ray.TryIntersect(circle, out var hit2))
{
Length distance = hit2.Distance;
LengthPoint2 point = hit2.Point;
Direction2 surfaceNormal = hit2.Normal;
}
// Path following
var path = new LengthPath2(new[] {
LengthPoint2.FromMeters(0, 0),
LengthPoint2.FromMeters(5, 0),
LengthPoint2.FromMeters(5, 5),
});
LengthPoint2 pos = path.Evaluate(Length.FromMeters(3)); // 3 m along the path
Direction2 tangent = path.TangentAt(Length.FromMeters(3));
Primitive types
| Type | Description |
|---|---|
Direction2 |
Unit-magnitude direction with rotation, compass constants, and angle helpers |
Transform2 |
2D coordinate frame: position + rotation (Direction2) + scale (Ratio) |
Circle2 |
Centre + radius; containment, tangent lines, point-on-circle |
Rectangle2 |
Centre + dimensions + rotation; corners, area, perimeter |
Triangle2 |
Three vertices; area (signed shoelace), centroid, containment |
Ellipse2 |
Centre + semi-axes + rotation; area, perimeter (Ramanujan) |
Arc2 |
Circle + start direction + signed sweep; arc length, polyline, PointAt/TangentAt parametric traversal |
Sector2 |
Circle + two radial edges + direction; area, containment |
Capsule2 |
Two spine endpoints + radius; area, closest-point containment |
Polygon2 |
N-vertex polygon; area, centroid, convexity, ray-cast containment |
LengthSegment2 |
Start + End endpoints; length, direction, closest-point projection |
LengthLine2 |
Infinite line through a point + direction |
LengthRay2 |
Half-line from origin in a direction |
LengthPath2 |
Arc-length parameterised polyline with Evaluate and TangentAt |
Collision detection
All shapes support TryGetManifold(other, out CollisionManifold) for every pairing:
CollisionManifold field |
Type | Description |
|---|---|---|
PenetrationDepth |
Length |
Minimum separation to resolve overlap |
ContactNormal |
Direction2 |
Push direction — apply to the first shape |
ContactPoint |
LengthPoint2 |
Representative contact point |
Supported pairings: Circle↔Circle, Circle↔Rectangle, Circle↔Triangle, Circle↔Capsule, Circle↔Polygon, Rectangle↔Rectangle, Rectangle↔Triangle, Rectangle↔Capsule, Rectangle↔Polygon, Triangle↔Triangle, Triangle↔Capsule, Triangle↔Polygon, Capsule↔Capsule, Capsule↔Polygon, Polygon↔Polygon. All zero-heap-allocation on the hot path.
Raycasting
LengthRay2.TryIntersect(shape, out RaycastHit) for all 5 shapes:
RaycastHit field |
Type | Description |
|---|---|---|
Distance |
Length |
Distance from ray origin to hit |
Point |
LengthPoint2 |
World-space contact point |
Normal |
Direction2 |
Surface normal at contact |
MonoGame integration
Add Thunder.UnitsNET.Vectors.Geometry.MonoGame to convert geometry types to XNA rendering primitives, and for DebugDraw extension methods that render all shapes as wireframes via SpriteBatch.
What's new in v0.7.0
Arc-length traversal for splines — BezierCurve2.EvaluateAtLength(distance, resolution) and TangentAtLength(distance, resolution) return a LengthPoint2 / Direction2 at a given arc-length distance along the curve. Same API on CatmullRomSpline2. Enables constant-speed object movement (cutscenes, train movement, camera paths) without requiring callers to manage a lookup table. Out-of-range distances clamp silently. For hot-path use, cache ToPath(resolution) and call Evaluate/TangentAt directly on the LengthPath2.
LengthPath2.FromArc — LengthPath2.FromArc(arc, resolution) approximates an Arc2 as a polyline, completing the factory family alongside FromBezier and FromCatmullRom. Default resolution is 32 segments; a unit-radius semicircle is within ~1.6% of its true arc length at this setting.
See also — CHANGELOG.md for full Phase 7 release notes (M35–M37).
What's new in v0.6.0
Circle2.FromPoints — Circle2.FromPoints(p1, p2, p3) returns the unique circumscribed circle passing through three non-collinear LengthPoint2 values. Throws ArgumentException when the points are collinear or near-collinear (signed-area < 1e-10 m²).
Arc2.FromPoints — 3-point overload — Arc2.FromPoints(start, through, end) constructs an arc from start to end that passes through through, with direction inferred automatically from the CCW/CW winding of the three points. No need to compute the circumscribed circle or choose ArcDirection manually.
ArcDirection Y-down documentation — ArcDirection.Clockwise and Counterclockwise now carry <remarks> blocks explaining the Y-down sign convention: in MonoGame screen space, Clockwise is visually clockwise; in a Y-up coordinate system the sense is reversed.
See also — CHANGELOG.md for full Phase 6 release notes (M32–M34.1).
What's new in v0.5.0
Spline types — BezierCurve2 and CatmullRomSpline2 with unit-aware control points (LengthPoint2). Evaluate(Ratio t) → LengthPoint2, TangentAt(Ratio t) → Direction2, ToPath(resolution) → LengthPath2. LengthPath2.FromCatmullRom(waypoints) factory for converting a waypoint list directly to an arc-length path.
Arc2 parametric traversal — Arc2.PointAt(Ratio t) and TangentAt(Ratio t) for smooth arc traversal (train-on-track style). Arc2.FromPoints(circle, start, end) infers direction and returns the shorter arc. CalculateArcPoints(n) generates a polyline approximation.
LengthVector2 dot-product and projections — Dot(LengthVector2) → Area (unit-preserving), Dot(ForceVector2) → Energy, Project(direction) → LengthVector2, PerpendicularDot(LengthVector2) → Area. No SI round-trips.
Polar constructors and dimension lifting — LengthVector2.FromPolar(Radius, Angle), LengthVector2.Extend(z) → LengthVector3, LengthVector3.Truncate() → LengthVector2. Available in the core Thunder.UnitsNET.Vectors package.
LengthSegment2.End — .Target renamed to .End (and AsRayFromStartToEnd / AsRayFromEndToStart for the ray-conversion methods). Hard rename — update call sites.
Radius unit properties — .Meters, .Centimeters, .Millimeters, .Feet, .Inches, .Kilometers pass-through properties for improved discoverability.
See also — CHANGELOG.md for full Phase 5 release notes (M27–M31.2).
What's new in v0.4.0
Collision manifolds — TryGetManifold between all 15 shape pairings. Returns penetration depth, contact normal, and contact point. Zero heap allocation.
Raycasting — LengthRay2.TryIntersect for all 5 shapes. Returns distance, contact point, and surface normal. Zero heap allocation.
Path following — LengthPath2: arc-length parameterised polyline with Evaluate(Length) → LengthPoint2, TangentAt(Length) → Direction2, and Project(LengthPoint2) for path snapping.
DebugDraw — Draw all geometry shapes and Transform2 axes as wireframes via SpriteBatch (Geometry.MonoGame package).
Performance — All hot paths profiled and optimised. Zero allocation. Rectangle_Rectangle manifold: 1,466 ns → 124 ns (colliding, 11.8×) / 27 ns (non-colliding, 44×).
See also — CHANGELOG.md for full Phase 4 release notes (M19–M26.2).
Packages in this family
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. 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 is compatible. 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. |
-
net10.0
- Thunder.UnitsNET.Vectors (>= 0.7.0)
- UnitsNet (>= 5.67.0)
-
net8.0
- Thunder.UnitsNET.Vectors (>= 0.7.0)
- UnitsNet (>= 5.67.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Thunder.UnitsNET.Vectors.Geometry:
| Package | Downloads |
|---|---|
|
Thunder.UnitsNET.Vectors.Geometry.MonoGame
MonoGame/XNA integration for Thunder.UnitsNET.Vectors.Geometry. Converts unit-aware 2D geometry shapes to XNA rendering primitives with explicit scale, keeping physics and rendering units separate. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.7.0 | 112 | 5/5/2026 |
| 0.7.0-preview37 | 105 | 5/5/2026 |
| 0.7.0-preview36 | 97 | 5/5/2026 |
| 0.7.0-preview35 | 99 | 5/4/2026 |
| 0.6.0-preview34 | 115 | 4/28/2026 |
| 0.6.0-preview33 | 109 | 4/27/2026 |
| 0.6.0-preview32 | 114 | 4/27/2026 |
| 0.5.0 | 123 | 4/23/2026 |
| 0.5.0-preview31 | 106 | 4/28/2026 |
| 0.5.0-preview30 | 125 | 4/28/2026 |
| 0.5.0-preview29 | 112 | 4/28/2026 |
| 0.5.0-preview28 | 112 | 4/28/2026 |
| 0.5.0-preview27 | 111 | 4/28/2026 |
| 0.4.0 | 135 | 4/22/2026 |
| 0.4.0-preview6 | 118 | 4/20/2026 |
| 0.4.0-preview5 | 107 | 4/20/2026 |
| 0.4.0-preview4 | 115 | 4/20/2026 |
| 0.4.0-preview25 | 96 | 4/20/2026 |
| 0.4.0-preview24 | 110 | 4/20/2026 |
| 0.4.0-preview23.1 | 53 | 4/20/2026 |