Skip to content

Getting Started

A lightweight, dependency-free geospatial database for .NET that combines SQLite R*Tree spatial indexing with custom C# geometry algorithms for high-performance spatial queries. No SpatiaLite, no NetTopologySuite — just SQLite and math.

  • Two-pass query pipeline — R*Tree bounding box filter (SQL, O(log n)) followed by C# geometry refinement for exact results
  • Dual coordinate systems — WGS84 (GPS/geographic) with Haversine distance and Cartesian with Euclidean distance
  • Full geometry type support — Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, GeometryCollection
  • WKB serialization — Well-Known Binary encoding/decoding for all geometry types
  • Fluent query builder — Chain spatial filters, property filters, sorting, and paging
  • Bulk insert — Transaction-wrapped batch inserts, ~20% faster than individual inserts
  • Pre-built databases — US states, US cities, Canadian provinces, and Canadian cities included
  • AOT-compatible and trimmable — works with ahead-of-time compilation on all .NET platforms
  • Zero geospatial dependencies — only depends on Microsoft.Data.Sqlite
  1. Install the NuGet package

    Terminal window
    dotnet add package Shiny.Spatial
  2. Create a database and spatial table

    using Shiny.Spatial.Database;
    using Shiny.Spatial.Geometry;
    using var db = new SpatialDatabase("mydata.db");
    var table = db.CreateTable(
    "cities",
    CoordinateSystem.Wgs84,
    new PropertyDefinition("name", PropertyType.Text),
    new PropertyDefinition("population", PropertyType.Integer)
    );
  3. Insert features

    var feature = new SpatialFeature(new Point(-104.99, 39.74))
    {
    Properties = { ["name"] = "Denver", ["population"] = 715000L }
    };
    long id = table.Insert(feature);
  4. Query spatially

    // Find all cities within 150km of Denver
    var results = table.FindWithinDistance(
    new Coordinate(-104.99, 39.74),
    distanceMeters: 150_000
    );
var features = cities.Select(c => new SpatialFeature(new Point(c.Longitude, c.Latitude))
{
Properties = { ["name"] = c.Name, ["population"] = c.Population }
}).ToList();
table.BulkInsert(features);
var colorado = 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)
});
var citiesInColorado = table.FindIntersecting(colorado);
var center = new Coordinate(-104.99, 39.74);
var results = table.Query()
.WithinDistance(center, 150_000)
.WhereProperty("population", ">", 200000L)
.OrderByDistance(center)
.Limit(10)
.ToList();
using var db = new SpatialDatabase("databases/us-states.db");
var states = db.GetTable("states");
var denver = new Point(-104.99, 39.74);
var result = states.FindIntersecting(denver);
// result[0].Properties["name"] == "Colorado"

Shiny.Spatial uses a two-pass query pipeline to deliver both speed and accuracy:

  1. Pass 1 — R*Tree bounding box filter (SQL): SQLite’s R*Tree index rapidly eliminates candidates whose bounding boxes don’t overlap the query region. This runs entirely in SQL at O(log n).

  2. Pass 2 — C# geometry refinement: Remaining candidates are tested with exact geometry algorithms (point-in-polygon, segment intersection, Haversine distance). This eliminates false positives from the bounding box approximation.

This approach eliminates 99%+ of candidates before expensive geometry checks, delivering sub-millisecond queries on datasets of 100K+ features.

Each spatial table creates an R*Tree virtual table with auxiliary columns:

CREATE VIRTUAL TABLE {name}_rtree USING rtree(
id,
min_x, max_x, min_y, max_y,
+geometry BLOB, -- WKB-encoded geometry
+prop_name TEXT, -- user-defined property columns
+prop_population INTEGER
);

Metadata is tracked in two internal tables:

  • __spatial_meta — table coordinate systems
  • __spatial_columns — property definitions
FrameworkSupport
.NET 10+Full support with AOT/trimming
.NET Standard 2.0Full support (Xamarin, .NET Framework, etc.)
iOS / AndroidFull support via Microsoft.Data.Sqlite
Windows / macOS / LinuxFull support