PDOK aerial imagery: is it worth wiring in? #179

Merged
viberfox-agent merged 1 commit from feat/175-pdok-aerial-basemap into main 2026-08-29 18:54:37 +00:00
Collaborator

Closes #175

Merged by the autopilot (docs/direction.md) after every Actions job passed on the branch head.

Closes #175 Merged by the autopilot (docs/direction.md) after every Actions job passed on the branch head.
feat(map): the ground can be a photograph, over the Netherlands
All checks were successful
CI / test cartopolis (pull_request) Successful in 19m48s
CI / wasm & android targets (pull_request) Has been skipped
6bf16d70e9
The flat tier's ground is a render of vector geometry, and Shortbread stops
at z14 while the clipmap anchors at z17 — so 179 of a fresh anchor's 424
tiles are magnified z14 renders. PDOK's Luchtfoto RGB serves those zooms
natively, in true colour, and it drops into the existing plumbing unchanged:
an XYZ `.jpeg` template that `format_osm_tile_url` substitutes and
`tile_source_kind` classifies as raster.

Off by default and reached from the client, the way `systems::height` reaches
the same host. There is deliberately no extractor and no mirror: the five
surveyed layers have pipelines because their sources are WFS/GML needing
reprojection and tessellation, while imagery is already tiled, already Web
Mercator, already CDN-cached and already CORS-open — and the Netherlands at
z20 is ~78 million tiles, ~1.5 TB, on a VPS that also hosts nominatim and
overpass.

Four things are load-bearing.

Coverage is an envelope, never a status code. PDOK answers a tile outside the
country with `200` and a ~1.6 kB blank JPEG, so a status check papers the
planet in grey — and its own `WGS84BoundingBox` describes the tile matrix
set, which reaches into France, so that is the same mistake with a longer
route to it. The envelope is AHN's, measured from its GetCapabilities and
already trusted here for "is this the Netherlands".

Two raster sources at one cache key collide, and that had to be fixed before
a second one existed. `tile_cache_key` wrote `tiles/{z}/{x}/{y}.png` for
anything raster and `CacheKey` was `(TileKey, TileSourceKind)`, so the drawn
map and the photograph would have shared an entry in memory and on disk, with
whichever landed first served to the other. `tile_source::SourceId` is a
stable FNV-1a slug of the template, derived inside `tile_bytes` so no call
site changes and none can forget to say which source it meant. It orphans the
old `tiles/{z}/…` paths once; `utils::cache::sweep` reclaims them.

A source flip retears on a new `MapStream::fetch_generation`, not on
`anchor_generation`. Sixteen systems answer an anchor bump by rebuilding —
every building cell, the terrain field, the interiors, the dikes, a fresh
weather fetch — and one checkbox over the ground texture must not cost the
mass mesh churn the device-loss guards exist for. The teardown is otherwise
the re-anchor's, through the same bounded despawn queue and the same
per-frame upload ceiling.

The default layer is `Actueel_ortho25` rather than the 8 cm `orthoHR`, on two
grounds that are recorded so they are not re-litigated: 25 cm is already
finer than a z17 clipmap tile can show, and ortho25 is the summer flight,
which matches the foliage drawn over it. `CARTO_AERIAL_LAYER` overrides it.

Only `map_stream` changes source. `map_geometry`, `globe`, `navigation` and
the router keep reading `OsmTileUrlTemplate` — they want MVT geometry, not
pixels — so routing, street labels, water shading and both building streamers
behave identically with the toggle either way.

`--aerial` opts a scripted run in and `ShotMetrics::aerial_tiles` counts the
standing tiles that came from PDOK, which is the assertable half: colour is
not evidence on a software rasteriser.

Refs #175
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jeroen/cartopolis!179
No description provided.