A real, end-to-end 3D (Z + M) editing pipeline over GeoPackage — wired into the running app, backed by an ESRI-compatible FeatureServer, and surfaced through the native ArcGIS Editor widget. No stubs, no flat geometry, no elevation lost.
Most "3D" GIS editors quietly flatten your data. This one doesn't.
GEOMETRY(Z), POINT Z, POLYGON Z.{x,y,z:1500.5} comes back as z = 1500.5.world-elevation ground.hasZ/hasM are read from gpkg_geometry_columns, never hardcoded.// service advertises the layer's true dimensionality { "hasZ": true, "hasM": false, "geometryType": "esriGeometryPoint", "features": [{ "geometry": { "x":-74.006, "y":40.712, "z":1500.5 } }] }
Underground pipes, flight paths, building floors, mine benches, geological strata — none of it lives on a flat plane.
Capture building heights and multi-level features without losing the Z that defines them.
Model pipes and cables at their true depth; navigate below the surface.
Use Z + M for altitude and timestamp along 3D trajectories.
Sub-surface excavation and strata modeling with real vertical precision.
Building information modeling where every floor and fixture has a height.
Plan vertical egress for emergency response scenarios.
All endpoints live under /api/featureserver/{datasetId} and follow the familiar ESRI FeatureServer shape.
| Method & endpoint | Returns | Notes |
|---|---|---|
| GET /{ds} | Service metadata | Capabilities: Query, Create, Update, Delete, Editing, Sync |
| GET /{ds}/{layer} | Layer schema | hasZ/hasM from gpkg_geometry_columns |
| GET /{ds}/{layer}/query | Features | Honors returnZ |
| POST …/addFeatures | Add results | Full Z + M ingestion |
| POST …/updateFeatures | Update results | Per-feature edits |
| POST …/deleteFeatures | Delete results | By OBJECTID |
| POST …/applyEdits | Transactional | Atomic adds + updates + deletes |
Capability strings reflect the implemented controller. Spatial filtering uses NetTopologySuite Envelope.Intersects client-side.
// OGC 12-128r12 standard GPKG blob envelope // magic "GP" + flags + int32 SRID + ISO WKB var writer = new WKBWriter { Strict = false, // allow SRID header HandleSRID = true, HandleOrdinates = XYZM // preserve Z & M }; byte[] blob = writer.Write(ntsGeom);
A single converter does the heavy lifting — ESRI JSON ↔ NTS Geometry ↔ standard GPKG blob — with no heavyweight ORM.
POINT(0 0).ST_Intersects — filtering now via NTS envelopes.edit3d.gpkg (points = POINT Z, polygons = POLYGON Z) on first run.Open the seeded edit3d dataset and start placing features at real elevations in seconds.