The sea stays level at a dike #195

Open
viberfox-agent wants to merge 1 commit from worktree-bridge-cse_01J8JH1ZQTxFXDzY8Ui7fxsU into main
Collaborator

Reported from a phone at the Eemshaven sea dike (Ranselgatweg): a flat dark polygon standing in the sea with a hard edge against the waves.

Two mechanisms, both measured against the real AHN patch:

  1. The bake invented a shelf over the sea. AHN has no data over water, and the hole-filling dilated the quay/dike heights (+4.5..7 m NAP) ~150 m out over the water, then cliffed to zero — 2.5 km² of invented ground standing metres above the drawn sea. A no-data region touching the grid edge is now the survey ending, not a hole: it lies flat at the lowest measured ground beside it (the waterline), capped at the datum. Enclosed holes (bridges) keep the old fill.

  2. Sea cells disagreed about their level. Water was levelled per cell at the median of its own vertices, and a sea polygon's vertices are whatever shoreline the tile clipped in — so neighbouring sea cells stepped by metres. The ocean MVT layer is now its own SurfaceGroup::Ocean (same material/rung/colour as Water, pinned by tests) levelled at exactly 0 — the one level every cell derives identically, and where the sea meets the flat world at the field's edge. Inland water keeps the per-cell median.

Verified with headless captures over the Borkumkade dike: the sea is one continuous surface against the dike and the quays. 778 client tests + 196 geo tests pass.

Reported from a phone at the Eemshaven sea dike (Ranselgatweg): a flat dark polygon standing in the sea with a hard edge against the waves. Two mechanisms, both measured against the real AHN patch: 1. **The bake invented a shelf over the sea.** AHN has no data over water, and the hole-filling dilated the quay/dike heights (+4.5..7 m NAP) ~150 m out over the water, then cliffed to zero — 2.5 km² of invented ground standing metres above the drawn sea. A no-data region touching the grid edge is now the survey *ending*, not a hole: it lies flat at the lowest measured ground beside it (the waterline), capped at the datum. Enclosed holes (bridges) keep the old fill. 2. **Sea cells disagreed about their level.** Water was levelled per cell at the median of its own vertices, and a sea polygon's vertices are whatever shoreline the tile clipped in — so neighbouring sea cells stepped by metres. The `ocean` MVT layer is now its own `SurfaceGroup::Ocean` (same material/rung/colour as `Water`, pinned by tests) levelled at exactly 0 — the one level every cell derives identically, and where the sea meets the flat world at the field's edge. Inland water keeps the per-cell median. Verified with headless captures over the Borkumkade dike: the sea is one continuous surface against the dike and the quays. 778 client tests + 196 geo tests pass.
fix(map): keep the sea level at a dike instead of stepping and shelving
All checks were successful
CI / test cartopolis (pull_request) Successful in 13m33s
CI / wasm & android targets (pull_request) Has been skipped
ce3bf541e0
Reported from a phone at the Eemshaven sea dike (Ranselgatweg): a flat
dark polygon standing in the sea with a hard diagonal edge against the
waves, and the shore a mess of misplaced surfaces. Two mechanisms, both
measured against the real AHN patch (2026-08-29):

1. AHN's DTM has no data over water, and the bake's neighbour-dilation
   fill treated the open sea as a hole: it extended the quay/dike-top
   heights (+4.5..7 m NAP there) ~150 m out over the water, then cliffed
   to zero where the six passes ran out — 2.5 km² of invented ground in
   one 6.4 km box, standing metres above the sea drawn over it. The
   raised basemap, painted sea-blue, is the flat band in the screenshot.
   A no-data region touching the grid's edge is now the survey *ending*,
   not a hole (flatten_open_regions): it lies flat at the lowest
   measured ground beside it — at a coast, the waterline — and never
   above the datum, so an invented sea bed cannot poke through the water
   even from a polder anchor below sea level. Enclosed holes (bridges,
   buildings) keep the old fill.

2. Sea water was levelled per cell at the median height over its own
   vertices, and a sea polygon's vertices are whatever shoreline the
   tile clipped in — a quay in one cell, bare tile edge in the next —
   so neighbouring sea cells disagreed by metres: a wall of water off
   the coast. No per-cell statistic can fix that (a min still tracks
   whichever bank the cell holds), so the ocean layer is now its own
   SurfaceGroup::Ocean — same material, rung and colour as Water, pinned
   in the tests — and is not displaced at all. Zero is the one level
   every cell derives identically, it is what unmeasured sea in the
   field reads as, and it is where the sea meets the flat world at the
   field's edge. Inland water keeps the per-cell median: switching it to
   a per-body minimum was considered and rejected, because the invented
   bed under a canal averages its banks and a min-levelled surface would
   sit below that bed, showing flat basemap through the waves on every
   canal with uneven banks.

The Eemshaven tile puts the sea in the ocean layer (30% of the tile;
water_polygons there is 0.9%, small port basins), so the split targets
the right geometry. Verified with headless captures over the Borkumkade
dike: the sea is one continuous surface against the dike and the quays,
settled, terrain_ready, relief 33 m.
All checks were successful
CI / test cartopolis (pull_request) Successful in 13m33s
CI / wasm & android targets (pull_request) Has been skipped
This pull request has changes conflicting with the target branch.
  • crates/cartopolis/src/systems/map/map_geometry.rs
  • crates/cartopolis/src/systems/map/road_depth.rs
  • crates/cartopolis/src/systems/map/terrain.rs
  • crates/geo/src/vector_tiles.rs
  • docs/notes/terrain-relief.md
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin worktree-bridge-cse_01J8JH1ZQTxFXDzY8Ui7fxsU:worktree-bridge-cse_01J8JH1ZQTxFXDzY8Ui7fxsU
git switch worktree-bridge-cse_01J8JH1ZQTxFXDzY8Ui7fxsU

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff worktree-bridge-cse_01J8JH1ZQTxFXDzY8Ui7fxsU
git switch worktree-bridge-cse_01J8JH1ZQTxFXDzY8Ui7fxsU
git rebase main
git switch main
git merge --ff-only worktree-bridge-cse_01J8JH1ZQTxFXDzY8Ui7fxsU
git switch worktree-bridge-cse_01J8JH1ZQTxFXDzY8Ui7fxsU
git rebase main
git switch main
git merge --no-ff worktree-bridge-cse_01J8JH1ZQTxFXDzY8Ui7fxsU
git switch main
git merge --squash worktree-bridge-cse_01J8JH1ZQTxFXDzY8Ui7fxsU
git switch main
git merge --ff-only worktree-bridge-cse_01J8JH1ZQTxFXDzY8Ui7fxsU
git switch main
git merge worktree-bridge-cse_01J8JH1ZQTxFXDzY8Ui7fxsU
git push origin main
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!195
No description provided.