-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
Implement core Geometry Server operations for spatial analysis and geometry processing using PostGIS functions.
Background
From the roadmap (docs/ROADMAP.md):
GeometryServer basics: project, buffer, simplify.
These operations are fundamental for geospatial analysis and are commonly used in GIS applications. PostGIS provides efficient implementations that should be exposed through REST API endpoints.
Proposed Operations
1. Buffer Operations
Create buffer zones around geometries - critical for proximity analysis.
Endpoint: POST /rest/services/geometry/buffer
Use Cases:
- Environmental impact zones (500m around industrial sites)
- Service areas (1km around schools, hospitals)
- Transportation corridors (50m buffer around highways)
- Property setbacks and zoning analysis
2. Simplify Operations
Reduce geometry complexity while preserving essential shape characteristics.
Endpoint: POST /rest/services/geometry/simplify
Use Cases:
- Optimize geometries for web display at different zoom levels
- Reduce file sizes for data export
- Improve query performance on complex geometries
- Cartographic generalization
3. Project/Transform Operations
Convert geometries between coordinate reference systems.
Endpoint: POST /rest/services/geometry/project
Use Cases:
- Convert GPS coordinates (WGS84) to local projected coordinates
- Reproject imported data to match layer CRS
- Convert between different national grid systems
- Prepare data for area/distance calculations
API Design
Buffer Request/Response
POST /rest/services/geometry/buffer
{
"geometries": [
{"x": -122.4194, "y": 37.7749}
],
"inSR": 4326,
"outSR": 4326,
"distances": [1000],
"unit": "esriMeters",
"unionResults": false,
"geodesic": true
}
Response:
{
"geometries": [
{"rings": [[...]]}
],
"spatialReference": {"wkid": 4326}
}Simplify Request/Response
POST /rest/services/geometry/simplify
{
"geometries": [
{"rings": [[...]]}
],
"inSR": 4326,
"outSR": 4326,
"maxDeviation": 10,
"deviationUnit": "esriMeters"
}Project Request/Response
POST /rest/services/geometry/project
{
"geometries": [
{"x": -122.4194, "y": 37.7749}
],
"inSR": 4326,
"outSR": 3857,
"transformation": null
}Acceptance Criteria
Buffer Operations
- Point buffer creates circular polygon (using geography for geodesic)
- Polygon buffer creates expanded/contracted polygon
- Line buffer creates corridor polygon
- Multiple distance values create multiple buffer zones
- Union option combines overlapping buffers
- Geodesic vs planar buffer options work correctly
Simplify Operations
- Douglas-Peucker algorithm via
ST_Simplify - Preserve topology option via
ST_SimplifyPreserveTopology - Tolerance specified in various units (meters, degrees, feet)
- Works with all geometry types (point, line, polygon)
- Simplified geometries remain valid
Project/Transform Operations
- Transform between any EPSG coordinate systems
- Batch transformation of multiple geometries
- Automatic datum transformation when needed
- Error handling for unsupported CRS combinations
- Performance optimization for same-CRS requests (no-op)
Error Handling
- Invalid geometry input returns descriptive errors
- Unsupported CRS returns proper error codes
- Buffer distance validation (positive values)
- Simplify tolerance validation (reasonable ranges)
Technical Implementation
PostGIS Function Mapping
public class GeometryService
{
// Buffer - use geography type for geodesic buffers
public async Task<byte[]> BufferAsync(byte[] wkb, double distance, bool geodesic)
{
var sql = geodesic
? "SELECT ST_AsBinary(ST_Buffer(ST_GeomFromWKB(@wkb)::geography, @distance)::geometry)"
: "SELECT ST_AsBinary(ST_Buffer(ST_GeomFromWKB(@wkb), @distance))";
// ...
}
// Simplify - with topology preservation option
public async Task<byte[]> SimplifyAsync(byte[] wkb, double tolerance, bool preserveTopology)
{
var function = preserveTopology ? "ST_SimplifyPreserveTopology" : "ST_Simplify";
var sql = $"SELECT ST_AsBinary({function}(ST_GeomFromWKB(@wkb), @tolerance))";
// ...
}
// Transform - leverage PostGIS CRS database
public async Task<byte[]> TransformAsync(byte[] wkb, int fromSrid, int toSrid)
{
if (fromSrid == toSrid) return wkb; // No-op optimization
var sql = "SELECT ST_AsBinary(ST_Transform(ST_SetSRID(ST_GeomFromWKB(@wkb), @fromSrid), @toSrid))";
// ...
}
}Endpoint Controllers
[HttpPost("buffer")]
public async Task<IResult> BufferAsync([FromBody] BufferRequest request)
{
var results = new List<EsriGeometry>();
foreach (var geometry in request.Geometries)
{
var wkb = _converter.ConvertEsriJsonToWkb(JsonSerializer.Serialize(geometry));
var buffered = await _geometryService.BufferAsync(wkb, request.Distance, request.Geodesic);
var esriGeom = _converter.ConvertWkbToEsriJson(buffered);
results.Add(esriGeom);
}
return Results.Ok(new BufferResponse { Geometries = results });
}Performance Considerations
- Batch operations - Process multiple geometries efficiently
- Streaming results - Don't buffer large result sets in memory
- Caching - Cache transformation parameters for repeated CRS conversions
- Limits - Impose reasonable limits on input geometry complexity
- Timeouts - Set operation timeouts to prevent DoS
Test Plan
Unit Tests
- PostGIS function calls generate correct SQL
- Parameter validation rejects invalid inputs
- Batch processing works correctly
- Error handling covers edge cases
Integration Tests
- Buffer around point creates expected circular area
- Buffer around line creates expected corridor
- Simplify reduces vertex count while preserving shape
- Transform between common CRS pairs (WGS84 ↔ Web Mercator)
- Batch operations process multiple geometries
- Error responses include helpful messages
Performance Tests
- Buffer operations complete within reasonable time
- Simplify operations reduce complexity as expected
- Transform operations handle large geometry sets
- Memory usage remains bounded during processing
Real-World Use Cases
Environmental Planning
// Create 500m buffer around industrial sites
const bufferRequest = {
geometries: industrialSites,
distances: [500],
unit: "esriMeters",
geodesic: true
};Web Mapping Optimization
// Simplify complex coastline for web display
const simplifyRequest = {
geometries: [coastlineGeometry],
maxDeviation: zoomLevel < 8 ? 100 : 10,
deviationUnit: "esriMeters"
};Coordinate System Conversion
// Convert GPS coordinates to state plane
const projectRequest = {
geometries: gpsPoints,
inSR: 4326, // WGS84
outSR: 2154 // California State Plane
};Dependencies
- Builds on GeometryConverter from Issue Spatial query support (geometry, spatialRel) #7
- May use additional geometry types from Issue feat: Add support for additional geometry types (LINESTRING, MULTIPOINT, MULTIPOLYGON, ENVELOPE) #94
- Leverages PostGIS spatial functions
- Requires geometry validation from Issue feat: Implement geometry validation and repair capabilities #97 for input safety
Legacy Reference
../Honua.Server/src/platform/core/Geometry/- geometry operation patterns- Esri Geometry Service documentation for API compatibility
- PostGIS documentation for
ST_Buffer,ST_Simplify,ST_Transform
Future Enhancements
- Additional operations: Union, Intersection, Difference
- Batch optimization: Spatial index-based processing
- Caching: Cache common transformation results
- Async processing: Queue long-running operations