#103: Sweden airports + airport_points from Topo 10 Anläggningsområde #146

Closed
art wants to merge 0 commits from issue-103-se-airports into main
Owner

#103: Sweden airports + airport_points from Topo 10 Anläggningsområde

Closes #103

What changed

Sweden gets the airports and airport_points layers, mirroring Iceland's
implementation (R140), from Lantmäteriet Topo 10 tema Anläggningsområde — a
files: entry on the already-negotiated topo10 Geotorget order plus the layers, no
new approval.

Source (conf/semap.yaml): start_landningsbana (objekttypnr 2853) — 206 runway
polygons with flygplatsstatus (I drift / Nedlagd) — and flygplatsomrade (objekttypnr
2854) — 183 airport-area polygons with the codes. Both staged (EPSG:3006 → 3857) as
se_runway_t10 / se_flygplats_t10; the theme zip is 11.4 MB / 25.7 MB unzipped,
recorded on first fetch (R5). The layer is filter_only, z10–z13 like Iceland's, and
reads the runway polygons joined to their airport area.

Design decisions, each measured against the live data:

  • Nedlagd runways are dropped at import (190 of 206 kept), the same closed-track
    decision the railways layer made: a decommissioned runway should not render as an
    airport.
  • airport_class comes from the codes, not from flygplatsstatus. Iceland's ladder
    (Áætlunarvöllur vs Lendingarstaður) has no Swedish equivalent — flygplatsstatus
    only says I drift/Nedlagd (operational state, not traffic level). So class 1
    (scheduled) = iata present ("regular traffic only" per the source docs), class 2 =
    absent. 57 class-1 / 133 class-2 runways. The coarse-zoom airport_points filter
    (z9, airport_class = 1, like Iceland) keeps the 42 scheduled airports on z8–z9.
  • Names come from the Topo 10 text theme (already staged for places): the ANLTX
    "X flygplats" labels — 48 of the 183 areas carry one, all inside their area, one per
    area. Neither anläggningsomrade table has a name, only codes (ESSA / ARN), and a code
    is not a label. The join is the label inside the runway's own area, not a nearest
    label: the uncapped nearest-label join this replaced assigned a label up to 300 km
    away (measured live; the R120 acceptance test would catch it). Named airports get a
    label point; the other 135 areas keep their runway polygons and no label.

Serving: conf/semap.yaml regains a sources: block (se, airports +
airport_points — the first unshared Sweden layer since Phase 5), conf/mapsrv.yaml
serves /tiles/se, and html/style.json declares the se source with
airports_se + airport_labels_se layers copied from Iceland's, reading the name
column.

Verification (live DB)

Rows per zoom (all partitions populated, z3–z14 floor):

  • se_airports_*: 190 runways at every of z10–z13
  • se_airport_points_*: 42 (scheduled) at z8–z9, 48 (all labeled) at z10–z13

Acceptance — make acceptance-all tally (fast + 100s/1000s buckets, every config):

conf/ismap.yaml  31 test(s): 31 passed, 0 failed
conf/semap.yaml  36 test(s): 36 passed, 0 failed
conf/plmap.yaml  29 test(s): 29 passed, 0 failed
conf/fimap.yaml  34 test(s): 34 passed, 0 failed
conf/world.yaml  14 test(s): 14 passed, 0 failed

New tests (in the same commit, on the airports / airport_points layers):

layer airports (se)       / R119: no airports zoom table is empty (z10–z13) — PASS (tables=4)
layer airports (se)       / R120: no NULL airport_class; every name is the label inside its own area — PASS (class_nulls=0, name_nulls=136, mismatched=0)
layer airport_points (se) / R119: no airport_points zoom table is empty (z8–z13) — PASS (tables=6)
layer airport_points (se) / R120: no NULL name or airport_class — PASS (name_nulls=0, class_nulls=0)

importer tiles --check conf/semap.yaml (R121, decoded MVT at coarsest + finest zoom):
airports z10/z13 and airport_points z8/z13 all PASS with keys [name airport_class country]. Decoded the z13 Arlanda tile by hand: 2 runway polygons, name=Arlanda flygplats, class 1. z9 below the airports floor returns 0 bytes.

Browser (real Chrome over CDP, no virtual time): at z13 Arlanda renders 6 runway
polygons + the "Arlanda flygplats" icon/label; Landvetter and Sturup render their
labels + runways at z13; at z11 Arlanda's label renders. At z8–z9 dense areas some
labels are collision-culled by MapLibre in favour of place names (normal symbol
placement — the source features are present). Local vision model (Qwen2.5-VL-3B) on
the Arlanda z13 screenshot: icon + "Arlanda flygplats" label + grey runways present,
no code labels, no garbled text. /tiles/se serves 200; the only console 404s are
the pre-existing /favicon.ico.

make build and make test pass.

Notes / left undone

  • flygplatspunkt (objekttypnr 2852, 68 heliport points) is in the same theme but not
    imported — it is a point layer of heliports, not airports; the issue scopes runway
    polygons + areas. Easy follow-up if wanted.
  • 10 iata airports have no ANLTX label (Gävle, Hultsfred, Hudiksvall, Idre,
    Kristianstad, Lidköping, Oskarshamn, Söderhamn, Storuman) — they keep runways but no
    label. That is the text theme's coverage, not an omission in the join.
  • No style width/colour invariants touched (the se layers copy the is layers'
    paint/layout verbatim, only nafnfitju → name).
#103: Sweden airports + airport_points from Topo 10 Anläggningsområde Closes #103 --- ## What changed Sweden gets the `airports` and `airport_points` layers, mirroring Iceland's implementation (R140), from Lantmäteriet Topo 10 tema **Anläggningsområde** — a `files:` entry on the already-negotiated `topo10` Geotorget order plus the layers, no new approval. **Source** (`conf/semap.yaml`): `start_landningsbana` (objekttypnr 2853) — 206 runway polygons with `flygplatsstatus` (I drift / Nedlagd) — and `flygplatsomrade` (objekttypnr 2854) — 183 airport-area polygons with the codes. Both staged (EPSG:3006 → 3857) as `se_runway_t10` / `se_flygplats_t10`; the theme zip is 11.4 MB / 25.7 MB unzipped, recorded on first fetch (R5). The layer is `filter_only`, z10–z13 like Iceland's, and reads the runway polygons joined to their airport area. **Design decisions, each measured against the live data:** - **Nedlagd runways are dropped at import** (190 of 206 kept), the same closed-track decision the `railways` layer made: a decommissioned runway should not render as an airport. - **airport_class comes from the codes, not from flygplatsstatus.** Iceland's ladder (Áætlunarvöllur vs Lendingarstaður) has no Swedish equivalent — `flygplatsstatus` only says I drift/Nedlagd (operational state, not traffic level). So class 1 (scheduled) = `iata` present ("regular traffic only" per the source docs), class 2 = absent. 57 class-1 / 133 class-2 runways. The coarse-zoom `airport_points` filter (z9, `airport_class = 1`, like Iceland) keeps the 42 scheduled airports on z8–z9. - **Names come from the Topo 10 `text` theme** (already staged for `places`): the ANLTX "X flygplats" labels — 48 of the 183 areas carry one, all inside their area, one per area. Neither anläggningsomrade table has a name, only codes (ESSA / ARN), and a code is not a label. The join is the label *inside the runway's own area*, not a nearest label: the uncapped nearest-label join this replaced assigned a label up to 300 km away (measured live; the R120 acceptance test would catch it). Named airports get a label point; the other 135 areas keep their runway polygons and no label. **Serving:** `conf/semap.yaml` regains a `sources:` block (`se`, airports + airport_points — the first unshared Sweden layer since Phase 5), `conf/mapsrv.yaml` serves `/tiles/se`, and `html/style.json` declares the `se` source with `airports_se` + `airport_labels_se` layers copied from Iceland's, reading the `name` column. ## Verification (live DB) Rows per zoom (all partitions populated, z3–z14 floor): - `se_airports_*`: 190 runways at every of z10–z13 - `se_airport_points_*`: 42 (scheduled) at z8–z9, 48 (all labeled) at z10–z13 Acceptance — `make acceptance-all` tally (fast + 100s/1000s buckets, every config): ``` conf/ismap.yaml 31 test(s): 31 passed, 0 failed conf/semap.yaml 36 test(s): 36 passed, 0 failed conf/plmap.yaml 29 test(s): 29 passed, 0 failed conf/fimap.yaml 34 test(s): 34 passed, 0 failed conf/world.yaml 14 test(s): 14 passed, 0 failed ``` New tests (in the same commit, on the airports / airport_points layers): ``` layer airports (se) / R119: no airports zoom table is empty (z10–z13) — PASS (tables=4) layer airports (se) / R120: no NULL airport_class; every name is the label inside its own area — PASS (class_nulls=0, name_nulls=136, mismatched=0) layer airport_points (se) / R119: no airport_points zoom table is empty (z8–z13) — PASS (tables=6) layer airport_points (se) / R120: no NULL name or airport_class — PASS (name_nulls=0, class_nulls=0) ``` `importer tiles --check conf/semap.yaml` (R121, decoded MVT at coarsest + finest zoom): `airports` z10/z13 and `airport_points` z8/z13 all PASS with keys `[name airport_class country]`. Decoded the z13 Arlanda tile by hand: 2 runway polygons, `name=Arlanda flygplats`, class 1. z9 below the airports floor returns 0 bytes. Browser (real Chrome over CDP, no virtual time): at z13 Arlanda renders 6 runway polygons + the "Arlanda flygplats" icon/label; Landvetter and Sturup render their labels + runways at z13; at z11 Arlanda's label renders. At z8–z9 dense areas some labels are collision-culled by MapLibre in favour of place names (normal symbol placement — the source features are present). Local vision model (Qwen2.5-VL-3B) on the Arlanda z13 screenshot: icon + "Arlanda flygplats" label + grey runways present, no code labels, no garbled text. `/tiles/se` serves 200; the only console 404s are the pre-existing `/favicon.ico`. `make build` and `make test` pass. ## Notes / left undone - `flygplatspunkt` (objekttypnr 2852, 68 heliport points) is in the same theme but not imported — it is a point layer of heliports, not airports; the issue scopes runway polygons + areas. Easy follow-up if wanted. - 10 iata airports have no ANLTX label (Gävle, Hultsfred, Hudiksvall, Idre, Kristianstad, Lidköping, Oskarshamn, Söderhamn, Storuman) — they keep runways but no label. That is the text theme's coverage, not an omission in the join. - No style width/colour invariants touched (the se layers copy the is layers' paint/layout verbatim, only `nafnfitju` → `name`).
Sweden's first unshared layer since unification Phase 5: `airports` (runway
polygons) + the derived `airport_points` label layer, mirroring Iceland's
implementation (R140), from the already-negotiated topo10 Geotorget order (new
files: entry only — 11.4 MB zipped / 25.7 MB unzipped, recorded on first fetch,
R5).

Source: start_landningsbana (objekttypnr 2853, 206 runway polygons with
flygplatsstatus I drift/Nedlagd) joined to flygplatsomrade (objekttypnr 2854,
183 areas with iata/icao). Design, each decision measured against the live data:

- Nedlagd runways are dropped at import (190 of 206 kept) — the same closed-track
  decision the railways layer made; a decommissioned runway is not an airport.
- airport_class comes from the codes, not flygplatsstatus: Iceland's
  scheduled-vs-strip ladder has no Swedish vocabulary, so class 1 = iata present
  ("regular traffic only" per the source docs), class 2 = absent. 57/133 runways.
  The coarse-zoom label filter (z9, class 1, like Iceland) keeps the 42 scheduled
  airports on z8-z9.
- Names come from the Topo 10 text theme's ANLTX "X flygplats" labels (48 of 183
  areas carry one, always inside its area): neither anläggningsomrade table has a
  name, only codes, and a code is not a label. The join is the label inside the
  runway's own area — the uncapped nearest-label join this replaced labelled
  runways from another airport up to 300 km away, and the R120 acceptance test
  pins the structural guarantee.

Serving: semap.yaml regains a sources: block (se), mapsrv.yaml serves /tiles/se,
html/style.json declares the se source with airports_se + airport_labels_se copied
from Iceland's (nafnfitju -> name). Docs updated: country-sweden.md catalogue line
(issue #84), R13 in country-requirements.md, style.md layer count, unification.md.

Verified against the live DB: se_airports_* 190 rows at z10-z13; se_airport_points_*
42 at z8-z9 / 48 at z10-z13; new R119/R120 acceptance tests PASS; importer tiles
--check PASS for both layers at coarsest + finest zoom; decoded the z13 Arlanda
tile by hand (2 runways, name=Arlanda flygplats, class 1); real-browser CDP render
at z11-13 shows Arlanda/Landvetter/Sturup labels + runways; make acceptance-all:
ismap 31/31, semap 36/36, plmap 29/29, fimap 34/34, world 14/14; make build and
make test pass.
Three review points, none of which changes Sweden's output (measured: 48 points,
42 class 1, before and after) — they make the derivation right for the sources
that will exercise it.

* `min(airport_class)`, not `max`. The ladder is 1 = scheduled, 2 = everything
  else, so max() demotes an airport to the tier of its weakest polygon. Sweden's
  class comes from the airport area and every runway of one airport agrees, but
  Poland's BDOT10k splits Wrocław-Strachowice and Lublin across a 'port lotniczy'
  and an 'inne lotnisko' polygon each, and max() drops both off the z9 filter.
  The aggregate has to be the one that survives a source disagreeing with itself.

* Group by (name, spatial cluster), the R91 idiom places uses, not by name alone.
  A name is the source's label, not an airport identity key. eps 5 000 web-
  Mercator units sits an order of magnitude above the widest legitimate multi-
  area airport (Arlanda's three areas, 2 684 units apart) and an order of
  magnitude below a real collision; measured over all four countries it splits
  exactly one group, in Poland.

* The unnamed areas do not "keep their runway polygons" below z10 — airports
  starts at z10, so they draw nothing at all at z8–z9. Ten of them carry an iata
  code (GVX, HLF, HUV, IDB, KSK, LDK, ORB, OSK, SOO, SQO), so the coarse-zoom set
  is the 42 labelled scheduled airports, not all 52. Recorded in the layer
  comment and docs/country-sweden.md; every major airport is labelled.
Author
Owner

Merged through !154

Merged through !154
art closed this pull request 2026-08-17 22:09:40 +00:00

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
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
art/ismap!146
No description provided.