ModelingEvolution.Drawing
1.4.0.55
dotnet add package ModelingEvolution.Drawing --version 1.4.0.55
NuGet\Install-Package ModelingEvolution.Drawing -Version 1.4.0.55
<PackageReference Include="ModelingEvolution.Drawing" Version="1.4.0.55" />
<PackageVersion Include="ModelingEvolution.Drawing" Version="1.4.0.55" />
<PackageReference Include="ModelingEvolution.Drawing" />
paket add ModelingEvolution.Drawing --version 1.4.0.55
#r "nuget: ModelingEvolution.Drawing, 1.4.0.55"
#:package ModelingEvolution.Drawing@1.4.0.55
#addin nuget:?package=ModelingEvolution.Drawing&version=1.4.0.55
#tool nuget:?package=ModelingEvolution.Drawing&version=1.4.0.55
ModelingEvolution.Drawing
A high-performance .NET generic math library for 2D geometry, shapes, intersections, and drawing primitives. Built on INumber<T> constraints from .NET generic math, all types work with float, double, decimal, or any compatible numeric type -- with zero boxing and full type safety.
Table of Contents
- Why This Library
- Installation
- Quick Start
- API Reference
- Key Features
- Code Examples
- Requirements
- License
Why This Library
- Generic math -- write geometry code once; use it with
float,double, or anyIFloatingPointIeee754<T>type. - No boxing -- all core types are
structorreadonly record struct, avoiding heap allocations. - Rich interface hierarchy --
IShape<T, TSelf>unifies area, perimeter, centroid, bounding box, containment, rotation, and scaling across all shape types. - Comprehensive intersections -- 21 intersection combinations (line, segment, circle, triangle, rectangle, polygon) with zero-alloc
FirstOfvariants. - Polygon booleans -- union, intersection, difference, and clustering via Clipper2.
- Exact Bezier clipping --
Path<T>.Intersect(Rectangle<T>)computes analytically exact sub-curves, not polygon approximations. - Serialization built in -- Protobuf (protobuf-net) attributes on all core types, plus custom JSON converters and SVG exporters.
Installation
dotnet add package ModelingEvolution.Drawing
Or via the NuGet Package Manager:
Install-Package ModelingEvolution.Drawing
Quick Start
using ModelingEvolution.Drawing;
// Points and vectors (using double precision)
var a = new Point<double>(1.0, 2.0);
var b = new Point<double>(4.0, 6.0);
double distance = a.DistanceTo(b); // 5.0
Point<double> mid = a.Lerp(b, 0.5); // {X=2.5, Y=4}
// Shapes with area and perimeter
var circle = new Circle<double>(Point<double>.Zero, 10.0);
double area = circle.Area(); // ~314.159
double perimeter = circle.Perimeter(); // ~62.832
bool inside = circle.Contains(new Point<double>(3.0, 4.0)); // true
// Intersections
var line = Line<double>.From(new Point<double>(0, 0), new Point<double>(10, 10));
Segment<double>? chord = circle.Intersect(line); // the chord through the circle
// Polygon boolean operations
var poly1 = new Polygon<double>(
new Point<double>(0, 0), new Point<double>(10, 0),
new Point<double>(10, 10), new Point<double>(0, 10));
var poly2 = new Polygon<double>(
new Point<double>(5, 5), new Point<double>(15, 5),
new Point<double>(15, 15), new Point<double>(5, 15));
Polygon<double> merged = poly1 | poly2; // union
Polygon<double> overlap = poly1 & poly2; // intersection
API Reference
Core Types
| Type | Description |
|---|---|
Point<T> |
2D Cartesian point. Supports arithmetic with vectors and sizes, distance, lerp, reflect, rotate, clamp, midpoint, matrix transform, tuple conversion, and parsing. |
Vector<T> |
2D vector with magnitude, direction, dot/cross product, normalize, projection, reflect, rotate, perpendicular (CW/CCW), angle between, lerp, and matrix transform. |
Size<T> |
Width/height pair with arithmetic operators, component-wise multiply/divide, and parsing. |
Matrix<T> |
3x3 affine transformation matrix. Supports translate, rotate, scale, skew, invert, append/prepend, and point/vector transforms. |
Rectangle<T> |
Axis-aligned rectangle with contains, intersect, inflate, offset, bounds, tiling, diagonal, distance-to-point, and LTRB construction. |
Shapes
All shapes implement IShape<T, TSelf>, providing Area(), Perimeter(), Centroid(), BoundingBox(), Contains(Point<T>), Rotate(Degree<T>, Point<T>), and Scale(T).
| Type | Description |
|---|---|
Circle<T> |
Center + radius. Intersects with lines, segments, circles, and rectangles. Tangent point detection. PointAt(Radian<T>) for parameterized access. |
Triangle<T> |
Three vertices. Incircle, circumcircle, orthocenter, angles, edges. Classification: IsRight(), IsAcute(), IsObtuse(), IsEquilateral(), IsIsosceles(), IsScalene(). Similarity and congruence tests. |
Polygon<T> |
Immutable polygon backed by ReadOnlyMemory<Point<T>>. Shoelace area, ray-casting containment, convex hull (Graham scan), IsConvex(), edges, simplify. Boolean operations: union, intersect, subtract, cluster. Operators: \| (union), & (intersect), - (subtract). |
Rectangle<T> |
Implements IArea<T>, IPerimeter<T>, ICentroid<T>, IBoundingBox<T>, IScalable<T, Rectangle<T>>. Rotation returns Polygon<T>. |
Lines and Segments
| Type | Description |
|---|---|
Line<T> |
Infinite line (supports vertical lines). From two points, point + direction, or equation. Intersect with lines, segments, circles, triangles, rectangles, polygons. Distance-to-point, angle-between, parallel/perpendicular tests, project point, reflect point. |
Segment<T> |
Bounded line segment (start + end). Length, midpoint, direction, lerp, split, reverse. Intersect with segments, lines, circles, rectangles. Distance-to-point, project point, parallel test. Liang-Barsky rectangle clipping. |
Curves and Paths
| Type | Description |
|---|---|
BezierCurve<T> |
Cubic Bezier curve (4 control points). Evaluate(t), Split(t), SubCurve(t0, t1) via De Casteljau. Extremum points, linear equation intersection, rectangle edge crossings. |
Path<T> |
Immutable sequence of BezierCurve<T> segments. Create from points (FromPoints) with smoothing, or from SVG path data (Parse). Length(), PointAt(t) with arc-length parameterization. Exact Intersect(Rectangle<T>) that splits Bezier curves at crossing points. Transform, rotate, reverse, append. Close() and ToPolygon() for rasterization. |
PolygonalCurve<T> |
Mutable sequence of connected points that generates smooth Bezier segments via GetSmoothSegment(i). |
Angles and Coordinates
| Type | Description |
|---|---|
Degree<T> |
Angle in degrees. Implicit conversion from numeric values and from Radian<T>. Arithmetic, normalize to (-180, 180], abs. |
Radian<T> |
Angle in radians. Implicit conversion from Degree<T>. Arithmetic, normalize to (-pi, pi], abs. Static Sin/Cos helpers. |
PolarPoint<T> |
Polar coordinates (radius, angle). Implicit conversions to/from Point<T>, explicit to Vector2 and Vector<T>. |
CylindricalPoint<T> |
Cylindrical coordinates (radius, angle, height). Implicit from PolarPoint<T>, to Vector3. |
Equations
| Type | Description |
|---|---|
LinearEquation<T> |
y = Ax + B. Create from points, angle, or direction. Compute, zero point, intersect, perpendicular, translate, mirror. |
QuadraticEquation<T> |
ax^2 + bx + c = 0. Zero points using the discriminant. |
CubicEquation<T> |
ax^3 + bx^2 + cx + d = 0. Root finding via Newton-Raphson. |
CircleEquation<T> |
(x-cx)^2 + (y-cy)^2 = r^2. Intersect with LinearEquation<T>. |
Colors
| Type | Description |
|---|---|
Color |
ARGB color as a 32-bit uint. Parse from hex (#RRGGBB, #AARRGGBB), rgba(r,g,b,a), or HSV strings. GetHue(), GetSaturation(), GetLightness(), GetBrightness(), MakeTransparent(float). Implicit from string or tuple. JSON and Protobuf serialization. |
HsvColor |
HSV (hue, saturation, value) color space with optional alpha. Implicit conversions to/from Color. Parse from hsv()/hsva() strings, JSON arrays, or hex. |
Interfaces
// Composable geometry traits
public interface IArea<T> { T Area(); }
public interface IPerimeter<T> { T Perimeter(); }
public interface ICentroid<T> { Point<T> Centroid(); }
public interface IBoundingBox<T> { Rectangle<T> BoundingBox(); }
public interface IRotatable<T, TSelf> { TSelf Rotate(Degree<T> angle, Point<T> origin = default); }
public interface IScalable<T, TSelf> { TSelf Scale(T factor); }
// Unified shape interface -- combines all of the above plus point containment
public interface IShape<T, TSelf> : IArea<T>, IPerimeter<T>, ICentroid<T>,
IBoundingBox<T>, IRotatable<T, TSelf>, IScalable<T, TSelf>
{
bool Contains(Point<T> point);
}
Implementing types: Circle<T>, Triangle<T>, Polygon<T>, and Rectangle<T> (partial -- no IRotatable since rotation produces a Polygon<T>).
Key Features
Generic Math
All geometry types are parameterized by T with constraints like IFloatingPointIeee754<T>, IMinMaxValue<T>, etc. This means the same code works with any numeric type:
// Single precision
var pf = new Point<float>(1f, 2f);
var cf = new Circle<float>(pf, 5f);
// Double precision
var pd = new Point<double>(1.0, 2.0);
var cd = new Circle<double>(pd, 5.0);
// Both compute area with their respective precision
float areaF = cf.Area();
double areaD = cd.Area();
IShape Interface Hierarchy
Write generic algorithms over any shape:
void PrintShapeInfo<T, TShape>(TShape shape)
where T : INumber<T>, ITrigonometricFunctions<T>, IRootFunctions<T>,
IFloatingPoint<T>, ISignedNumber<T>, IFloatingPointIeee754<T>, IMinMaxValue<T>
where TShape : IShape<T, TShape>
{
Console.WriteLine($"Area: {shape.Area()}");
Console.WriteLine($"Perimeter: {shape.Perimeter()}");
Console.WriteLine($"Centroid: {shape.Centroid()}");
Console.WriteLine($"Bounds: {shape.BoundingBox()}");
}
Intersections
The Intersections static class provides 21 combination overloads covering every pair of: Line, Segment, Circle, Triangle, Rectangle, and Polygon. Each combination also has a zero-allocation FirstOf variant.
// Line x Line
Point<double>? p = Intersections.Of(line1, line2);
// Line x Circle -> chord (Segment) or null
Segment<double>? chord = Intersections.Of(line, circle);
// Tangent detection
Point<double>? tangent = Intersections.TangentPoint(line, circle);
// Circle x Circle -> radical chord or tangent point
Segment<double>? radicalChord = Intersections.Of(circle1, circle2);
// Segment x Segment
Point<double>? hit = Intersections.Of(seg1, seg2);
// Zero-alloc first-hit variants
Segment<double>? first = Intersections.FirstOf(line, polygon);
Instance methods are also available on each shape for convenience:
Segment<double>? chord = circle.Intersect(line);
Point<double>? hit = segment.Intersect(otherSegment);
Segment<double>? clipped = line.Intersect(rectangle);
Polygon Boolean Operations
Powered by Clipper2:
var a = new Polygon<double>( /* ... */ );
var b = new Polygon<double>( /* ... */ );
// Operators
Polygon<double> union = a | b;
Polygon<double> intersect = a & b;
Polygon<double> difference = a - b;
// Methods returning multiple result polygons
List<Polygon<double>> unions = a.Union(b, removeHoles: true);
List<Polygon<double>> diffs = a.Subtract(b);
// Batch operations
List<Polygon<double>> merged = Polygon<double>.Union(polygons);
// Clustering overlapping polygons
IEnumerable<Polygon<double>> clusters = Polygon<double>.Cluster(polygons);
Bezier Path Clipping
Path<T>.Intersect(Rectangle<T>) performs analytically exact Bezier-rectangle clipping. It finds the precise parameter values where each cubic Bezier segment crosses the rectangle edges, then uses SubCurve(t0, t1) via De Casteljau subdivision to return exact sub-paths -- not polygon approximations.
var path = Path<double>.FromPoints(points);
IEnumerable<Path<double>> clipped = path.Intersect(viewport);
foreach (var subPath in clipped)
{
// Each sub-path contains only the Bezier segments inside the rectangle,
// with curves split precisely at the rectangle boundaries.
}
Serialization
Protobuf -- all core types carry [ProtoContract] / [ProtoMember] attributes for use with protobuf-net:
var point = new Point<float>(1f, 2f);
byte[] bytes = Serializer.Serialize(point);
JSON -- custom System.Text.Json converters for Point<T>, Polygon<T>, Path<T>, Color, and HsvColor:
var polygon = new Polygon<double>( /* ... */ );
string json = JsonSerializer.Serialize(polygon);
String parsing -- IParsable<T> implementations on Point<T>, Rectangle<T>, Size<T>, Path<T>, Color, and HsvColor:
var point = Point<double>.Parse("1.5, 2.5");
var rect = Rectangle<double>.Parse("0 0 100 200");
var color = Color.Parse("#FF8800");
var path = Path<double>.Parse("M 0 0 C 1 2, 3 4, 5 6", null);
SVG Export
Polygon<T> and Path<T> support SVG export via the [SvgExporter] attribute and the SvgExporter infrastructure:
// Path<T>.ToString() produces SVG path data
var path = Path<double>.FromPoints(points);
string svgData = path.ToString(); // "M 0 0 C 1.5 2.3, 3.1 4.2, 5 6 ..."
Code Examples
Points: Distance, Lerp, Rotate
var a = new Point<double>(0, 0);
var b = new Point<double>(3, 4);
double dist = a.DistanceTo(b); // 5.0
Point<double> quarter = a.Lerp(b, 0.25); // {X=0.75, Y=1}
Point<double> reflected = a.Reflect(b); // {X=6, Y=8}
// Rotate 90 degrees around the origin
Degree<double> angle = 90.0;
Point<double> rotated = b.Rotate(angle); // {X=-4, Y=3}
// Rotate around a custom center
var center = new Point<double>(1, 1);
Point<double> rotated2 = b.Rotate(angle, center);
// Clamp to a rectangle
var bounds = new Rectangle<double>(0, 0, 10, 10);
Point<double> clamped = new Point<double>(15, -3).Clamp(bounds); // {X=10, Y=0}
Shapes: Area and Perimeter
// Circle
var circle = new Circle<double>(new Point<double>(5, 5), 3.0);
double cArea = circle.Area(); // ~28.274
double cPerim = circle.Perimeter(); // ~18.850
// Triangle
var triangle = new Triangle<double>(
new Point<double>(0, 0),
new Point<double>(4, 0),
new Point<double>(0, 3));
double tArea = triangle.Area(); // 6.0
double tPerim = triangle.Perimeter(); // 12.0
// Polygon (shoelace formula)
var poly = new Polygon<double>(
new Point<double>(0, 0), new Point<double>(4, 0),
new Point<double>(4, 3), new Point<double>(0, 3));
double pArea = poly.Area(); // 12.0
Line-Circle Intersection
var circle = new Circle<double>(new Point<double>(0, 0), 5.0);
var line = Line<double>.From(new Point<double>(-10, 0), new Point<double>(10, 0));
// Secant -- returns the chord as a segment
Segment<double>? chord = circle.Intersect(line);
// chord.Value.Start ~ {X=-5, Y=0}, chord.Value.End ~ {X=5, Y=0}
// Tangent detection
var tangentLine = Line<double>.Horizontal(5.0);
Point<double>? tangent = circle.TangentPoint(tangentLine);
// tangent.Value ~ {X=0, Y=5}
Segment-Rectangle Clipping
var viewport = new Rectangle<double>(0, 0, 100, 100);
var segment = new Segment<double>(
new Point<double>(-20, 50),
new Point<double>(150, 50));
// Liang-Barsky clipping
Segment<double>? clipped = segment.Intersect(viewport);
// clipped.Value: Start={X=0, Y=50}, End={X=100, Y=50}
Path-Rectangle Clipping
var points = new[]
{
new Point<double>(10, 50),
new Point<double>(50, 10),
new Point<double>(90, 50),
new Point<double>(130, 90)
};
var path = Path<double>.FromPoints(points);
var viewport = new Rectangle<double>(20, 20, 60, 60); // 20,20 to 80,80
// Exact Bezier clipping -- returns sub-paths with curves split at boundaries
foreach (var subPath in path.Intersect(viewport))
{
Console.WriteLine($"Sub-path with {subPath.Count} Bezier segments");
}
Triangle Properties
var t = new Triangle<double>(
new Point<double>(0, 0),
new Point<double>(4, 0),
new Point<double>(2, 3));
// Derived circles
Circle<double> incircle = t.Incircle(); // largest circle inside
Circle<double> circumcircle = t.Circumcircle(); // passes through all vertices
// Center points
Point<double> centroid = t.Centroid();
Point<double> orthocenter = t.Orthocenter;
// Classification
bool right = t.IsRight();
bool equilateral = t.IsEquilateral();
bool isosceles = t.IsIsosceles();
// Similarity and congruence
var t2 = new Triangle<double>(
new Point<double>(0, 0),
new Point<double>(8, 0),
new Point<double>(4, 6));
bool similar = t.IsSimilarTo(t2); // true (same shape, scaled 2x)
bool congruent = t.IsCongruentTo(t2); // false (different size)
// Interior angles
var (atA, atB, atC) = t.Angles;
Polygon Operations
// Convex hull
var cloud = new Polygon<double>(
new Point<double>(0, 0), new Point<double>(1, 3),
new Point<double>(2, 1), new Point<double>(4, 4),
new Point<double>(3, 0), new Point<double>(5, 2));
Polygon<double> hull = cloud.ConvexHull();
// Point containment (ray casting)
bool inside = hull.Contains(new Point<double>(2, 2));
// Boolean operations
var a = new Polygon<double>( /* ... */ );
var b = new Polygon<double>( /* ... */ );
List<Polygon<double>> union = a.Union(b, removeHoles: true);
List<Polygon<double>> diff = a.Subtract(b);
List<Polygon<double>> inter = a.Intersect(b);
// Simplify (remove collinear/close points)
Polygon<double> simplified = hull.Simplify(epsilon: 0.1);
// Convexity test
bool convex = hull.IsConvex();
// Clustering overlapping polygons
var clusters = Polygon<double>.Cluster(polygons);
Matrix Transformations
// Build a transformation
var matrix = Matrix<double>.Identity;
matrix.Translate(10.0, 20.0);
matrix.Rotate(Degree<double>.Create(45.0));
matrix.Scale(2.0, 2.0);
// Transform points and vectors
Point<double> transformed = matrix.Transform(new Point<double>(1, 0));
Vector<double> rotatedVec = matrix.Transform(new Vector<double>(1, 0));
// Compose matrices
var combined = matrix1 * matrix2;
// Invert
matrix.Invert();
Point<double> original = matrix.Transform(transformed);
// Transform a path
var path = Path<double>.FromPoints(points);
Path<double> transformedPath = path.Transform(matrix);
Requirements
- .NET 9.0 or later (uses generic math interfaces from .NET 7+)
- Dependencies: Clipper2 1.4.0, protobuf-net 3.2.45
License
See LICENSE for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- Clipper2 (>= 1.4.0)
- protobuf-net (>= 3.2.45)
NuGet packages (9)
Showing the top 5 NuGet packages that depend on ModelingEvolution.Drawing:
| Package | Downloads |
|---|---|
|
RocketWelder.SDK
High-performance video streaming client library for RocketWelder services with zero-copy shared memory support |
|
|
BlazorBlaze
High-performance 2D canvas engine for Blazor using SkiaSharp. Features include scene graph, hit detection, camera zoom/pan, extensible controls, and reactive data binding. |
|
|
ModelingEvolution.Controls.Blazor.ResizableControl
Resizable |
|
|
ModelingEvolution.Controls.Blazor.SvgCanvasControl
SvgCanvasControl |
|
|
ModelingEvolution.HdrSplitControl
HDR Split Canvas Controls for Blazor |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.4.0.55 | 0 | 2/6/2026 |
| 1.3.0.54 | 0 | 2/6/2026 |
| 1.2.1.53 | 0 | 2/6/2026 |
| 1.2.0.52 | 0 | 2/6/2026 |
| 1.1.5.51 | 110 | 1/18/2026 |
| 1.1.4.50 | 85 | 1/18/2026 |
| 1.1.3.49 | 85 | 1/18/2026 |
| 1.1.2.48 | 87 | 1/18/2026 |
| 1.1.1.47 | 157 | 1/12/2026 |
| 1.1.0.46 | 89 | 1/12/2026 |
| 1.0.63.45 | 806 | 11/24/2025 |
| 1.0.62.44 | 649 | 9/28/2025 |
| 1.0.61.43 | 132 | 9/26/2025 |
| 1.0.60.42 | 147 | 9/26/2025 |
| 1.0.59.41 | 160 | 9/26/2025 |
| 1.0.58.36 | 189 | 9/5/2025 |
| 1.0.53.35 | 331 | 2/26/2025 |
| 1.0.48.34 | 176 | 2/3/2025 |
| 1.0.47.33 | 143 | 1/28/2025 |
| 1.0.46.33 | 135 | 1/28/2025 |
| 1.0.45.33 | 152 | 1/27/2025 |
| 1.0.44.33 | 143 | 1/27/2025 |
| 1.0.43.33 | 141 | 1/27/2025 |
| 1.0.42.32 | 140 | 1/27/2025 |
| 1.0.41.31 | 154 | 1/27/2025 |
| 1.0.40.31 | 144 | 1/27/2025 |
| 1.0.39.29 | 153 | 1/27/2025 |
| 1.0.38.28 | 160 | 1/26/2025 |
| 1.0.37.28 | 157 | 1/26/2025 |
| 1.0.36.28 | 147 | 1/22/2025 |
| 1.0.35.26 | 219 | 12/2/2024 |
| 1.0.34.26 | 158 | 11/29/2024 |
| 1.0.32.26 | 157 | 11/4/2024 |
| 1.0.31.26 | 158 | 11/4/2024 |
| 1.0.30.26 | 155 | 11/3/2024 |
| 1.0.29.26 | 169 | 10/30/2024 |
| 1.0.28.25 | 144 | 10/30/2024 |
| 1.0.27.24 | 193 | 9/30/2024 |
| 1.0.26.23 | 166 | 9/19/2024 |
| 1.0.25.22 | 453 | 5/7/2024 |
| 1.0.23.22 | 156 | 5/7/2024 |
| 1.0.22.22 | 162 | 5/7/2024 |
| 1.0.21.21 | 148 | 5/7/2024 |
| 1.0.20.21 | 173 | 4/17/2024 |
| 1.0.19.18 | 187 | 2/26/2024 |
| 1.0.18.18 | 188 | 2/26/2024 |
| 1.0.17.17 | 170 | 2/26/2024 |
| 1.0.16.17 | 174 | 2/26/2024 |
| 1.0.15.15 | 172 | 2/15/2024 |
| 1.0.14.14 | 179 | 2/14/2024 |
| 1.0.13.13 | 173 | 2/12/2024 |
| 1.0.10.13 | 185 | 2/7/2024 |
| 1.0.6.12 | 174 | 2/6/2024 |
| 1.0.5.9 | 167 | 2/5/2024 |
| 1.0.0 | 169 | 2/5/2024 |
| 0.0.3.7 | 158 | 2/5/2024 |