Skip to main content

shiny-spatial

Build geospatial applications with Shiny.Spatial - a dependency-free, AOT-compatible .NET spatial database using SQLite R*Tree indexing with custom C# geometry algorithms for two-pass spatial queries

Ir a la instalación

Datos de origen

Repositorio
shinyorg/skills
Última actividad en el origen
15 de agosto de 2026 a las 17:13
Idioma detectado de SKILL.md
inglés
Estrellas
4
Forks
0

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
shiny-spatial
description
Build geospatial applications with Shiny.Spatial - a dependency-free, AOT-compatible .NET spatial database using SQLite R*Tree indexing with custom C# geometry algorithms for two-pass spatial queries
auto_invoke
true
triggers
["spatial","geospatial","spatial database","rtree","shiny.spatial","shiny spatial","geofence","geofencing","region change"]
# Shiny.Spatial Skill ## Triggers - spatial - geospatial - spatial database - rtree - shiny.spatial - shiny spatial - geofence - geofencing - region change You are an expert in Shiny.Spatial, a dependency-free, cross-platform .NET geospatial database library that uses SQLite R*Tree for spatial indexing with custom C# geometry algorithms for query refinement. No SpatiaLite, no NetTopologySuite — only SQLite via `Microsoft.Data.Sqlite`. ## When to Use This Skill Invoke this skill when the user wants to: - Create or query a spatial database with geospatial data - Store and retrieve geometry objects (Points, LineStrings, Polygons, Multi*, GeometryCollection) - Perform spatial queries: distance, intersection, containment, bounding box - Use the fluent query builder with property filters and distance ordering - Work with WKB (Well-Known Binary) serialization - Use pre-built databases (US/Canadian states, provinces, cities) - Build location-aware applications on iOS, Android, or any .NET platform - Set up GPS-driven geofence monitoring with enter/exit events - Implement an `ISpatialGeofenceDelegate` for region change handling - Configure `ISpatialGeofenceManager` to start/stop geofence detection ## Library Overview **Repository**: https://github.com/shinyorg/geospatialdb **Namespace**: `Shiny.Spatial` **AOT compatible and trimmable.** ### Target Frameworks | Package | Framework | Notes | |---|---|---| | `Shiny.Spatial` | `net10.0` | AOT compatible and trimmable | | `Shiny.Spatial.Geofencing` | `net10.0-ios`, `net10.0-android` | iOS/Android GPS geofencing | ### Dependencies - `Microsoft.Data.Sqlite` — brings `SQLitePCLRaw.bundle_e_sqlite3` with R*Tree enabled - `Shiny.Locations` — geofencing package only (background GPS) ## Setup ### Install NuGet Package ```bash dotnet add package Shiny.Spatial ``` ## Architecture ### Two-Pass Query Pipeline 1. **R*Tree bounding box filter** (SQL, O(log n)) — eliminates most candidates using the SQLite R*Tree index 2. **C# geometry refinement** — exact Contains/Intersects/WithinDistance checks on survivors ### SQLite Schema Each spatial table creates a single R*Tree virtual table with auxiliary columns: ```sql CREATE VIRTUAL TABLE {name}_rtree USING rtree( id, min_x, max_x, min_y, max_y, +geometry BLOB, -- WKB-encoded geometry +prop_{name} {type}, ... -- user-defined property columns ); ``` Metadata is tracked in `__spatial_meta` and `__spatial_columns` tables. ## Geometry Types All geometry classes are immutable and sealed, extending the abstract `Geometry` base class. Namespace: `Shiny.Spatial.Geometry`. | Type | Description | |---|---| | `Coordinate` | Readonly struct with `X`/`Y` (aliased as `Longitude`/`Latitude`) | | `Envelope` | Readonly struct — bounding box with `MinX`, `MaxX`, `MinY`, `MaxY` | | `Point` | Single coordinate | | `LineString` | Ordered sequence of coordinates (minimum 2) | | `Polygon` | Exterior ring + optional interior rings (holes) | | `MultiPoint` | Collection of Points | | `MultiLineString` | Collection of LineStrings | | `MultiPolygon` | Collection of Polygons | | `GeometryCollection` | Collection of mixed Geometry types | ### Creating Geometries ```csharp using Shiny.Spatial.Geometry; // Point var point = new Point(-104.99, 39.74); // LineString (minimum 2 coordinates) var line = new LineString(new[] { new Coordinate(-104.99, 39.74), new Coordinate(-104.82, 38.83) }); // Polygon (exterior ring, closed — first == last coordinate) 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) }); // Polygon with holes var polygonWithHole = new Polygon( exteriorRing: new[] { /* outer coords */ }, interiorRings: new[] { new[] { /* hole coords */ } } ); // Multi types var multiPoint = new MultiPoint(new[] { point1, point2 }); var multiLine = new MultiLineString(new[] { line1, line2 }); var multiPoly = new MultiPolygon(new[] { polygon1, polygon2 }); var collection = new GeometryCollection(new Geometry[] { point, line, polygon }); ``` ## Database API ### SpatialDatabase (IDisposable) ```csharp using Shiny.Spatial.Database; var db = new SpatialDatabase("path.db"); // file-backed var db = new SpatialDatabase(":memory:"); // in-memory SpatialTable table = db.CreateTable(name, coordinateSystem, properties...); SpatialTable table = db.GetTable(name); bool exists = db.TableExists(name); db.DropTable(name); db.Dispose(); ``` ### Creating Tables with Properties ```csharp var table = db.CreateTable("cities", CoordinateSystem.Wgs84, new PropertyDefinition("name", PropertyType.Text), new PropertyDefinition("population", PropertyType.Integer), new PropertyDefinition("area", PropertyType.Real)); ``` | PropertyType | Description | |---|---| | `Text` | String values | | `Integer` | Long integer values | | `Real` | Double floating point values | | `Blob` | Binary data | ### SpatialTable CRUD | Method | Returns | Description | |---|---|---| | `Insert(feature)` | `long` | Insert a feature, returns its ID | | `BulkInsert(features)` | `void` | Insert many features in a single transaction | | `Update(feature)` | `void` | Update a feature by ID | | `Delete(id)` | `bool` | Delete a feature by ID | | `GetById(id)` | `SpatialFeature?` | Retrieve a single feature | | `Count()` | `long` | Total feature count | ### SpatialFeature ```csharp var feature = new SpatialFeature(new Point(-104.99, 39.74)) { Properties = { ["name"] = "Denver", ["population"] = 715000L } }; long id = feature.Id; // set after Insert Geometry geom = feature.Geometry; Dictionary<string, object?> props = feature.Properties; ``` ### Spatial Queries | Method | Description | |---|---| | `FindInEnvelope(envelope)` | R*Tree bounding box query | | `FindIntersecting(geometry)` | Two-pass intersection query | | `FindContainedBy(geometry)` | Two-pass containment query | | `FindWithinDistance(center, meters)` | Two-pass distance query | | `Query()` | Returns a fluent `SpatialQuery` builder | ```csharp // Distance query var nearby = table.FindWithinDistance( new Coordinate(-104.99, 39.74), distanceMeters: 150_000 ); // Shape intersection var inState = table.FindIntersecting(coloradoPolygon); // Bounding box var envelope = new Envelope(-110, -100, 35, 42); var inBox = table.FindInEnvelope(envelope); ``` ### Fluent Query Builder | Method | Type | Description | |---|---|---| | `InEnvelope(envelope)` | Filter | Bounding box filter | | `Intersecting(geometry)` | Filter | Geometry intersection | | `ContainedBy(geometry)` | Filter | Geometry containment | | `WithinDistance(center, meters)` | Filter | Distance radius | | `WhereProperty(name, op, value)` | Filter | Property comparison (`=`, `!=`, `<`, `<=`, `>`, `>=`, `LIKE`) | | `OrderByDistance(center)` | Sort | Order by distance from coordinate | | `Limit(count)` | Paging | Limit result count | | `Offset(count)` | Paging | Skip first N results | | `ToList()` | Terminal | Execute and return results | | `Count()` | Terminal | Execute and return count | | `FirstOrDefault()` | Terminal | Execute and return first or null | ```csharp var center = new Coordinate(-104.99, 39.74); var results = table.Query() .WithinDistance(center, 150_000) .WhereProperty("population", ">", 200000L) .OrderByDistance(center) .Limit(10) .ToList(); int count = table.Query().InEnvelope(envelope).Count(); var first = table.Query().WithinDistance(center, 1000).FirstOrDefault(); ``` ## Algorithms Namespace: `Shiny.Spatial.Algorithms` | Class | Method | Description | |---|---|---| | `DistanceCalculator` | `Haversine(a, b)` | Great-circle distance in meters (WGS84) | | `DistanceCalculator` | `Euclidean(a, b)` | Cartesian distance | | `DistanceCalculator` | `DistanceToSegment(p, a, b)` | Perpendicular distance from point to segment | | `PointInPolygon` | `Contains(polygon, point)` | Ray-casting with hole support | | `SegmentIntersection` | `Intersects(a1, a2, b1, b2)` | Cross-product segment intersection test | | `SpatialPredicates` | `Intersects(a, b)` | Dispatch for all geometry type combinations | | `SpatialPredicates` | `Contains(container, contained)` | Dispatch for all geometry type combinations | | `EnvelopeExpander` | `ExpandByDistance(env, meters, cs)` | Expand envelope by distance (WGS84 or Cartesian) | ## WKB Serialization ```csharp using Shiny.Spatial.Serialization; byte[] wkb = WkbWriter.Write(geometry); Geometry restored = WkbReader.Read(wkb); ``` Full roundtrip support for all geometry types using the WKB (Well-Known Binary) format. ## Pre-Built Databases Located in `databases/`: | Database | Table | Geometry | Records | Properties | |---|---|---|---|---| | `us-states.db` | `states` | Polygon | 51 (50 states + DC) | `name`, `abbreviation`, `population` | | `us-cities.db` | `cities` | Point | 100 (top 100 by pop.) | `name`, `state`, `population` | | `ca-provinces.db` | `provinces` | Polygon | 13 (all provinces/territories) | `name`, `abbreviation`, `population` | | `ca-cities.db` | `cities` | Point | 50 (top 50 by pop.) | `name`, `province`, `population` | All use `CoordinateSystem.Wgs84` (longitude/latitude). ```csharp using var db = new SpatialDatabase("databases/us-states.db"); var states = db.GetTable("states"); // Find which state Denver is in var denver = new Point(-104.99, 39.74); var results = states.FindIntersecting(denver); // results[0].Properties["name"] == "Colorado" ``` ## Coordinate Systems | System | Enum | Distance Algorithm | Use Case | |---|---|---|---| | WGS84 | `CoordinateSystem.Wgs84` | Haversine (great-circle) | Real-world GPS coordinates | | Cartesian | `CoordinateSystem.Cartesian` | Euclidean | Flat/projected coordinate systems | ## Code Generation Instructions When generating code with Shiny.Spatial: ### 1. Database Lifecycle - Always wrap `SpatialDatabase` in a `using` statement or `IDisposable` pattern - Use `:memory:` for tests, file paths for production - Call `CreateTable` for new tables, `GetTable` for existing tables ### 2. Coordinate System Selection - Use `CoordinateSystem.Wgs84` for real-world GPS latitude/longitude data - Use `CoordinateSystem.Cartesian` for projected or flat coordinate systems - WGS84 uses Haversine distance (meters), Cartesian uses Euclidean distance ### 3. Property Types - Use `PropertyType.Text` for strings - Use `PropertyType.Integer` for long values — always use `L` suffix (e.g., `715000L`) - Use `PropertyType.Real` for doubles - Use `PropertyType.Blob` for binary data ### 4. Query Strategy - For simple spatial queries, use the direct methods (`FindWithinDistance`, `FindIntersecting`, etc.) - For combined spatial + property filtering, use the fluent `Query()` builder - Always apply spatial filters first (they use the R*Tree index) before property filters - Use `Limit()` and `Offset()` for pagination - Use `OrderByDistance()` for nearest-neighbor results ### 5. Bulk Operations - Use `BulkInsert()` for inserting multiple features — it wraps in a transaction for performance - Single `Insert()` is fine for one-off inserts ### 6. Geometry Construction - Polygons must be closed (first coordinate == last coordinate) - LineStrings require minimum 2 coordinates - Use `Coordinate` struct for X/Y pairs (aliases: `Longitude`/`Latitude`) ### 7. Testing Pattern ```csharp using var db = new SpatialDatabase(":memory:"); var table = db.CreateTable("test", CoordinateSystem.Wgs84, new PropertyDefinition("name", PropertyType.Text));
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub