3D basisvoorziening: is it worth wiring in? #199
Labels
No labels
agent
agent:ci
agent:done
agent:failed
agent:needs-input
agent:refined
agent:refining
agent:running
agent:shipped
agent:skip
autonomous
autopilot
driven
local
plan
proposal
qa
qa-gap
research
retro
ship
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
jeroen/cartopolis#199
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
docs/direction.mdcarries one row in Candidates, unverified: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:gebouwen.glbleavesterreinenbasisbestand_gebouwenbasisbestand_gebouwen_terreinenhoogtestatistieken_gebouwendigitaalterreinmodeldigitaaloppervlaktemodel_20cm/_8cmThe five
/itemsendpoints are a sheet index, not a feature service: each item is a polygon withdownload_linkanddownload_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 tocreativecommons.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,665Building+ 14,660BuildingPart, 539,829 vertices. Geometry per building:Semantic surfaces are
WallSurface,RoofSurface,GroundSurfaceand 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 areidentificatie: NL.IMBAG.Pand.…,oorspronkelijkBouwjaar, and a block ofrf_*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:1is "3DBAG LoD2.2 real building meshes";docs/guides/server.md:485routeslod22/from "3DBAG CityJSON LoD2.2";docs/adr/027-3dbag-buildings.md:46describes exactly the parse — LoD2.2Solid, dropGroundSurface, 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). Takingbasisbestand_gebouwenwould 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-statewould 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:LandUse21,341,Road6,390,PlantCover4,477,OtherConstruction341,WaterBody53,Bridge45, every one at LoD 1.2, the source tables beingWegdeel_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 onheight.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 thePlantCoverSolids 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 onbagpandid. 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).One pointer worth keeping rather than losing: the combined file carries
Overbruggingsdeel_vlakbridge decks with AHN-draped z (45 in the Groningen block; one viaduct runs 0.96 → 6.62 m), anddocs/direction.mdsays 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.mdalready 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.
docs/notes/3d-basisvoorziening.md(new) — the standing record, so the check is not repeated. Front-matter perdocs/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; therf_*/identificatieevidence 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 exactcurl/ Python used. Aim under ~120 lines — the README calls ~100 a smell, and only the measurement appendix earns more.docs/direction.md— remove the3D basisvoorzieningrow from Candidates, unverified; add a2026-08-30row to Checked and not taken, in the same shape as the five rows already there, linking the note.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.)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. Bumpupdated:.docs/notes/bridge-heights.md— one pointer: the 3D basisvoorziening's combined file carriesOverbruggingsdeel_vlakdecks 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. Bumpupdated:.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. NoCo-Authored-By.Acceptance criteria
docs/notes/3d-basisvoorziening.mdexists withtopic:/triggers:/updated: 2026-08-30front-matter.rel: "license"link, and says explicitly that the licence was not the obstacle.WallSurface/RoofSurface/GroundSurfaceonly) and states that no national LoD3 exists.rf_*roofer attributes andidentificatie: NL.IMBAG.Pand.…— and citescrates/cartopolis/src/systems/map/lod22.rs:1anddocs/guides/server.md:485as what already streams it.buildings_2025_232000_582000.zip15,737,752 B → 98,070,614 B, 14,665 buildings, 539,829 vertices;volledig_2025_232000_582000.zip14,100,639 B → 77,715,868 B, 32,647 objects, no buildings;volledig_2022_…44,824,991 B, buildings present. One 3D Tiles.glbleaf sampled at 1,124,404 B.path:linecitation where one exists.Overbruggingsdeel_vlakdecks with z against the open BGT bridge-decks ticket, and the 2025 combined file no longer carrying buildings despite its own description.curland Python that produced each figure.docs/direction.mdno longer lists3D basisvoorzieningunder Candidates, unverified.docs/direction.mdhas a Checked and not taken row dated2026-08-30naming the LoD 2.2 ceiling, the duplication with the wired 3DBAG lane, CC BY 4.0 as not-the-obstacle, and linkingnotes/3d-basisvoorziening.md.docs/notes/importing-a-building-model.mdcarries a pointer to the new note and a bumpedupdated:.docs/notes/bridge-heights.mdcarries the deck pointer and a bumpedupdated:.docs/. No.rs, noCargo.toml, noPROTOCOL_HISTORY.Refs #199. No attribution trailer.Verification
Documentation only — nothing compiles, so there is nothing to build and no
cargocommand applies.cargo fmt --checkis only needed if the diff grows a.rsfile, which would mean the scope was exceeded.Re-running the check itself (all read-only, all reproducible from this container):
Note the download endpoint answers 302 —
curlneeds-Lor you get a 5-byte body that reads as an empty dataset.Nothing here needs a workstation, a GPU,
--shotorcargo shots: there is no visible change to photograph, which is itself part of the reason the answer is no.Out of scope
crates/, to cartopy'sserver/pipeline/, or to what3dbag.cartopolis.orgserves.rf_pc_source: "AHN6",rf_pc_year: 2025); which release the servedlod22/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.TERRAIN_GRIDor movingheight.rsto a newer AHN coverage.overbruggingsdeel/tunneldeelticket. This pass only adds a pointer to it.docs/direction.mdother 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-takenOriginal 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:
Not worth it is a valid answer. Record it in
docs/direction.mdagainst this rowwith 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.mdexist 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 whatis 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.
🤖 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.
🤖 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:skipstops me.🤖 viberfox issue agent on the VPS — 43 turns · $4.09 · session
ad2634e2-d3b8-43b5-80dd-65a922249b93. Reply with @agent to continue this session.🤖 Picked this up — working on branch
docs/199-3d-basisvoorziening-not-takenin a fresh worktree on the VPS. I'll report back here when I'm done.Label an issue
agent:skipto keep me off it, ordrivento keep it in a session you are driving.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 carriesOverbruggingsdeel_vlakdecks 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 ofWallSurface/RoofSurface/GroundSurfaceand nothing else — no openings. The attributes areNL.IMBAG.Pand.…plus 33rf_*fields (rf_pc_source: "AHN6",rf_rmse_lod22,rf_ridgelines), which is the roofer pipeline: this is 3DBAG, the datasetlod22.rsalready streams. Value 4 ("add, don't replace"), with value 6 agreeing that no--dump-statecount 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
Building/BuildingPartobjects, but the 14,867Pand_vlakrecords are there — as flat LoD 1.2LandUsepatches with an emptyidentificatiebag. The distinction matters to anyone who fetches it expecting building volumes.LandUseinternal relief p90 0.52 m (not 0.72),PlantCoversolid 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
.glbleaves requireEXT_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
cargocommand applies.git diff --cached --name-onlyis four paths, all underdocs/. The candidates section renders as prose rather than a bare header. The one markdown link in the new note (bridge-heights.md) resolves; thepath:linecitations were each checked against the current tree withgrep -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-takenis 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)🤖 viberfox issue agent on the VPS — 48 turns · $4.08 · session
4b606394-698d-4283-9839-19784d9d4c9c. Reply with @agent to continue this session.🤖 Marked
agent:donewithout a CI verdict onab48fd45— no workflow reported on this commit. The branch is waiting for review; check the run yourself before landing it.🤖 Merged into
mainas pull request #200 (ab48fd45).🤖 Merged, but not deployed. The deploy step exited 1:
mainhas the change; the public services are still on the previous build.agent:donenever means "CI agreed" #220docs/qa/targets.md— 14 of 14 passes re-verified a shipped ticket, 9 of them documentation-only verdicts #280