3D basisvoorziening: is it worth wiring in? #199

Closed
opened 2026-08-30 01:39:49 +00:00 by viberfox-agent · 7 comments
Collaborator

Problem

docs/direction.md carries one row in Candidates, unverified:

Source What it would add
3D basisvoorziening national LoD3, in place of one hand-imported model

The first half of this ticket is the check, and the check is done. It was run read-only from the agent container on 2026-08-30 against the live PDOK service. The answer is no, and the row's description is wrong — the same way the NWB and Kadaster-parcels rows were wrong before they were retired.

What the source actually is

One keyless OGC API, https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1, eight collections:

Collection What it is Access shape
gebouwen buildings, "LoD 2.2, LoD 1.3 where AHN is missing" (its own description) OGC 3D Tiles, .glb leaves
terreinen BGT ground surfaces draped on AHN OGC 3D Tiles
basisbestand_gebouwen the same buildings as CityJSON sheet index + zip download
basisbestand_gebouwen_terreinen buildings + terrain + water + roads, CityJSON sheet index + zip download
hoogtestatistieken_gebouwen 2D footprints with height attributes sheet index + zip download
digitaalterreinmodel AHN6 DTM, Quantized Mesh for Cesium tileset
digitaaloppervlaktemodel_20cm / _8cm DSM point clouds, LASZip sheet index + zip download

The five /items endpoints are a sheet index, not a feature service: each item is a polygon with download_link and download_size_bytes. There is no per-building and no per-bbox feature query. Since 2021 the sheets are 2 km RD blocks (232000_582000); before that they were 1:25,000 map sheets. The 3D Tiles bulk download is by request only (~73 GB, delivered into an Azure container you provide an SAS token for).

Licence: CC BY 4.0, stated by the API's own landing page as a rel: "license" link to creativecommons.org/licenses/by/4.0/deed.nl. Redistributing a cached extract is allowed. It is the same licence the client already carries for 3DBAG (crates/cartopolis/src/resources.rs:100), so the licence was never the obstacle.

The finding that settles it: this is 3DBAG, and its ceiling is LoD 2.2

Downloaded buildings_2025_232000_582000.zip (15,737,752 B → 98,070,614 B of CityJSON 2.0) and parsed it. 14,665 Building + 14,660 BuildingPart, 539,829 vertices. Geometry per building:

('Building',     'MultiSurface', lod '0'  ) × 14665     ← footprint
('BuildingPart', 'Solid',        lod '1.2') × 14660
('BuildingPart', 'Solid',        lod '1.3') × 14660
('BuildingPart', 'Solid',        lod '2.2') × 14660

Semantic surfaces are WallSurface, RoofSurface, GroundSurface and nothing else — 87,960 / 77,161 / 43,980. No openings, no windows, no doors, no facade detail. There is no LoD3 in this dataset. The attributes are identificatie: NL.IMBAG.Pand.…, oorspronkelijkBouwjaar, and a block of rf_* fields (rf_pc_source: "AHN6", rf_pc_year: 2025, rf_h_roof_ridge, rf_rmse_lod12, rf_ridgelines) — these are roofer reconstruction attributes, i.e. the TU Delft 3DBAG pipeline. TU Delft's own project page says the stable 3D BAG is forwarded to the Kadaster's 3D basisvoorziening.

So the collection is the product this client already streams. crates/cartopolis/src/systems/map/lod22.rs:1 is "3DBAG LoD2.2 real building meshes"; docs/guides/server.md:485 routes lod22/ from "3DBAG CityJSON LoD2.2"; docs/adr/027-3dbag-buildings.md:46 describes exactly the parse — LoD2.2 Solid, drop GroundSurface, triangulate Wall/Roof. The cell format already carries the roof/wall split (lod22.rs:7) and the BAG identificatie is already the join key (crates/cartopolis/src/systems/map/building_facts.rs:11). Taking basisbestand_gebouwen would be substituting one delivery of one dataset for another delivery of the same dataset — value 4, "add, don't replace" — and value 6 agrees: no count in --dump-state would move.

And there is no LoD3 to be had elsewhere either. A national Dutch LoD3 does not exist; enriching LoD2 with facade openings from oblique imagery is current research, not a published register. crates/cartopolis/src/systems/map/lod3.rs:1 — the tier that streams one hand-imported IFC model — has nothing to be replaced by.

The other collections, each against what is already wired

  • basisbestand_gebouwen_terreinen — downloaded the 2025 Groningen block (14,100,639 B → 77,715,868 B, 32,647 objects, 656,457 vertices). It is the BGT draped on AHN: LandUse 21,341, Road 6,390, PlantCover 4,477, OtherConstruction 341, WaterBody 53, Bridge 45, every one at LoD 1.2, the source tables being Wegdeel_vlak, OnbegroeidTerreindeel_vlak, BegroeidTerreindeel_vlak, Waterdeel_vlak, Kunstwerkdeel_vlak, Overbruggingsdeel_vlak. The client already streams those BGT polygons (crates/geo/src/paving.rs, crates/cartopolis/src/systems/map/surveyed.rs) and already lifts them on a measured AHN field. The z here is the same AHN, sampled at BGT vertices instead of on the client's 25 m grid (crates/cartopolis/src/systems/map/terrain.rs:63, :69, :76) — median internal relief per LandUse polygon 0.15 m, p90 0.72 m. That is a resolution knob on height.rs, not a new source. Worth recording, because two things are surprising: the 2025 block contains no buildings at all despite the collection description promising them (the 2022 block, 44,824,991 B, does), and the PlantCover Solids are near-flat — 720 of 4,477, median height 0.17 m, p90 0.36 m — so they are not canopy volumes.
  • hoogtestatistieken_gebouwen — footprints plus height statistics, joinable on bagpandid. The client has the geometry itself and the register facts beside it (building_facts.rs).
  • digitaalterreinmodel — AHN6 DTM as Quantized Mesh. The client reads AHN directly from the WCS (crates/cartopolis/src/systems/map/height.rs:113, :114 — dtm_05m / dsm_05m).
  • DSM 8 cm / 20 cm — raw LASZip point clouds. No consumer in this tree.

One pointer worth keeping rather than losing: the combined file carries Overbruggingsdeel_vlak bridge decks with AHN-draped z (45 in the Groningen block; one viaduct runs 0.96 → 6.62 m), and docs/direction.md says the separate BGT bridge-decks ticket is blocked on "a deck height the register does not carry". It is not a reason to take this source — docs/notes/bridge-heights.md already measures the same clearance from AHN's own DSM/DTM pair, and the constraint there was never the height but the flat approach roads.

Approach

Documentation only. No crate is touched.

  1. docs/notes/3d-basisvoorziening.md (new) — the standing record, so the check is not repeated. Front-matter per docs/notes/README.md (topic:, triggers:, updated: 2026-08-30). It carries: the endpoint and the eight collections; the two access shapes and the absence of a feature query; CC BY 4.0 with the API's own licence link; the measured volumes; the LoD ceiling of 2.2 with the geometry tally that proves it; the rf_* / identificatie evidence that it is 3DBAG; the per-collection comparison against what is wired; the two pointers above; and a closing "how every number was measured" block of the exact curl / Python used. Aim under ~120 lines — the README calls ~100 a smell, and only the measurement appendix earns more.
  2. docs/direction.md — remove the 3D basisvoorziening row from Candidates, unverified; add a 2026-08-30 row to Checked and not taken, in the same shape as the five rows already there, linking the note.
  3. docs/direction.md, the now-empty candidates table — that row was the last one. Keep the **Candidates, unverified.** heading and its paragraph and replace the bare table with one sentence saying the queue is currently empty. Do not delete the section: it defines what the section is for, and the autopilot and every unattended session read it to decide what may be pulled. (Stated here so the implementer does not have to guess; value 7.)
  4. docs/notes/importing-a-building-model.md — one pointer under What is not done: there is no national LoD3 to replace the hand-imported model with, link the new note. Bump updated:.
  5. docs/notes/bridge-heights.md — one pointer: the 3D basisvoorziening's combined file carries Overbruggingsdeel_vlak decks with AHN-draped z, and the client already measures the same number from AHN itself, so it is not a reason to take the source. Bump updated:.
  6. Commit — docs(direction): 3D basisvoorziening checked and not taken, Conventional Commits, body naming value 4 as the one applied with value 6 agreeing and the row's false premise stated plainly, Refs #199. No Co-Authored-By.

Acceptance criteria

  • docs/notes/3d-basisvoorziening.md exists with topic: / triggers: / updated: 2026-08-30 front-matter.
  • The note states the licence as CC BY 4.0 and cites the API's own rel: "license" link, and says explicitly that the licence was not the obstacle.
  • The note records the LoD ceiling as 2.2 with the per-building geometry tally (LoD 0 MultiSurface + LoD 1.2 / 1.3 / 2.2 Solids; semantics WallSurface / RoofSurface / GroundSurface only) and states that no national LoD3 exists.
  • The note records the evidence that the collection is 3DBAG — the rf_* roofer attributes and identificatie: NL.IMBAG.Pand.… — and cites crates/cartopolis/src/systems/map/lod22.rs:1 and docs/guides/server.md:485 as what already streams it.
  • The note records the measured volumes: buildings_2025_232000_582000.zip 15,737,752 B → 98,070,614 B, 14,665 buildings, 539,829 vertices; volledig_2025_232000_582000.zip 14,100,639 B → 77,715,868 B, 32,647 objects, no buildings; volledig_2022_… 44,824,991 B, buildings present. One 3D Tiles .glb leaf sampled at 1,124,404 B.
  • The note walks all eight collections and, for each, names what in this tree already covers it, with a path:line citation where one exists.
  • The note carries the two pointers: the Overbruggingsdeel_vlak decks with z against the open BGT bridge-decks ticket, and the 2025 combined file no longer carrying buildings despite its own description.
  • The note ends with a reproducible "how every number was measured" block — the exact curl and Python that produced each figure.
  • docs/direction.md no longer lists 3D basisvoorziening under Candidates, unverified.
  • docs/direction.md has a Checked and not taken row dated 2026-08-30 naming the LoD 2.2 ceiling, the duplication with the wired 3DBAG lane, CC BY 4.0 as not-the-obstacle, and linking notes/3d-basisvoorziening.md.
  • The Candidates, unverified heading and its explanatory paragraph survive, with a sentence in place of the empty table saying the queue is empty.
  • docs/notes/importing-a-building-model.md carries a pointer to the new note and a bumped updated:.
  • docs/notes/bridge-heights.md carries the deck pointer and a bumped updated:.
  • The diff touches only docs/. No .rs, no Cargo.toml, no PROTOCOL_HISTORY.
  • The commit body names value 4 (with value 6 agreeing) and says why, and ends Refs #199. No attribution trailer.

Verification

Documentation only — nothing compiles, so there is nothing to build and no cargo command applies. cargo fmt --check is only needed if the diff grows a .rs file, which would mean the scope was exceeded.

# the row moved, and the candidates table is not left as a bare header
grep -n "3D basisvoorziening" docs/direction.md
sed -n '/Candidates, unverified/,/Checked and not taken/p' docs/direction.md

# only docs changed
git diff --name-only main... | grep -v '^docs/' && echo "SCOPE EXCEEDED"

# every markdown link in the new note resolves
grep -o '](\./\?[a-z0-9./-]*\.md)' docs/notes/3d-basisvoorziening.md

Re-running the check itself (all read-only, all reproducible from this container):

# the eight collections, and the licence link on the landing page
curl -s 'https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1/collections?f=json' | python3 -m json.tool
curl -s 'https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1?f=json' | python3 -m json.tool | grep -A3 '"license"'

# the sheet index for Groningen: download links and sizes, not features
curl -s 'https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1/collections/basisbestand_gebouwen/items?f=json&limit=200&bbox=6.55,53.21,6.58,53.23'

# the block itself: LoD ceiling, semantics, attributes
curl -sL -o /tmp/geb.zip 'https://download.pdok.nl/kadaster/basisvoorziening-3d/v1_0/2025/gebouwen/buildings_2025_232000_582000.zip'
# then: unzip in memory, json.loads, Counter over (type, geometry.type, geometry.lod)

Note the download endpoint answers 302 — curl needs -L or you get a 5-byte body that reads as an empty dataset.

Nothing here needs a workstation, a GPU, --shot or cargo shots: there is no visible change to photograph, which is itself part of the reason the answer is no.

Out of scope

  • Any change to crates/, to cartopy's server/pipeline/, or to what 3dbag.cartopolis.org serves.
  • Refreshing the existing 3DBAG lane to a newer vintage. PDOK's 2025 buildings are reconstructed from AHN6 (rf_pc_source: "AHN6", rf_pc_year: 2025); which release the served lod22/ tree was built from cannot be determined from this repository — the extractor is in cartopy and the output is on the VPS. That is a maintenance question about a wired layer, and it is a separate ticket if anyone wants it.
  • Raising TERRAIN_GRID or moving height.rs to a newer AHN coverage.
  • The separate BGT overbruggingsdeel / tunneldeel ticket. This pass only adds a pointer to it.
  • Writing a 3D Tiles or Quantized Mesh loader.
  • Rewriting any part of docs/direction.md other than the two table edits and the one sentence replacing the emptied table. A session may propose changes to that file as a ticket; it may not rewrite it.

Open questions

None. Everything the decision needed — interface, licence, volume, and whether it changes the picture — was answerable read-only against the live service, and it was.


Branch: docs/199-3d-basisvoorziening-not-taken

Original request

From the frontier in docs/direction.md: 3D basisvoorziening — national LoD3, in place of one hand-imported model.

The first half of this ticket is deciding whether it is worth doing at all:

  • Is there an interface a client or an extractor can use, and what does it cost per cell?
  • Does the licence allow redistributing what we would cache?
  • Does it change the picture, or only the data behind it?

Not worth it is a valid answer. Record it in docs/direction.md against this row
with the reason, and close this ticket — that is the result, not a failure.

Decide it yourself. This ticket is not being watched, so a question asked
here is a ticket that stops. The seven values at the top of docs/direction.md
exist to settle exactly this kind of ambiguity — pick the reading they support,
say in the commit body which one you applied and why, and build. Only a decision
that would need something nobody can derive from the repository — a credential, a
licence somebody must agree to, a choice about what the project is for — is a
reason to stop.

If it is worth doing, follow the shape the surveyed layers already use:
an extractor under tools/, a coverage manifest, a streamer that adds to what
is drawn rather than replacing it, and no unbounded per-frame upload.

Filed by the autopilot.

🤖 Refined by the viberfox issue agent. Reply with @agent refine and what is wrong to have this rewritten.

## Problem `docs/direction.md` carries one row in **Candidates, unverified**: | Source | What it would add | |---|---| | 3D basisvoorziening | national LoD3, in place of one hand-imported model | The first half of this ticket is the check, and the check is done. It was run read-only from the agent container on 2026-08-30 against the live PDOK service. **The answer is no, and the row's description is wrong** — the same way the NWB and Kadaster-parcels rows were wrong before they were retired. ### What the source actually is One keyless OGC API, `https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1`, eight collections: | Collection | What it is | Access shape | |---|---|---| | `gebouwen` | buildings, "LoD 2.2, LoD 1.3 where AHN is missing" (its own description) | OGC 3D Tiles, `.glb` leaves | | `terreinen` | BGT ground surfaces draped on AHN | OGC 3D Tiles | | `basisbestand_gebouwen` | the same buildings as CityJSON | sheet index + zip download | | `basisbestand_gebouwen_terreinen` | buildings + terrain + water + roads, CityJSON | sheet index + zip download | | `hoogtestatistieken_gebouwen` | 2D footprints with height attributes | sheet index + zip download | | `digitaalterreinmodel` | AHN6 DTM, Quantized Mesh for Cesium | tileset | | `digitaaloppervlaktemodel_20cm` / `_8cm` | DSM point clouds, LASZip | sheet index + zip download | The five `/items` endpoints are a **sheet index, not a feature service**: each item is a polygon with `download_link` and `download_size_bytes`. There is no per-building and no per-bbox feature query. Since 2021 the sheets are 2 km RD blocks (`232000_582000`); before that they were 1:25,000 map sheets. The 3D Tiles bulk download is by request only (~73 GB, delivered into an Azure container you provide an SAS token for). **Licence: CC BY 4.0**, stated by the API's own landing page as a `rel: "license"` link to `creativecommons.org/licenses/by/4.0/deed.nl`. Redistributing a cached extract is allowed. It is the same licence the client already carries for 3DBAG (`crates/cartopolis/src/resources.rs:100`), so the licence was never the obstacle. ### The finding that settles it: this is 3DBAG, and its ceiling is LoD 2.2 Downloaded `buildings_2025_232000_582000.zip` (15,737,752 B → 98,070,614 B of CityJSON 2.0) and parsed it. 14,665 `Building` + 14,660 `BuildingPart`, 539,829 vertices. Geometry per building: ``` ('Building', 'MultiSurface', lod '0' ) × 14665 ← footprint ('BuildingPart', 'Solid', lod '1.2') × 14660 ('BuildingPart', 'Solid', lod '1.3') × 14660 ('BuildingPart', 'Solid', lod '2.2') × 14660 ``` Semantic surfaces are `WallSurface`, `RoofSurface`, `GroundSurface` and nothing else — 87,960 / 77,161 / 43,980. **No openings, no windows, no doors, no facade detail. There is no LoD3 in this dataset.** The attributes are `identificatie: NL.IMBAG.Pand.…`, `oorspronkelijkBouwjaar`, and a block of `rf_*` fields (`rf_pc_source: "AHN6"`, `rf_pc_year: 2025`, `rf_h_roof_ridge`, `rf_rmse_lod12`, `rf_ridgelines`) — these are **roofer** reconstruction attributes, i.e. the TU Delft 3DBAG pipeline. TU Delft's own project page says the stable 3D BAG is forwarded to the Kadaster's 3D basisvoorziening. So the collection is the product this client already streams. `crates/cartopolis/src/systems/map/lod22.rs:1` is "3DBAG **LoD2.2** real building meshes"; `docs/guides/server.md:485` routes `lod22/` from "3DBAG CityJSON LoD2.2"; `docs/adr/027-3dbag-buildings.md:46` describes exactly the parse — LoD2.2 `Solid`, drop `GroundSurface`, triangulate Wall/Roof. The cell format already carries the roof/wall split (`lod22.rs:7`) and the BAG identificatie is already the join key (`crates/cartopolis/src/systems/map/building_facts.rs:11`). Taking `basisbestand_gebouwen` would be substituting one delivery of one dataset for another delivery of the same dataset — **value 4, "add, don't replace"** — and **value 6** agrees: no count in `--dump-state` would move. And there is no LoD3 to be had elsewhere either. A national Dutch LoD3 does not exist; enriching LoD2 with facade openings from oblique imagery is current research, not a published register. `crates/cartopolis/src/systems/map/lod3.rs:1` — the tier that streams one hand-imported IFC model — has nothing to be replaced by. ### The other collections, each against what is already wired - **`basisbestand_gebouwen_terreinen`** — downloaded the 2025 Groningen block (14,100,639 B → 77,715,868 B, 32,647 objects, 656,457 vertices). It is the BGT draped on AHN: `LandUse` 21,341, `Road` 6,390, `PlantCover` 4,477, `OtherConstruction` 341, `WaterBody` 53, `Bridge` 45, every one at LoD 1.2, the source tables being `Wegdeel_vlak`, `OnbegroeidTerreindeel_vlak`, `BegroeidTerreindeel_vlak`, `Waterdeel_vlak`, `Kunstwerkdeel_vlak`, `Overbruggingsdeel_vlak`. The client already streams those BGT polygons (`crates/geo/src/paving.rs`, `crates/cartopolis/src/systems/map/surveyed.rs`) and already lifts them on a measured AHN field. The z here is the *same AHN*, sampled at BGT vertices instead of on the client's 25 m grid (`crates/cartopolis/src/systems/map/terrain.rs:63`, `:69`, `:76`) — median internal relief per LandUse polygon 0.15 m, p90 0.72 m. That is a resolution knob on `height.rs`, not a new source. Worth recording, because two things are surprising: the **2025 block contains no buildings at all** despite the collection description promising them (the 2022 block, 44,824,991 B, does), and the `PlantCover` Solids are near-flat — 720 of 4,477, median height 0.17 m, p90 0.36 m — so they are not canopy volumes. - **`hoogtestatistieken_gebouwen`** — footprints plus height statistics, joinable on `bagpandid`. The client has the geometry itself and the register facts beside it (`building_facts.rs`). - **`digitaalterreinmodel`** — AHN6 DTM as Quantized Mesh. The client reads AHN directly from the WCS (`crates/cartopolis/src/systems/map/height.rs:113`, `:114` — `dtm_05m` / `dsm_05m`). - **DSM 8 cm / 20 cm** — raw LASZip point clouds. No consumer in this tree. One pointer worth keeping rather than losing: the combined file carries `Overbruggingsdeel_vlak` **bridge decks with AHN-draped z** (45 in the Groningen block; one viaduct runs 0.96 → 6.62 m), and `docs/direction.md` says the separate BGT bridge-decks ticket is blocked on "a deck height the register does not carry". It is not a reason to take this source — `docs/notes/bridge-heights.md` already measures the same clearance from AHN's own DSM/DTM pair, and the constraint there was never the height but the flat approach roads. ## Approach Documentation only. No crate is touched. 1. **`docs/notes/3d-basisvoorziening.md`** (new) — the standing record, so the check is not repeated. Front-matter per `docs/notes/README.md` (`topic:`, `triggers:`, `updated: 2026-08-30`). It carries: the endpoint and the eight collections; the two access shapes and the absence of a feature query; CC BY 4.0 with the API's own licence link; the measured volumes; the LoD ceiling of 2.2 with the geometry tally that proves it; the `rf_*` / `identificatie` evidence that it is 3DBAG; the per-collection comparison against what is wired; the two pointers above; and a closing "how every number was measured" block of the exact `curl` / Python used. Aim under ~120 lines — the README calls ~100 a smell, and only the measurement appendix earns more. 2. **`docs/direction.md`** — remove the `3D basisvoorziening` row from **Candidates, unverified**; add a `2026-08-30` row to **Checked and not taken**, in the same shape as the five rows already there, linking the note. 3. **`docs/direction.md`, the now-empty candidates table** — that row was the last one. Keep the `**Candidates, unverified.**` heading and its paragraph and replace the bare table with one sentence saying the queue is currently empty. Do not delete the section: it defines what the section is for, and the autopilot and every unattended session read it to decide what may be pulled. (Stated here so the implementer does not have to guess; value 7.) 4. **`docs/notes/importing-a-building-model.md`** — one pointer under *What is not done*: there is no national LoD3 to replace the hand-imported model with, link the new note. Bump `updated:`. 5. **`docs/notes/bridge-heights.md`** — one pointer: the 3D basisvoorziening's combined file carries `Overbruggingsdeel_vlak` decks with AHN-draped z, and the client already measures the same number from AHN itself, so it is not a reason to take the source. Bump `updated:`. 6. **Commit** — `docs(direction): 3D basisvoorziening checked and not taken`, Conventional Commits, body naming **value 4** as the one applied with **value 6** agreeing and the row's false premise stated plainly, `Refs #199`. No `Co-Authored-By`. ## Acceptance criteria - [ ] `docs/notes/3d-basisvoorziening.md` exists with `topic:` / `triggers:` / `updated: 2026-08-30` front-matter. - [ ] The note states the licence as **CC BY 4.0** and cites the API's own `rel: "license"` link, and says explicitly that the licence was not the obstacle. - [ ] The note records the LoD ceiling as **2.2** with the per-building geometry tally (LoD 0 MultiSurface + LoD 1.2 / 1.3 / 2.2 Solids; semantics `WallSurface` / `RoofSurface` / `GroundSurface` only) and states that no national LoD3 exists. - [ ] The note records the evidence that the collection *is* 3DBAG — the `rf_*` roofer attributes and `identificatie: NL.IMBAG.Pand.…` — and cites `crates/cartopolis/src/systems/map/lod22.rs:1` and `docs/guides/server.md:485` as what already streams it. - [ ] The note records the measured volumes: `buildings_2025_232000_582000.zip` 15,737,752 B → 98,070,614 B, 14,665 buildings, 539,829 vertices; `volledig_2025_232000_582000.zip` 14,100,639 B → 77,715,868 B, 32,647 objects, no buildings; `volledig_2022_…` 44,824,991 B, buildings present. One 3D Tiles `.glb` leaf sampled at 1,124,404 B. - [ ] The note walks all eight collections and, for each, names what in this tree already covers it, with a `path:line` citation where one exists. - [ ] The note carries the two pointers: the `Overbruggingsdeel_vlak` decks with z against the open BGT bridge-decks ticket, and the 2025 combined file no longer carrying buildings despite its own description. - [ ] The note ends with a reproducible "how every number was measured" block — the exact `curl` and Python that produced each figure. - [ ] `docs/direction.md` no longer lists `3D basisvoorziening` under **Candidates, unverified**. - [ ] `docs/direction.md` has a **Checked and not taken** row dated `2026-08-30` naming the LoD 2.2 ceiling, the duplication with the wired 3DBAG lane, CC BY 4.0 as not-the-obstacle, and linking `notes/3d-basisvoorziening.md`. - [ ] The **Candidates, unverified** heading and its explanatory paragraph survive, with a sentence in place of the empty table saying the queue is empty. - [ ] `docs/notes/importing-a-building-model.md` carries a pointer to the new note and a bumped `updated:`. - [ ] `docs/notes/bridge-heights.md` carries the deck pointer and a bumped `updated:`. - [ ] The diff touches only `docs/`. No `.rs`, no `Cargo.toml`, no `PROTOCOL_HISTORY`. - [ ] The commit body names value 4 (with value 6 agreeing) and says why, and ends `Refs #199`. No attribution trailer. ## Verification Documentation only — nothing compiles, so there is nothing to build and no `cargo` command applies. `cargo fmt --check` is only needed if the diff grows a `.rs` file, which would mean the scope was exceeded. ```bash # the row moved, and the candidates table is not left as a bare header grep -n "3D basisvoorziening" docs/direction.md sed -n '/Candidates, unverified/,/Checked and not taken/p' docs/direction.md # only docs changed git diff --name-only main... | grep -v '^docs/' && echo "SCOPE EXCEEDED" # every markdown link in the new note resolves grep -o '](\./\?[a-z0-9./-]*\.md)' docs/notes/3d-basisvoorziening.md ``` Re-running the check itself (all read-only, all reproducible from this container): ```bash # the eight collections, and the licence link on the landing page curl -s 'https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1/collections?f=json' | python3 -m json.tool curl -s 'https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1?f=json' | python3 -m json.tool | grep -A3 '"license"' # the sheet index for Groningen: download links and sizes, not features curl -s 'https://api.pdok.nl/kadaster/3d-basisvoorziening/ogc/v1/collections/basisbestand_gebouwen/items?f=json&limit=200&bbox=6.55,53.21,6.58,53.23' # the block itself: LoD ceiling, semantics, attributes curl -sL -o /tmp/geb.zip 'https://download.pdok.nl/kadaster/basisvoorziening-3d/v1_0/2025/gebouwen/buildings_2025_232000_582000.zip' # then: unzip in memory, json.loads, Counter over (type, geometry.type, geometry.lod) ``` Note the download endpoint answers **302** — `curl` needs `-L` or you get a 5-byte body that reads as an empty dataset. Nothing here needs a workstation, a GPU, `--shot` or `cargo shots`: there is no visible change to photograph, which is itself part of the reason the answer is no. ## Out of scope - Any change to `crates/`, to cartopy's `server/pipeline/`, or to what `3dbag.cartopolis.org` serves. - Refreshing the existing 3DBAG lane to a newer vintage. PDOK's 2025 buildings are reconstructed from AHN6 (`rf_pc_source: "AHN6"`, `rf_pc_year: 2025`); which release the served `lod22/` tree was built from cannot be determined from this repository — the extractor is in cartopy and the output is on the VPS. That is a maintenance question about a wired layer, and it is a separate ticket if anyone wants it. - Raising `TERRAIN_GRID` or moving `height.rs` to a newer AHN coverage. - The separate BGT `overbruggingsdeel` / `tunneldeel` ticket. This pass only adds a pointer to it. - Writing a 3D Tiles or Quantized Mesh loader. - Rewriting any part of `docs/direction.md` other than the two table edits and the one sentence replacing the emptied table. A session may propose changes to that file as a ticket; it may not rewrite it. ## Open questions None. Everything the decision needed — interface, licence, volume, and whether it changes the picture — was answerable read-only against the live service, and it was. --- Branch: `docs/199-3d-basisvoorziening-not-taken` <details><summary>Original request</summary> From the frontier in [`docs/direction.md`](../src/branch/main/docs/direction.md): **3D basisvoorziening** — national LoD3, in place of one hand-imported model. The first half of this ticket is deciding whether it is worth doing at all: - Is there an interface a client or an extractor can use, and what does it cost per cell? - Does the licence allow redistributing what we would cache? - Does it change the picture, or only the data behind it? **Not worth it is a valid answer.** Record it in `docs/direction.md` against this row with the reason, and close this ticket — that is the result, not a failure. **Decide it yourself.** This ticket is not being watched, so a question asked here is a ticket that stops. The seven values at the top of `docs/direction.md` exist to settle exactly this kind of ambiguity — pick the reading they support, say in the commit body which one you applied and why, and build. Only a decision that would need something nobody can derive from the repository — a credential, a licence somebody must agree to, a choice about what the project is *for* — is a reason to stop. If it is worth doing, follow the shape the surveyed layers already use: an extractor under `tools/`, a coverage manifest, a streamer that adds to what is drawn rather than replacing it, and no unbounded per-frame upload. <sub>Filed by the autopilot. <!-- autopilot:3d-basisvoorziening --></sub> </details> <sub>🤖 Refined by the viberfox issue agent. Reply with **@agent refine** and what is wrong to have this rewritten.</sub>
Author
Collaborator

🤖 Refining this before anything gets built — reading the code, no branch, no commits. If it turns out I'd have to guess at the requirements I'll stop and ask instead.

🤖 Refining this before anything gets built — reading the code, no branch, no commits. If it turns out I'd have to guess at the requirements I'll stop and ask instead.
Author
Collaborator

🤖 Refined. The description above is now the spec; I'll pick it up for implementation on the next poll.

If the direction is wrong, say so now — @agent refine with a correction rewrites it, and agent:skip stops me.


🤖 viberfox issue agent on the VPS — 43 turns · $4.09 · session ad2634e2-d3b8-43b5-80dd-65a922249b93. Reply with @agent to continue this session.

🤖 **Refined.** The description above is now the spec; I'll pick it up for implementation on the next poll. If the direction is wrong, say so now — **@agent refine** with a correction rewrites it, and `agent:skip` stops me. --- <sub>🤖 viberfox issue agent on the VPS — 43 turns · $4.09 · session `ad2634e2-d3b8-43b5-80dd-65a922249b93`. Reply with **@agent** to continue this session.</sub>
Author
Collaborator

🤖 Picked this up — working on branch docs/199-3d-basisvoorziening-not-taken in a fresh worktree on the VPS. I'll report back here when I'm done.

Label an issue agent:skip to keep me off it, or driven to keep it in a session you are driving.

🤖 Picked this up — working on branch `docs/199-3d-basisvoorziening-not-taken` in a fresh worktree on the VPS. I'll report back here when I'm done. <sub>Label an issue `agent:skip` to keep me off it, or `driven` to keep it in a session you are driving.</sub>
Author
Collaborator

The answer is no, and I re-ran the whole check myself rather than trusting the ticket's figures.

What I did

Documentation only — four files under docs/, no crate touched.

  • docs/notes/3d-basisvoorziening.md (new, 170 lines) — the standing record.
  • docs/direction.md — row moved from Candidates, unverified to Checked and not taken. That was the last candidate, so the empty table is replaced by a sentence; the heading and its paragraph stay.
  • docs/notes/importing-a-building-model.md — a What is not done entry: there is nothing national to replace the hand-imported IFC model with.
  • docs/notes/bridge-heights.md — the combined file carries Overbruggingsdeel_vlak decks with an AHN-draped z, and that note already measures the same number from AHN itself.

Why not

The row said "national LoD3". There is no LoD3 in it. I downloaded buildings_2025_232000_582000.zip (15,737,752 B → 98,070,614 B) and every geometry in the file is LoD 0 footprint plus LoD 1.2 / 1.3 / 2.2 solids, with semantics of WallSurface / RoofSurface / GroundSurface and nothing else — no openings. The attributes are NL.IMBAG.Pand.… plus 33 rf_* fields (rf_pc_source: "AHN6", rf_rmse_lod22, rf_ridgelines), which is the roofer pipeline: this is 3DBAG, the dataset lod22.rs already streams. Value 4 ("add, don't replace"), with value 6 agreeing that no --dump-state count would move. CC BY 4.0 — the same licence the client already carries for 3DBAG, so the licence was never the obstacle. The other seven collections are AHN, the BGT and DSM point clouds, each already covered.

Two things the ticket got slightly wrong, which I corrected in the note

  • It said the 2025 combined block "contains no buildings at all". More precisely: no Building/BuildingPart objects, but the 14,867 Pand_vlak records are there — as flat LoD 1.2 LandUse patches with an empty identificatiebag. The distinction matters to anyone who fetches it expecting building volumes.
  • My measured p90s differ from the ticket's: LandUse internal relief p90 0.52 m (not 0.72), PlantCover solid height p90 0.41 m (not 0.36). Medians match. I wrote my own numbers, and the appendix shows exactly how they were computed.

I also added two facts the ticket didn't have: the AHN6 DTM national zip is 12,228,609,219 B, and the 3D Tiles .glb leaves require EXT_meshopt_compression + KHR_mesh_quantization, which bevy's glTF loader does not read — so that delivery shape would mean writing a loader to arrive at meshes we already have. I did not verify the ticket's "~73 GB bulk download via Azure SAS" claim, so it is not in the note.

Verification

Nothing compiles, so no cargo command applies. git diff --cached --name-only is four paths, all under docs/. The candidates section renders as prose rather than a bare header. The one markdown link in the new note (bridge-heights.md) resolves; the path:line citations were each checked against the current tree with grep -n. Every figure in the note was measured by me today against the live service, and the appendix reproduces each one.

Nothing here needs a visual check — there is no picture to photograph, which is part of why the answer is no.

Branch docs/199-3d-basisvoorziening-not-taken is pushed. Nothing for you to decide; the frontier queue is now empty, which may itself be worth a ticket.

Branch docs/199-3d-basisvoorziening-not-taken (pushed)

ab48fd4 docs(direction): 3D basisvoorziening checked and not taken

🤖 viberfox issue agent on the VPS — 48 turns · $4.08 · session 4b606394-698d-4283-9839-19784d9d4c9c. Reply with @agent to continue this session.

The answer is **no**, and I re-ran the whole check myself rather than trusting the ticket's figures. ## What I did Documentation only — four files under `docs/`, no crate touched. - **`docs/notes/3d-basisvoorziening.md`** (new, 170 lines) — the standing record. - **`docs/direction.md`** — row moved from *Candidates, unverified* to *Checked and not taken*. That was the last candidate, so the empty table is replaced by a sentence; the heading and its paragraph stay. - **`docs/notes/importing-a-building-model.md`** — a *What is not done* entry: there is nothing national to replace the hand-imported IFC model with. - **`docs/notes/bridge-heights.md`** — the combined file carries `Overbruggingsdeel_vlak` decks with an AHN-draped z, and that note already measures the same number from AHN itself. ## Why not The row said "national LoD3". There is no LoD3 in it. I downloaded `buildings_2025_232000_582000.zip` (15,737,752 B → 98,070,614 B) and every geometry in the file is LoD 0 footprint plus LoD 1.2 / 1.3 / **2.2** solids, with semantics of `WallSurface` / `RoofSurface` / `GroundSurface` and nothing else — no openings. The attributes are `NL.IMBAG.Pand.…` plus 33 `rf_*` fields (`rf_pc_source: "AHN6"`, `rf_rmse_lod22`, `rf_ridgelines`), which is the roofer pipeline: **this is 3DBAG**, the dataset `lod22.rs` already streams. Value 4 ("add, don't replace"), with value 6 agreeing that no `--dump-state` count would move. CC BY 4.0 — the same licence the client already carries for 3DBAG, so the licence was never the obstacle. The other seven collections are AHN, the BGT and DSM point clouds, each already covered. ## Two things the ticket got slightly wrong, which I corrected in the note - It said the 2025 combined block "contains no buildings at all". More precisely: no `Building`/`BuildingPart` objects, but the 14,867 `Pand_vlak` records **are** there — as flat LoD 1.2 `LandUse` patches with an empty `identificatiebag`. The distinction matters to anyone who fetches it expecting building volumes. - My measured p90s differ from the ticket's: `LandUse` internal relief p90 **0.52 m** (not 0.72), `PlantCover` solid height p90 **0.41 m** (not 0.36). Medians match. I wrote my own numbers, and the appendix shows exactly how they were computed. I also added two facts the ticket didn't have: the AHN6 DTM national zip is 12,228,609,219 B, and the 3D Tiles `.glb` leaves require `EXT_meshopt_compression` + `KHR_mesh_quantization`, which bevy's glTF loader does not read — so that delivery shape would mean writing a loader to arrive at meshes we already have. I did **not** verify the ticket's "~73 GB bulk download via Azure SAS" claim, so it is not in the note. ## Verification Nothing compiles, so no `cargo` command applies. `git diff --cached --name-only` is four paths, all under `docs/`. The candidates section renders as prose rather than a bare header. The one markdown link in the new note (`bridge-heights.md`) resolves; the `path:line` citations were each checked against the current tree with `grep -n`. Every figure in the note was measured by me today against the live service, and the appendix reproduces each one. Nothing here needs a visual check — there is no picture to photograph, which is part of why the answer is no. Branch `docs/199-3d-basisvoorziening-not-taken` is pushed. Nothing for you to decide; the frontier queue is now empty, which may itself be worth a ticket. **Branch** `docs/199-3d-basisvoorziening-not-taken` (pushed) ``` ab48fd4 docs(direction): 3D basisvoorziening checked and not taken ``` --- <sub>🤖 viberfox issue agent on the VPS — 48 turns · $4.08 · session `4b606394-698d-4283-9839-19784d9d4c9c`. Reply with **@agent** to continue this session.</sub>
Author
Collaborator

🤖 Marked agent:done without a CI verdict on ab48fd45 — no workflow reported on this commit. The branch is waiting for review; check the run yourself before landing it.

🤖 Marked `agent:done` **without a CI verdict** on `ab48fd45` — no workflow reported on this commit. The branch is waiting for review; check the run yourself before landing it.
viberfox-agent 2026-08-30 01:59:53 +00:00
Author
Collaborator

🤖 Merged into main as pull request #200 (ab48fd45).

🤖 **Merged into `main`** as pull request #200 (`ab48fd45`).
Author
Collaborator

🤖 Merged, but not deployed. The deploy step exited 1:

main is at 44b6251f
  waiting for CI on 44b6251f
refusing: no Actions job ran for 44b6251f — nothing has verified this commit

main has the change; the public services are still on the previous build.

🤖 **Merged, but not deployed.** The deploy step exited 1: ``` main is at 44b6251f waiting for CI on 44b6251f refusing: no Actions job ran for 44b6251f — nothing has verified this commit ``` `main` has the change; the public services are still on the previous build.
Sign in to join this conversation.
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#199
No description provided.