Skip to content

Algorithms & Serialization

Shiny.Spatial includes standalone algorithm classes and WKB serialization that can be used independently of the database layer.

The DistanceCalculator class provides distance computation between coordinates.

Calculates the great-circle distance between two geographic coordinates on Earth. Returns distance in meters.

using Shiny.Spatial.Algorithms;
var london = new Coordinate(-0.1276, 51.5074);
var paris = new Coordinate(2.3522, 48.8566);
double meters = DistanceCalculator.Haversine(london, paris);
// ~343,000 meters (~343 km)

Calculates the straight-line distance between two points in a flat coordinate system.

var a = new Coordinate(0, 0);
var b = new Coordinate(3, 4);
double distance = DistanceCalculator.Euclidean(a, b);
// 5.0 (classic 3-4-5 triangle)

Calculates the perpendicular distance from a point to a line segment.

var point = new Coordinate(1, 1);
var segStart = new Coordinate(0, 0);
var segEnd = new Coordinate(2, 0);
double distance = DistanceCalculator.DistanceToSegment(point, segStart, segEnd);

The SpatialPredicates class provides geometry-to-geometry relationship testing for any pair of geometry types.

Tests whether two geometries share any point in common.

using Shiny.Spatial.Algorithms;
var point = new Point(-104.99, 39.74);
var polygon = new Polygon(new[]
{
new Coordinate(-109.05, 37.0),
new Coordinate(-102.05, 37.0),
new Coordinate(-102.05, 41.0),
new Coordinate(-109.05, 41.0),
new Coordinate(-109.05, 37.0)
});
bool intersects = SpatialPredicates.Intersects(point, polygon); // true

Tests whether one geometry fully contains another.

bool contains = SpatialPredicates.Contains(polygon, point); // true

The PointInPolygon class implements the ray-casting algorithm for testing whether a coordinate falls inside a polygon, including support for holes (interior rings).

using Shiny.Spatial.Algorithms;
bool inside = PointInPolygon.Contains(polygon, new Coordinate(-104.99, 39.74));

The SegmentIntersection class tests whether two line segments cross each other.

using Shiny.Spatial.Algorithms;
bool crosses = SegmentIntersection.Intersects(
new Coordinate(0, 0), new Coordinate(2, 2), // segment A
new Coordinate(0, 2), new Coordinate(2, 0) // segment B
);
// true (segments form an X)

The EnvelopeExpander class expands an envelope by a distance, accounting for the coordinate system.

using Shiny.Spatial.Algorithms;
var envelope = new Envelope(-105, -104, 39, 40);
// Expand by 10km in WGS84 (accounts for Earth curvature)
var expanded = EnvelopeExpander.ExpandByDistance(
envelope,
meters: 10_000,
CoordinateSystem.Wgs84
);

Benchmark results (Apple M2, .NET 10):

AlgorithmMeanAllocated
Haversine distance28.3 ns-
Euclidean distance0.15 ns-
Point-in-polygon (5 vertices)23.6 ns-
Point-in-polygon (100 vertices)253 ns-
Segment intersection2.7 ns-
SpatialPredicates.Intersects (point/polygon)25.7 ns32 B
SpatialPredicates.Intersects (polygon/polygon)41.9 ns-

Well-Known Binary (WKB) is a standard binary format for encoding geometries. Shiny.Spatial includes a complete WKB encoder and decoder supporting all geometry types.

using Shiny.Spatial.Serialization;
var point = new Point(-104.99, 39.74);
byte[] wkb = WkbWriter.Write(point);
Geometry geometry = WkbReader.Read(wkb);
// Cast to specific type
if (geometry is Point p)
{
Console.WriteLine($"{p.X}, {p.Y}");
}

WKB roundtrip serialization is supported for all geometry types:

  • Point
  • LineString
  • Polygon (with holes)
  • MultiPoint
  • MultiLineString
  • MultiPolygon
  • GeometryCollection
OperationMeanAllocated
Write Point58 ns432 B
Read Point50 ns248 B
Write Polygon (5 vertices)116 ns504 B
Read Polygon (5 vertices)136 ns672 B
Write Polygon (100 vertices)1.37 us5.7 KB
Read Polygon (100 vertices)2.21 us8.4 KB
Write LineString (50 coordinates)705 ns2.8 KB
Read LineString (50 coordinates)827 ns4.2 KB