Files
2026-05-27 23:29:53 +01:00

6.8 KiB

OpenSpec Change: enterprise-osm-buildings

  • Change ID: enterprise-osm-buildings
  • Package: @suaveplan/osm-buildings
  • Category: universal
  • Target path: universal/geo/osm-buildings
  • Status: IN PROGRESS
  • Date: 2026-04-24
  • Reference spec: /mnt/s/web/suaveplan/enterprise/osm-buildings.md

Summary

Deliver @suaveplan/osm-buildings on the genesis branch from scratch at enterprise quality. The package provides OpenStreetMap building and road geometry extraction and mesh generation: OSM XML/PBF-lite parsing, building footprint extraction from building=* relations and ways, road network extraction from highway=* ways, polygon simplification (Ramer-Douglas-Peucker), 2.5D extruded building mesh generation (flat roof, pitched roof from roof:shape=*), LOD (level of detail) tile pyramid for buildings, elevation offset from @suaveplan/heightmap-tiles, GeoJSON and flat-buffer mesh output, and a streaming feature extractor. Genesis adds structured errors, Zod schemas, OTel instrumentation, and property-based tests.


Current-state audit (genesis)

The package does not exist on genesis yet — this is a fresh build.


Available workspace deps on genesis

Package Role
@suaveplan/error (workspace:^) OsmBuildingsError; OSM.* error codes
@suaveplan/types (workspace:^) LoggerLike
@suaveplan/geo (workspace:^) LatLng, BoundingBox, polygon area, coordinate utilities
@suaveplan/heightmap-tiles (workspace:^) Elevation offset for 3D building placement
@suaveplan/serialize (workspace:^) Binary flat-buffer output serialization
zod (catalog:forms) Schema validation
@opentelemetry/api (catalog:observability) Spans + counters

Dev deps: vitest, @vitest/coverage-istanbul, fast-check (all catalog:testing).


Public API surface

Core types

interface OsmBuilding {
  id: string                   // OSM way/relation ID
  footprint: LatLng[]          // exterior ring, counter-clockwise
  holes: LatLng[][]            // interior rings
  height: number               // metres; 0 if unknown
  minHeight: number            // metres above ground; for bridges/overhangs
  levels?: number
  roofShape?: RoofShape
  tags: Record<string, string> // raw OSM tags
}

type RoofShape = 'flat' | 'pitched' | 'hipped' | 'dome' | 'pyramidal' | 'unknown'

interface OsmRoad {
  id: string
  points: LatLng[]
  highway: string              // OSM highway value e.g. 'primary', 'residential'
  name?: string
  lanes?: number
  oneWay: boolean
  tags: Record<string, string>
}

interface BuildingMesh {
  buildingId: string
  vertices: Float32Array       // xyz triplets
  indices: Uint32Array         // triangle indices
  uvs?: Float32Array           // optional UV coords
}

Parsers

function parseOsmXml(xml: string, options?: ParseOptions): OsmFeatureSet
function parseOsmPbfLite(buffer: Uint8Array, options?: ParseOptions): OsmFeatureSet

interface OsmFeatureSet {
  buildings: OsmBuilding[]
  roads: OsmRoad[]
  bbox: BoundingBox
}

interface ParseOptions {
  bbox?: BoundingBox           // filter to bounding box
  includeBuildings?: boolean   // default true
  includeRoads?: boolean       // default true
  signal?: AbortSignal
}

Mesh generation

function buildingToMesh(
  building: OsmBuilding,
  options?: MeshOptions
): BuildingMesh

function buildingsToMeshes(
  buildings: OsmBuilding[],
  options?: MeshOptions
): BuildingMesh[]

interface MeshOptions {
  store?: HeightmapTileStore   // for elevation offset; optional
  lodLevel?: number            // 0 = highest detail; higher = simplified
  uvScale?: number
}

Simplification

function simplifyPolygon(ring: LatLng[], toleranceMetres: number): LatLng[]
function simplifyRoad(points: LatLng[], toleranceMetres: number): LatLng[]

Streaming extractor

function createOsmFeatureStream(options?: ParseOptions): OsmFeatureStream

interface OsmFeatureStream {
  writable: WritableStream<Uint8Array>  // OSM XML or PBF-lite bytes
  readable: ReadableStream<OsmBuilding | OsmRoad>
}

Error codes

type OsmBuildingsErrorCode =
  | 'OSM_PARSE_FAILED'
  | 'OSM_INVALID_GEOMETRY'
  | 'OSM_MESH_FAILED'
  | 'OSM_ELEVATION_FAILED'
  | 'OSM_SIMPLIFY_FAILED'
  | 'OSM_ABORTED'

Genesis additions

  1. OsmBuildingsError extends SuaveplanError with six stable codes.
  2. Zod schemas for OsmBuilding, OsmRoad, OsmFeatureSet, ParseOptions, MeshOptions, BuildingMesh.
  3. PBF-lite parser — supports a simplified subset of OSM PBF (nodes, ways, string table) without requiring a full protobuf library; implemented natively using DataView binary parsing.
  4. LOD pyramid — lodLevel in MeshOptions controls polygon simplification tolerance (level 0 = 0 m, level 1 = 1 m, level 2 = 5 m, level 3 = 20 m) for progressive rendering.
  5. Elevation offset — when a HeightmapTileStore is provided, building vertices receive a per-vertex Z offset from @suaveplan/heightmap-tiles; gracefully degrades to z=0 without a store.
  6. OTel instrumentation — counter osm.buildings_parsed_total; span osm.parse with attribute osm.format; histogram osm.mesh_build_duration_ms.
  7. Property-based tests — simplification never produces self-intersections; mesh index buffer references only valid vertex indices; Ramer-Douglas-Peucker preserves first and last points.

File layout

universal/geo/osm-buildings/
  package.json
  tsconfig.json
  vitest.config.ts
  src/
    index.ts
    error-codes.ts
    constants/
      index.ts
    types/
      common.ts
      common.md
    parsers/
      osm-xml-parser/
        osm-xml-parser.ts
        osm-xml-parser.md
        osm-xml-parser.test.ts
        index.ts
      osm-pbf-parser/
        osm-pbf-parser.ts
        osm-pbf-parser.md
        osm-pbf-parser.test.ts
        index.ts
      feature-extractor/
        feature-extractor.ts
        feature-extractor.md
        feature-extractor.test.ts
        index.ts
    mesh/
      building-mesher/
        building-mesher.ts
        building-mesher.md
        building-mesher.types.ts
        building-mesher.test.ts
        index.ts
      roof-builder/
        roof-builder.ts
        roof-builder.md
        roof-builder.test.ts
        index.ts
    geometry/
      simplifier/
        simplifier.ts
        simplifier.md
        simplifier.test.ts
        index.ts
    streaming/
      osm-feature-stream/
        osm-feature-stream.ts
        osm-feature-stream.md
        osm-feature-stream.test.ts
        index.ts
    __benchmarks__/
      osm-buildings.bench.ts
  tests/
    integration.test.ts
    property.test.ts

Impact

Downstream consumers: 3D map rendering services.

Workspace dep prerequisites: @suaveplan/error, @suaveplan/types, @suaveplan/geo, @suaveplan/heightmap-tiles, @suaveplan/serialize.