#29: place names for Sweden and Poland #73

Merged
art merged 3 commits from issue-29-se-pl-place-names into main 2026-08-09 10:04:29 +00:00
Owner

Closes #29


Place names for Sweden and Poland via the shared places layer

What and why

Issue #29 asked for place names in Poland, Sweden and Finland. PR #53 landed Finland
and Iceland through a shared map_places layer (points + name + importance 1–3, with
MapLibre doing the decluttering). This PR fills in the other two countries against the
same layer, on top of the merged #71 rank shape (per-country rank column, per-zoom
rank <= N budget caps).

Design decision (per the issue's open question). Points suffice — the shared layer
contract (#53) is explicitly points with a name, collision handling is MapLibre's job,
and label-anchor polygons are the "extension the issue flagged", deferred. Both new
countries confirm the source reality: Sweden's Topo 10 text theme is points only
(textobjekt, 835 k points), and Poland's PRNG settlement names are points.

Sweden — Lantmäteriet Topo 10 text theme

  • New geotorget order topo10-text fetches text_sverige.zip (52 MB) as its own
    entry
    rather than a files: line in the topo10 order: delivery ids rotate, and
    adding a file to that order would trip its filesPresent() short-circuit into a ~13 GB
    re-download of mark on the next import.
  • The settlement classes BEBTÄTTX (tätort, the towns) and BEBTX (bebyggelse,
    settlements) are staged into PostGIS (se_text_t10, then the cluster se_text_t10_cl)
    because the rank needs the built-up join and a cluster dedupe — both PostGIS. Terrain/
    water/marsh/nature/church labels are the lake-and-river-naming extension, not place
    names, and stay out.
  • importance = the register's own label-height ladder (thojd 10–30): 30 → 3, 20 → 2,
    else 1. This is the same "survey prints it big" signal Finland's kirjasinkoko and
    Iceland's örnefnaflokkur carry.
  • rank = ROW_NUMBER over (importance, built-up footprint, name). The footprint is the
    real size signal: total area of the se_mark_t10 built-up polygons (2636/2637/2638/
    2639) within 6 km of the nearest tätort label, summed per place. It puts Stockholm
    first and gives z5 the maintainer's expected set — {Stockholm, Göteborg, Västerås,
    Uppsala, Linköping, Malmö} — where the original label-placement-count tiebreak ranked
    Västerås/Nyköping/Sala above the capital and left Göteborg/Malmö out of z5 entirely
    (issue #29 review).
  • Dedupe: se_text_t10_cl clusters the settlement labels spatially within the name
    (ST_ClusterDBSCAN, 15 km eps) and the layer keeps one row per (name, cluster) — the
    largest-label placement. A big town's several label points are one place; two genuinely
    separate villages with the same name both survive. (The old nationwide ROW_NUMBER
    silently dropped the second village.)
  • Verified: 203 830 places, zoom counts 1/6/24/96/384/1536/6144/24576/98304 match the
    X=60% budget, no NULLs, decoded z5 tile carries exactly the six big cities, real-browser
    CDP render shows the names.

Poland — GUGiK PRNG

  • The register behind the IDENTYFIKATORPRNG identifiers on water/transport features.
    New downloads: entry fetches the M1_UrzedoweNazwyMiejscowosci layer (official
    names) as one WFS GetFeature GML (~86 MB, PROPERTYNAME slimmed to the columns this
    layer reads: NAZWAGLOWNA, SKALA_WYSWIETLANIA, msGeometry). M2 (pozostałe/other)
    is deliberately not fetched — the non-official tier, the same exclusion as Finland's
    48190 "other".
  • Importer change: the GML loader (readGMLTable) was polygon-only (one MULTIPOLYGON
    for masks). A new gml_points loader reads point features with named attributes —
    one row per feature, geometry from gml:Point/gml:pos, every other direct child
    element a text column (lowercased), axis-order handling via swap_axes like the
    polygon path. Tested in importer/gml_test.go.
  • importance = the register's own SKALA_WYSWIETLANIA (display scale, 1:100000 up to
    1:8000000) — fine-grained where Sweden's thojd is coarse: exactly 1026 names print at
    1:500000 or coarser (the cities) → scale ≥ 1:500000 is 3, 1:250000 is 2, 1:100000 is 1.
  • rank = ROW_NUMBER over (scale denominator, name) — the redundant importance DESC
    first key is dropped, since importance is derived from the denominator. The register
    ties its top tier: 17 cities all print at 1:8000000, so within it the order falls to
    name — Warszawa is rank 15, appearing from z6 (rank ≤ 18). This is the register's own
    coarseness, exactly the #71 acceptance of register ladders; at z5 Poland shows its four
    largest cities by the survey's own order.
  • Poland deliberately keeps the WHOLE register (all 101 334 rows, one per place, no
    dedupe), including the część wsi/część miasta parts that label city districts at
    high zoom — a flat catalogue of official names with no hierarchy to filter on, unlike
    Sweden's mixed label theme. The two countries agree on what a place is (one label point
    per place); they differ only in that Poland's source is already pure place names.
  • Verified: 101 334 names, no NULLs, zoom counts match the budget, decoded z6 tile
    carries Warszawa, CDP render confirms.

The shared contract

conf/common.yaml places comment updated to say all four countries now have partitions
(the old text said Sweden and Poland render nothing). #71's budget formula is reused
unchanged with each country's land area, and this branch sits on the merged #71 — the
fimap/ismap rank changes are already in main.

What's left undone

  • The lake/river/terrain names in Sweden's text theme (the issue's extended scope) and
    the spatial join to put water names on the water features — explicitly deferred.
  • Warsaw's top-tier tie means the register itself doesn't rank the capital first; a
    population-based tiebreak is the documented alternative if that ever matters.

Verification

  • make build, go test ./... in importer/ and mapsrv/ — green.
  • Live-DB row counts per zoom per country, NULL checks, partitions at every zoom (z4–14,
    all four countries), decoded tiles, and real-browser CDP renders (never virtual time).
Closes #29 --- # Place names for Sweden and Poland via the shared places layer ## What and why Issue #29 asked for place names in Poland, Sweden and Finland. PR #53 landed Finland and Iceland through a shared `map_places` layer (points + name + importance 1–3, with MapLibre doing the decluttering). This PR fills in the other two countries against the same layer, on top of the merged #71 rank shape (per-country `rank` column, per-zoom `rank <= N` budget caps). **Design decision (per the issue's open question).** Points suffice — the shared layer contract (#53) is explicitly points with a name, collision handling is MapLibre's job, and label-anchor polygons are the "extension the issue flagged", deferred. Both new countries confirm the source reality: Sweden's Topo 10 `text` theme is points only (`textobjekt`, 835 k points), and Poland's PRNG settlement names are points. ## Sweden — Lantmäteriet Topo 10 `text` theme - New geotorget order `topo10-text` fetches `text_sverige.zip` (52 MB) **as its own entry** rather than a `files:` line in the `topo10` order: delivery ids rotate, and adding a file to that order would trip its `filesPresent()` short-circuit into a ~13 GB re-download of `mark` on the next import. - The settlement classes `BEBTÄTTX` (tätort, the towns) and `BEBTX` (bebyggelse, settlements) are staged into PostGIS (`se_text_t10`, then the cluster `se_text_t10_cl`) because the rank needs the built-up join and a cluster dedupe — both PostGIS. Terrain/ water/marsh/nature/church labels are the lake-and-river-naming extension, not place names, and stay out. - `importance` = the register's own label-height ladder (`thojd` 10–30): 30 → 3, 20 → 2, else 1. This is the same "survey prints it big" signal Finland's kirjasinkoko and Iceland's örnefnaflokkur carry. - `rank` = ROW_NUMBER over (importance, built-up footprint, name). The footprint is the real size signal: total area of the `se_mark_t10` built-up polygons (2636/2637/2638/ 2639) within 6 km of the nearest tätort label, summed per place. It puts Stockholm first and gives z5 the maintainer's expected set — {Stockholm, Göteborg, Västerås, Uppsala, Linköping, Malmö} — where the original label-placement-count tiebreak ranked Västerås/Nyköping/Sala above the capital and left Göteborg/Malmö out of z5 entirely (issue #29 review). - Dedupe: `se_text_t10_cl` clusters the settlement labels spatially within the name (ST_ClusterDBSCAN, 15 km eps) and the layer keeps one row per (name, cluster) — the largest-label placement. A big town's several label points are one place; two genuinely separate villages with the same name both survive. (The old nationwide ROW_NUMBER silently dropped the second village.) - Verified: 203 830 places, zoom counts 1/6/24/96/384/1536/6144/24576/98304 match the X=60% budget, no NULLs, decoded z5 tile carries exactly the six big cities, real-browser CDP render shows the names. ## Poland — GUGiK PRNG - The register behind the `IDENTYFIKATORPRNG` identifiers on water/transport features. New `downloads:` entry fetches the **M1_UrzedoweNazwyMiejscowosci** layer (official names) as one WFS GetFeature GML (~86 MB, PROPERTYNAME slimmed to the columns this layer reads: NAZWAGLOWNA, SKALA_WYSWIETLANIA, msGeometry). M2 (pozostałe/other) is deliberately not fetched — the non-official tier, the same exclusion as Finland's 48190 "other". - **Importer change:** the GML loader (`readGMLTable`) was polygon-only (one MULTIPOLYGON for masks). A new `gml_points` loader reads point features with named attributes — one row per feature, geometry from `gml:Point`/`gml:pos`, every other direct child element a text column (lowercased), axis-order handling via `swap_axes` like the polygon path. Tested in `importer/gml_test.go`. - `importance` = the register's own `SKALA_WYSWIETLANIA` (display scale, 1:100000 up to 1:8000000) — fine-grained where Sweden's thojd is coarse: exactly 1026 names print at 1:500000 or coarser (the cities) → scale ≥ 1:500000 is 3, 1:250000 is 2, 1:100000 is 1. - `rank` = ROW_NUMBER over (scale denominator, name) — the redundant `importance DESC` first key is dropped, since importance is derived from the denominator. The register ties its top tier: 17 cities all print at 1:8000000, so within it the order falls to name — Warszawa is rank 15, appearing from z6 (rank ≤ 18). This is the register's own coarseness, exactly the #71 acceptance of register ladders; at z5 Poland shows its four largest cities by the survey's own order. - Poland deliberately keeps the WHOLE register (all 101 334 rows, one per place, no dedupe), including the `część wsi`/`część miasta` parts that label city districts at high zoom — a flat catalogue of official names with no hierarchy to filter on, unlike Sweden's mixed label theme. The two countries agree on what a place is (one label point per place); they differ only in that Poland's source is already pure place names. - Verified: 101 334 names, no NULLs, zoom counts match the budget, decoded z6 tile carries Warszawa, CDP render confirms. ## The shared contract `conf/common.yaml` places comment updated to say all four countries now have partitions (the old text said Sweden and Poland render nothing). `#71`'s budget formula is reused unchanged with each country's land area, and this branch sits on the merged #71 — the fimap/ismap rank changes are already in main. ## What's left undone - The lake/river/terrain names in Sweden's `text` theme (the issue's extended scope) and the spatial join to put water names on the water features — explicitly deferred. - Warsaw's top-tier tie means the register itself doesn't rank the capital first; a population-based tiebreak is the documented alternative if that ever matters. ## Verification - `make build`, `go test ./...` in `importer/` and `mapsrv/` — green. - Live-DB row counts per zoom per country, NULL checks, partitions at every zoom (z4–14, all four countries), decoded tiles, and real-browser CDP renders (never virtual time).
Issue #29 asked for place names in Poland, Sweden and Finland. PR #53 landed Finland
and Iceland through a shared `map_places` layer (points + name + importance, MapLibre
doing the decluttering); this fills in Sweden and Poland against the same layer, and
carries the sibling #71 rank shape (per-country `rank`, per-zoom `rank <= N` budget
caps) that the layer is converging on.

The issue's design question — points or polygons — is answered by the shared contract
itself: points suffice. The layer promises points with a name, collision handling is
MapLibre's job, and label-anchor polygons are the deferred extension. Both new sources
are points anyway.

Sweden — Lantmäteriet Topo 10 `text` theme. New geotorget order `topo10-text` fetches
`text_sverige.zip` as its own entry, so fetching the 52 MB theme never re-negotiates
the `topo10` order's delivery (which would re-download ~13 GB of mark). The layer reads
`textobjekt` directly from the GeoPackage — no staging — filtering the settlement
classes `BEBTÄTTX` (tätort) and `BEBTX` (bebyggelse). importance mirrors the register's
own label-height ladder (`thojd` 10–30: 30→3, 20→2, else 1); rank orders importance,
thojd, then the tätort label-placement count (the survey's own finer signal within a
coarse tier — 127 towns tie at thojd 30, and the placement count is the only thing
Lantmäteriet's data offers to break it; Stockholm lands rank 4). regtext is the
assembled name (the theme splits long labels across rows); ROW_NUMBER keeps one point
per name, the largest-label placement.

Poland — GUGiK PRNG. New `downloads:` entry fetches the M1 (official names) layer as a
single WFS GetFeature GML. The importer's GML loader was polygon-only; a new `gml_points`
loader reads point features with named attributes (one row per feature, geometry from
gml:Point/gml:pos, other direct children as lowercased text columns), tested in
importer/gml_test.go. importance comes from the register's own SKALA_WYSWIETLANIA
(display scale): ≥1:500000 → 3, 1:250000 → 2, 1:100000 → 1. rank orders importance,
then scale denominator, then name; the register ties its top tier (17 cities at
1:8000000) so Warszawa is rank 15 — the register's own coarseness, the same acceptance
as #71's FORSSA-over-HELSINKI.

Adding `rank` to the shared places contract makes wireSharedLayers require it from every
country, so this PR also carries the #71 rank shape for Finland and Iceland — it subsumes
the sibling #72 for this layer; the two PRs conflict by construction.

Verified against the live DB: per-zoom row counts match the X=60% land-area budget for
both countries (se 1/5/23/94/378/1514/…/96943, pl 1/4/18/72/289/1159/…/74226), no NULLs
in name/importance/rank, partitions at every zoom z4–14, decoded tiles carry the top
names (Sweden's z5 shows the register's top-5 including Stockholm; Poland's z6 includes
Warszawa), and a real-browser CDP render confirms the labels draw. `make build` and
`go test ./...` pass in both importer and mapsrv.
art force-pushed issue-29-se-pl-place-names from 1366af641e to b0ae0bfe6a 2026-08-08 22:17:29 +00:00 Compare
Author
Owner

Sweden z5 is showing some really strange choices. It should be Stockholm, Göteborg, Malmö, Uppsala and (here the fight starts because technically it should be a locality created a decade ago because parts of Stockholm didn't actually fit the technical definition of tätort and were split up, but it's such a new name that Lanmäteriet refuses to use it because they have a technical requirement of a name being in use for sufficiently long time, which is much more than this abomination has existed and besides no one uses it outside of pub quizzes) Västerås and Linköping.

Sweden z5 is showing some really strange choices. It should be Stockholm, Göteborg, Malmö, Uppsala and (here the fight starts because technically it should be a locality created a decade ago because parts of Stockholm didn't actually fit the technical definition of tätort and were split up, but it's such a new name that Lanmäteriet refuses to use it because they have a technical requirement of a name being in use for sufficiently long time, which is much more than this abomination has existed and besides no one uses it outside of pub quizzes) Västerås and Linköping.
Collaborator

Review — changes requested (Sweden's rank tiebreak)

Poland's half verifies cleanly against the live DB. PRNG's SKALA_WYSWIETLANIA tier is a real signal: exactly 1026 rows print at 1:500000 or coarser and exactly 1026 rows are rodzajobiektu = 'miasto', so "the coarse tier is the cities" is the register's own statement, not an inference. The 17 at 1:8000000 are the voivodeship capitals, Warszawa lands at rank 15 → z6, all as documented. gml_points is a clean addition and go test ./... passes in importer/ on the branch.

Sweden's ranking is the problem.

tpos is not measuring town size (conf/semap.yaml:947)

The tiebreak is justified as "Lantmäteriet prints a big town's name at several points on the map and a hamlet's at one". The imported result contradicts that:

z4 Sweden shows exactly one name:  Västerås
z5:  Västerås, Nyköping, Sala, Stockholm, Uppsala
Göteborg 6 · Linköping 16 · Malmö 20 · Örebro 29 · Kiruna 791

Ranks 7 onward are plain alphabetical (Hallstahammar, Halmstad, Helsingborg, Hultsfred, …), so tpos separates six names in the entire thojd-30 tier — and it orders Sala and Nyköping above Stockholm.

This is not the #71 FORSSA-over-HELSINKI situation. There, the register's own coarseness was being accepted. Here a derived quantity is being introduced on the claim that it tracks size, and its output falsifies the claim: the country map at z4 names Västerås and nothing else. The count is count(DISTINCT hex(geom)) over regtext + thojd nationwide, so it is picking up split-label fragments and repeated name strings across the country, both uncorrelated with importance.

Options, roughly in order of cost:

  1. Drop tpos and tie-break on name, as Poland's layer does. Arbitrary, but honestly arbitrary — and Stockholm/Göteborg/Malmö at least fall where alphabet puts them rather than behind Sala.
  2. Use a real size signal. se_mark_t10 is already staged and carries built-up polygons (Låg bebyggelse 16 554, Hög bebyggelse 4 527, Sluten bebyggelse 394, Industri- och handelsbebyggelse 6 995). Total built-up area within a small radius of the label point is a genuine measure of how big the place is, and it would rank the tier properly.

(2) is the one that makes z4–z6 look like a map of Sweden.

Nationwide dedupe drops distinct places (conf/semap.yaml:956)

ROW_NUMBER() OVER (PARTITION BY g.regtext ORDER BY …) keeps one point per name for the whole country. That is needed for the split-label case ("Stock-" + "holm" sharing a regtext), but it is too broad: two separate Swedish villages with the same name yield one label, and the other place is silently gone. Same fix as the sibling #74 — cluster spatially within the name (ST_ClusterDBSCAN … PARTITION BY regtext) and keep one row per (name, cluster). Note Poland's query does not dedupe (101 334 rows, one per place), so the two countries in this PR currently disagree about what a place is.

Smaller points

  • Sweden's z12 cap is rank <= 96943 against a 96 499-row register, so that rung is a no-op; the comment says "z13+ keeps the whole register" but z12 does too.
  • Poland's layer keeps all 101 334 register rows, including 34 177 część wsi and 6 710 część miasta. City districts will label inside cities at high zoom. Sweden filters to the settlement classes (BEBTÄTTX/BEBTX) — worth being deliberate about the asymmetry rather than inheriting it.
  • statusnazwy is a constant ('urzędowa') across the whole register and is read by neither this PR nor #68's, and rodzajobiektu is read only by #68's. The comment "PROPERTYNAME keeps only the columns the layer reads + geometry" isn't accurate as written.
  • Poland's rank orders importance DESC, denominator DESC, name — importance is derived from the denominator, so the first key is redundant. Harmless.
  • The body's "this PR subsumes the sibling #72 (issue #71)" is stale: #71 landed in e5b5eda and this branch sits on top of it. The diff no longer touches fimap.yaml/ismap.yaml.

Merge order

Verified: #74 and (now-merged) #75 merge cleanly onto this branch. #68's PR conflicts — it independently adds the same pl_prng_m1 download and staging entries plus a verbatim copy of this branch's importer/staging.go. This PR should land first and #76 rebase onto it.

## Review — changes requested (Sweden's rank tiebreak) Poland's half verifies cleanly against the live DB. PRNG's `SKALA_WYSWIETLANIA` tier is a real signal: exactly 1026 rows print at 1:500000 or coarser and exactly 1026 rows are `rodzajobiektu = 'miasto'`, so "the coarse tier is the cities" is the register's own statement, not an inference. The 17 at 1:8000000 are the voivodeship capitals, Warszawa lands at rank 15 → z6, all as documented. `gml_points` is a clean addition and `go test ./...` passes in `importer/` on the branch. Sweden's ranking is the problem. ### `tpos` is not measuring town size (conf/semap.yaml:947) The tiebreak is justified as "Lantmäteriet prints a big town's name at several points on the map and a hamlet's at one". The imported result contradicts that: ``` z4 Sweden shows exactly one name: Västerås z5: Västerås, Nyköping, Sala, Stockholm, Uppsala Göteborg 6 · Linköping 16 · Malmö 20 · Örebro 29 · Kiruna 791 ``` Ranks 7 onward are plain alphabetical (Hallstahammar, Halmstad, Helsingborg, Hultsfred, …), so `tpos` separates six names in the entire thojd-30 tier — and it orders Sala and Nyköping above Stockholm. This is not the #71 FORSSA-over-HELSINKI situation. There, the register's own coarseness was being accepted. Here a *derived* quantity is being introduced on the claim that it tracks size, and its output falsifies the claim: the country map at z4 names Västerås and nothing else. The count is `count(DISTINCT hex(geom))` over `regtext + thojd` nationwide, so it is picking up split-label fragments and repeated name strings across the country, both uncorrelated with importance. Options, roughly in order of cost: 1. **Drop `tpos`** and tie-break on name, as Poland's layer does. Arbitrary, but honestly arbitrary — and Stockholm/Göteborg/Malmö at least fall where alphabet puts them rather than behind Sala. 2. **Use a real size signal.** `se_mark_t10` is already staged and carries built-up polygons (`Låg bebyggelse` 16 554, `Hög bebyggelse` 4 527, `Sluten bebyggelse` 394, `Industri- och handelsbebyggelse` 6 995). Total built-up area within a small radius of the label point is a genuine measure of how big the place is, and it would rank the tier properly. (2) is the one that makes z4–z6 look like a map of Sweden. ### Nationwide dedupe drops distinct places (conf/semap.yaml:956) `ROW_NUMBER() OVER (PARTITION BY g.regtext ORDER BY …)` keeps one point per name for the whole country. That is needed for the split-label case ("Stock-" + "holm" sharing a `regtext`), but it is too broad: two separate Swedish villages with the same name yield one label, and the other place is silently gone. Same fix as the sibling #74 — cluster spatially within the name (`ST_ClusterDBSCAN … PARTITION BY regtext`) and keep one row per (name, cluster). Note Poland's query does *not* dedupe (101 334 rows, one per place), so the two countries in this PR currently disagree about what a place is. ### Smaller points * Sweden's z12 cap is `rank <= 96943` against a 96 499-row register, so that rung is a no-op; the comment says "z13+ keeps the whole register" but z12 does too. * Poland's layer keeps all 101 334 register rows, including 34 177 `część wsi` and 6 710 `część miasta`. City districts will label inside cities at high zoom. Sweden filters to the settlement classes (`BEBTÄTTX`/`BEBTX`) — worth being deliberate about the asymmetry rather than inheriting it. * `statusnazwy` is a constant (`'urzędowa'`) across the whole register and is read by neither this PR nor #68's, and `rodzajobiektu` is read only by #68's. The comment "PROPERTYNAME keeps only the columns the layer reads + geometry" isn't accurate as written. * Poland's rank orders `importance DESC, denominator DESC, name` — `importance` is derived from the denominator, so the first key is redundant. Harmless. * The body's "this PR subsumes the sibling #72 (issue #71)" is stale: #71 landed in `e5b5eda` and this branch sits on top of it. The diff no longer touches `fimap.yaml`/`ismap.yaml`. ### Merge order Verified: #74 and (now-merged) #75 merge cleanly onto this branch. **#68's PR conflicts** — it independently adds the same `pl_prng_m1` download and staging entries plus a verbatim copy of this branch's `importer/staging.go`. This PR should land first and #76 rebase onto it.
The review of the Sweden half of the places layer flagged two real defects in the
`tpos` tiebreak (label-placement count) and the nationwide dedupe:

* `tpos` was not measuring town size. It counted distinct label points per
  (regtext, thojd), which picks up split-label fragments and repeated names
  across the country — uncorrelated with importance. The imported result was
  bizarre (z4 = Västerås alone; z5 = Västerås/Nyköping/Sala/Stockholm/Uppsala;
  ranks 7+ alphabetical). Replace it with a genuine size signal: the total area
  of the `se_mark_t10` built-up polygons (objekttypnr 2636/2637/2638/2639)
  within 6 km of the nearest tätort label, summed per place. z5 is now exactly
  the maintainer's expected set: Stockholm, Göteborg, Västerås, Uppsala,
  Linköping, Malmö.

  A plain "built-up within a small radius of the label point" is not used
  because Lantmäteriet places each town's label at a readable map position
  (Stockholm's over the archipelago), so a radius around the label point
  under-measures the town and lets its suburbs outrank it. Assigning each
  built-up polygon to the nearest tätort label gives every place its own
  footprint.

* The dedupe kept one point per name nationwide, silently dropping a second
  village that shared a name. `se_text_t10_cl` clusters the settlement labels
  spatially within the name (ST_ClusterDBSCAN, 15 km eps): a big town's several
  label points are one place, two genuinely separate villages both survive. The
  register grows from 96 499 names to 203 830 places; the z12 cap is now
  meaningful (98304 < register) instead of a no-op.

To run the footprint join and the cluster dedupe (both PostGIS), the
`textobjekt` points are staged into PostGIS (`se_text_t10`, then the clustered
`se_text_t10_cl`) instead of read straight from the GeoPackage. The built-up
kNN runs against the gist index on the clustered table.

Poland's half: the redundant `importance DESC` first rank key is dropped
(importance is derived from the denominator), the PROPERTYNAME comment now
matches the URL (dropped the constant `statusnazwy` column and `rodzajobiektu`,
which only #68 reads and re-adds on rebase), and the deliberate asymmetry is
documented — Poland keeps the whole register (parts included) because PRNG is
already pure place names, where Sweden must filter its mixed label theme.

Verified against the live DB: 203 830 Swedish places, zoom counts
1/6/24/96/384/1536/6144/24576/98304, no NULLs in name/geom/importance/rank,
partitions at every zoom, decoded z5 tile carries exactly the six expected
names, Poland unchanged at 101 334 rows with Warszawa rank 15 → z6.
`go test ./...` green in importer/ and mapsrv/.
Author
Owner

Review addressed on the branch (commit d6a0823). What changed:

1. Size signal — tpos is gone, replaced by built-up footprint. rank now orders by (importance, footprint, name), where footprint = total area of the se_mark_t10 built-up polygons (2636/2637/2638/2639) within 6 km of the nearest tätort label, summed per place. z5 is now exactly the maintainer's expected set: Stockholm, Göteborg, Västerås, Uppsala, Linköping, Malmö (z4 = Stockholm alone).

Why not the literal "built-up within a small radius of the label point": Lantmäteriet places each town's label at a readable map position (Stockholm's over the archipelago), so a plain radius under-measures the town and lets its suburbs outrank it. Assigning each built-up polygon to the nearest tätort label gives every place its own footprint — Stockholm first, Täby/Sollentuna out of the top-6.

2. Nationwide dedupe replaced by spatial clustering within the name. se_text_t10_cl runs ST_ClusterDBSCAN(geom, 15000, 1) OVER (PARTITION BY regtext); the layer keeps one row per (name, cluster). A big town's several label points are one place; two same-named villages both survive. Register: 96 499 → 203 830 places. This also fixes the z12 no-op (98304 < register now filters).

3. Smaller points. z12 cap is now 98304 and filters; the z13+ comment says ~203 800 places. The Poland/Sweden asymmetry is now a documented deliberate decision (Poland keeps the whole register because PRNG is pure place names; Sweden must filter its mixed label theme). PROPERTYNAME trimmed to the columns this layer reads (dropped the constant statusnazwy and rodzajobiektu, which #68 re-adds on rebase); the comment now matches. Poland's rank drops the redundant importance DESC first key. The stale "#72 subsumes" line is out of the body.

4. Merge order. This branch touches only conf/common.yaml, conf/plmap.yaml, conf/semap.yaml and docs — no importer code beyond what the original PR already carried, so #68's pl_prng_m1/staging.go overlap is unchanged and #76 can rebase onto this.

Verified against the live DB: 203 830 Swedish places, zoom counts 1/6/24/96/384/1536/6144/24576/98304, no NULLs, partitions at every zoom, decoded z5 tile carries exactly the six expected names; Poland unchanged (101 334 rows, Warszawa rank 15 → z6). go test ./... green in importer/ and mapsrv/.

Review addressed on the branch (commit d6a0823). What changed: **1. Size signal — `tpos` is gone, replaced by built-up footprint.** `rank` now orders by (importance, footprint, name), where footprint = total area of the `se_mark_t10` built-up polygons (2636/2637/2638/2639) within 6 km of the nearest tätort label, summed per place. z5 is now exactly the maintainer's expected set: Stockholm, Göteborg, Västerås, Uppsala, Linköping, Malmö (z4 = Stockholm alone). Why not the literal "built-up within a small radius of the label point": Lantmäteriet places each town's label at a readable map position (Stockholm's over the archipelago), so a plain radius under-measures the town and lets its suburbs outrank it. Assigning each built-up polygon to the *nearest* tätort label gives every place its own footprint — Stockholm first, Täby/Sollentuna out of the top-6. **2. Nationwide dedupe replaced by spatial clustering within the name.** `se_text_t10_cl` runs ST_ClusterDBSCAN(geom, 15000, 1) OVER (PARTITION BY regtext); the layer keeps one row per (name, cluster). A big town's several label points are one place; two same-named villages both survive. Register: 96 499 → 203 830 places. This also fixes the z12 no-op (98304 < register now filters). **3. Smaller points.** z12 cap is now 98304 and filters; the z13+ comment says ~203 800 places. The Poland/Sweden asymmetry is now a documented deliberate decision (Poland keeps the whole register because PRNG is pure place names; Sweden must filter its mixed label theme). PROPERTYNAME trimmed to the columns this layer reads (dropped the constant `statusnazwy` and `rodzajobiektu`, which #68 re-adds on rebase); the comment now matches. Poland's rank drops the redundant `importance DESC` first key. The stale "#72 subsumes" line is out of the body. **4. Merge order.** This branch touches only conf/common.yaml, conf/plmap.yaml, conf/semap.yaml and docs — no importer code beyond what the original PR already carried, so #68's `pl_prng_m1`/staging.go overlap is unchanged and #76 can rebase onto this. Verified against the live DB: 203 830 Swedish places, zoom counts 1/6/24/96/384/1536/6144/24576/98304, no NULLs, partitions at every zoom, decoded z5 tile carries exactly the six expected names; Poland unchanged (101 334 rows, Warszawa rank 15 → z6). `go test ./...` green in importer/ and mapsrv/.
Two defects from the review of the footprint ranking.

The footprint was summed with ST_Area over EPSG:3857 geometry, where area inflates as
1/cos²(lat). Across Sweden's 55°-69° that is a 2.6x spread and it systematically promotes
northern towns: Skellefteå ranked 14th and Sundsvall 10th against 31st and 17th by true
area, and the distortion was large enough to push Malmö out of the top five. The area is
now taken in EPSG:3006 (SWEREF99 TM, the source's own national grid). The catchment
radius was likewise 6 000 raw 3857 units — 3.4 km on the ground in the south, 2.3 km in
the north — and is now a uniform 3.4 km ground distance, scaled by 1/cos(lat) at the
call site so ST_DWithin still runs against the 3857 gist index. Nearest-anchor assignment
needs no correction; Mercator is conformal, so the nearest anchor is the same either way.

3.4 km rather than a rounder 6 km because the catchment is tuned and tighter is better:
at a true 6 km, suburbs start absorbing the metro sprawl around them and Sundbyberg
climbs to 4th nationally, ahead of Västerås and Uppsala.

The zoom caps had been replaced with 6/24/96/384/1536/6144/24576/98304 — exactly 6·4^n,
which no land area produces. The shared budget (conf/common.yaml) gives Sweden 5.9161 at
z5, and the previous ladder 5/23/94/378/1514/6058/24235/96943 was that formula's own
output. N(z) is a property of the country's area, so it is restored: rounding z5 up to 6
to admit a sixth city is the tuning issue #71 exists to avoid. With the projection fixed
the bump is unnecessary anyway — Malmö is rank 4.

Verified against the live DB by running the query exactly as it sits in the config:
203 830 places unchanged, no NULLs, importance 3/2/1 = 127/1 901/201 802, and
  z4  Stockholm
  z5  Stockholm, Göteborg, Västerås, Malmö, Uppsala
  z6  + Linköping, Helsingborg, Sundbyberg, Borlänge, Örebro, Växjö, Lund, Karlstad,
      Norrköping, Halmstad, Jönköping, Sollentuna, Sundsvall, Gävle, Motala, Borås,
      Åkersberga, Falun
Not reimported — the maintainer is doing that.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
art merged commit 69f4c70725 into main 2026-08-09 10:04:29 +00:00
art deleted branch issue-29-se-pl-place-names 2026-08-09 10:04:29 +00:00
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!73
No description provided.