From bc7c23dce4284163c2efa3fcb56b1b407cb4d708 Mon Sep 17 00:00:00 2001 From: Siarhei Fedartsou Date: Sun, 8 Dec 2024 13:23:45 +0100 Subject: [PATCH 1/4] Add house numbers layer --- styles/src/base_layers.ts | 18 ++++++++++ .../java/com/protomaps/basemap/Basemap.java | 5 +++ .../basemap/layers/Housenumbers.java | 34 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 tiles/src/main/java/com/protomaps/basemap/layers/Housenumbers.java diff --git a/styles/src/base_layers.ts b/styles/src/base_layers.ts index f0b80e3d..b08e10e5 100644 --- a/styles/src/base_layers.ts +++ b/styles/src/base_layers.ts @@ -1373,6 +1373,24 @@ export function labels_layers( script?: string, ): LayerSpecification[] { return [ + { + id: "housenumbers_label", + type: "symbol", + source: source, + "source-layer": "housenumbers", + minzoom: 13, + layout: { + "symbol-placement": "point", // Places the text at a point location + "text-font": [t.italic || "Noto Sans Italic"], + "text-field": ["get", "housenumber"], // Retrieves the text from the 'housenumber' property in the source + "text-size": 12 // Adjust text size as needed + }, + paint: { + "text-color": "red", // Set text color to red + "text-halo-color": "white", // Optional: adds a halo around the text for better visibility + "text-halo-width": 1 // Optional: defines the width of the halo + } + }, { id: "water_waterway_label", type: "symbol", diff --git a/tiles/src/main/java/com/protomaps/basemap/Basemap.java b/tiles/src/main/java/com/protomaps/basemap/Basemap.java index 0c0db93f..ad172621 100644 --- a/tiles/src/main/java/com/protomaps/basemap/Basemap.java +++ b/tiles/src/main/java/com/protomaps/basemap/Basemap.java @@ -16,6 +16,7 @@ import com.protomaps.basemap.layers.Roads; import com.protomaps.basemap.layers.Transit; import com.protomaps.basemap.layers.Water; +import com.protomaps.basemap.layers.Housenumbers; import com.protomaps.basemap.text.FontRegistry; import java.nio.file.Path; import java.util.HashMap; @@ -36,6 +37,10 @@ public Basemap(NaturalEarthDb naturalEarthDb, QrankDb qrankDb) { registerHandler(buildings); registerSourceHandler("osm", buildings::processOsm); + var housenumbers = new Housenumbers(); + registerHandler(housenumbers); + registerSourceHandler("osm", housenumbers::processOsm); + var landuse = new Landuse(); registerHandler(landuse); registerSourceHandler("osm", landuse::processOsm); diff --git a/tiles/src/main/java/com/protomaps/basemap/layers/Housenumbers.java b/tiles/src/main/java/com/protomaps/basemap/layers/Housenumbers.java new file mode 100644 index 00000000..1294f405 --- /dev/null +++ b/tiles/src/main/java/com/protomaps/basemap/layers/Housenumbers.java @@ -0,0 +1,34 @@ +package com.protomaps.basemap.layers; + +import com.onthegomap.planetiler.FeatureCollector; +import com.onthegomap.planetiler.ForwardingProfile; +import com.onthegomap.planetiler.VectorTile; +import com.onthegomap.planetiler.geo.GeometryException; +import com.onthegomap.planetiler.reader.SourceFeature; +import com.protomaps.basemap.feature.FeatureId; + +import java.util.List; + +public class Housenumbers implements ForwardingProfile.LayerPostProcesser { + public void processOsm(SourceFeature sf, FeatureCollector features) { + if (sf.hasTag("addr:housenumber")) { + if (sf.isPoint()) { + features.point(this.name()) + .setId(FeatureId.create(sf)) + .setAttr("housenumber", sf.getString("addr:housenumber")) + .setZoomRange(10, 17); + } + } + } + + @Override + public List postProcess(int zoom, List items) throws GeometryException { + return items; + } + + @Override + public String name() { + return "housenumbers"; + } + +} From b8899b8ae0d00f21b4ebd2dc188837c7b3af0c5a Mon Sep 17 00:00:00 2001 From: Siarhei Fedartsou Date: Mon, 9 Dec 2024 22:03:02 +0100 Subject: [PATCH 2/4] Add house numbers layer --- styles/src/base_layers.ts | 15 ++++--- styles/src/themes.ts | 21 +++++++++ .../protomaps/basemap/layers/Buildings.java | 1 - .../basemap/layers/Housenumbers.java | 44 ++++++++++++++----- 4 files changed, 63 insertions(+), 18 deletions(-) diff --git a/styles/src/base_layers.ts b/styles/src/base_layers.ts index b08e10e5..150e26cf 100644 --- a/styles/src/base_layers.ts +++ b/styles/src/base_layers.ts @@ -1378,17 +1378,18 @@ export function labels_layers( type: "symbol", source: source, "source-layer": "housenumbers", - minzoom: 13, + minzoom: 17, layout: { - "symbol-placement": "point", // Places the text at a point location + "symbol-placement": "point", "text-font": [t.italic || "Noto Sans Italic"], - "text-field": ["get", "housenumber"], // Retrieves the text from the 'housenumber' property in the source - "text-size": 12 // Adjust text size as needed + "text-field": ["get", "housenumber"], + "text-size": 12 }, paint: { - "text-color": "red", // Set text color to red - "text-halo-color": "white", // Optional: adds a halo around the text for better visibility - "text-halo-width": 1 // Optional: defines the width of the halo + "text-color": t.housenumbers_label, + "text-halo-color": t.house_numbers_label_halo, + "text-halo-width": 1, + "text-halo-blur": 1, } }, { diff --git a/styles/src/themes.ts b/styles/src/themes.ts index e33f63a3..1cf45b97 100644 --- a/styles/src/themes.ts +++ b/styles/src/themes.ts @@ -76,6 +76,9 @@ export interface Theme { state_label_halo: string; country_label: string; + housenumbers_label: string; + house_numbers_label_halo: string; + regular?: string; bold?: string; italic?: string; @@ -188,6 +191,9 @@ export const CONTRAST: Theme = { state_label: "#777777", state_label_halo: "#ffffff", country_label: "#9590aa", + + housenumbers_label: "#91888b", + house_numbers_label_halo: "#ffffff", }; export const LIGHT: Theme = { @@ -270,6 +276,9 @@ export const LIGHT: Theme = { state_label_halo: "#e0e0e0", country_label: "#a3a3a3", + housenumbers_label: "#91888b", + house_numbers_label_halo: "#ffffff", + pois: { blue: "#1A8CBD", green: "#20834D", @@ -372,6 +381,9 @@ export const DARK: Theme = { state_label_halo: "#1f1f1f", country_label: "#5c5c5c", + housenumbers_label: "#525252", + house_numbers_label_halo: "#1f1f1f", + pois: { blue: "#4299BB", green: "#30C573", @@ -473,6 +485,9 @@ export const WHITE: Theme = { state_label: "#b3b3b3", state_label_halo: "#ffffff", country_label: "#b8b8b8", + + housenumbers_label: "#adadad", + house_numbers_label_halo: "#ffffff", }; export const GRAYSCALE: Theme = { @@ -554,6 +569,9 @@ export const GRAYSCALE: Theme = { state_label: "#999999", state_label_halo: "#cccccc", country_label: "#858585", + + housenumbers_label: "#999999", + house_numbers_label_halo: "#e0e0e0", }; export const BLACK: Theme = { @@ -635,6 +653,9 @@ export const BLACK: Theme = { state_label: "#3d3d3d", state_label_halo: "#141414", country_label: "#707070", + + housenumbers_label: "#525252", + house_numbers_label_halo: "#141414", }; const themes: Record = { diff --git a/tiles/src/main/java/com/protomaps/basemap/layers/Buildings.java b/tiles/src/main/java/com/protomaps/basemap/layers/Buildings.java index 6bd864ea..1ce6a35f 100644 --- a/tiles/src/main/java/com/protomaps/basemap/layers/Buildings.java +++ b/tiles/src/main/java/com/protomaps/basemap/layers/Buildings.java @@ -151,7 +151,6 @@ public List postProcess(int zoom, List i } } } - return FeatureMerge.mergeNearbyPolygons(items, 3.125, 3.125, 0.5, 0.5); } } diff --git a/tiles/src/main/java/com/protomaps/basemap/layers/Housenumbers.java b/tiles/src/main/java/com/protomaps/basemap/layers/Housenumbers.java index 1294f405..ee290cd1 100644 --- a/tiles/src/main/java/com/protomaps/basemap/layers/Housenumbers.java +++ b/tiles/src/main/java/com/protomaps/basemap/layers/Housenumbers.java @@ -1,29 +1,53 @@ package com.protomaps.basemap.layers; - import com.onthegomap.planetiler.FeatureCollector; +import com.onthegomap.planetiler.FeatureMerge; import com.onthegomap.planetiler.ForwardingProfile; import com.onthegomap.planetiler.VectorTile; import com.onthegomap.planetiler.geo.GeometryException; import com.onthegomap.planetiler.reader.SourceFeature; import com.protomaps.basemap.feature.FeatureId; +import com.onthegomap.planetiler.geo.GeometryType; +import com.protomaps.basemap.feature.NaturalEarthDb; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import java.util.List; +import java.util.*; public class Housenumbers implements ForwardingProfile.LayerPostProcesser { + private static final Logger LOGGER = LoggerFactory.getLogger(Housenumbers.class); + public void processOsm(SourceFeature sf, FeatureCollector features) { - if (sf.hasTag("addr:housenumber")) { - if (sf.isPoint()) { - features.point(this.name()) - .setId(FeatureId.create(sf)) - .setAttr("housenumber", sf.getString("addr:housenumber")) - .setZoomRange(10, 17); - } + if (!sf.hasTag("addr:housenumber")) { + return; + } + FeatureCollector.Feature feature = null; + if (sf.isPoint()) { + feature = features.point(this.name()); + } else if (sf.canBePolygon()) { + feature = features.centroid(this.name()); + } + if (feature != null) { + feature + .setId(FeatureId.create(sf)) + .setAttr("housenumber", sf.getString("addr:housenumber")) + .setAttr("street", sf.getString("addr:street")) + .setZoomRange(14, 15); } } @Override public List postProcess(int zoom, List items) throws GeometryException { - return items; + HashMap, List> grouped = new LinkedHashMap<>(); + for (VectorTile.Feature item : items) { + grouped.computeIfAbsent(item.tags(), k -> new ArrayList<>()).add(item); + } + + return grouped.values().stream().map(g -> { + var feature = g.getFirst(); + // drop `addr:street` to save space + feature.tags().remove("addr:street"); + return feature; + }).toList(); } @Override From 77a14c718c6399ac131dc054ddd7979f83c3ab62 Mon Sep 17 00:00:00 2001 From: Siarhei Fedartsou Date: Sat, 14 Dec 2024 09:53:39 +0100 Subject: [PATCH 3/4] Move housenumbers to buildings layer --- styles/src/base_layers.ts | 8 ++- .../java/com/protomaps/basemap/Basemap.java | 5 -- .../protomaps/basemap/layers/Buildings.java | 36 +++++++++++- .../basemap/layers/Housenumbers.java | 58 ------------------- 4 files changed, 40 insertions(+), 67 deletions(-) delete mode 100644 tiles/src/main/java/com/protomaps/basemap/layers/Housenumbers.java diff --git a/styles/src/base_layers.ts b/styles/src/base_layers.ts index 150e26cf..a4fb53ad 100644 --- a/styles/src/base_layers.ts +++ b/styles/src/base_layers.ts @@ -594,6 +594,7 @@ export function nolabels_layers( type: "fill", source: source, "source-layer": "buildings", + filter: ["!=", "kind", "address"], paint: { "fill-color": t.buildings, "fill-opacity": 0.5, @@ -1377,12 +1378,13 @@ export function labels_layers( id: "housenumbers_label", type: "symbol", source: source, - "source-layer": "housenumbers", - minzoom: 17, + "source-layer": "buildings", + minzoom: 18, + filter: ["==", "kind", "address"], layout: { "symbol-placement": "point", "text-font": [t.italic || "Noto Sans Italic"], - "text-field": ["get", "housenumber"], + "text-field": ["get", "addr_housenumber"], "text-size": 12 }, paint: { diff --git a/tiles/src/main/java/com/protomaps/basemap/Basemap.java b/tiles/src/main/java/com/protomaps/basemap/Basemap.java index ad172621..0c0db93f 100644 --- a/tiles/src/main/java/com/protomaps/basemap/Basemap.java +++ b/tiles/src/main/java/com/protomaps/basemap/Basemap.java @@ -16,7 +16,6 @@ import com.protomaps.basemap.layers.Roads; import com.protomaps.basemap.layers.Transit; import com.protomaps.basemap.layers.Water; -import com.protomaps.basemap.layers.Housenumbers; import com.protomaps.basemap.text.FontRegistry; import java.nio.file.Path; import java.util.HashMap; @@ -37,10 +36,6 @@ public Basemap(NaturalEarthDb naturalEarthDb, QrankDb qrankDb) { registerHandler(buildings); registerSourceHandler("osm", buildings::processOsm); - var housenumbers = new Housenumbers(); - registerHandler(housenumbers); - registerSourceHandler("osm", housenumbers::processOsm); - var landuse = new Landuse(); registerHandler(landuse); registerSourceHandler("osm", landuse::processOsm); diff --git a/tiles/src/main/java/com/protomaps/basemap/layers/Buildings.java b/tiles/src/main/java/com/protomaps/basemap/layers/Buildings.java index 1ce6a35f..73e95360 100644 --- a/tiles/src/main/java/com/protomaps/basemap/layers/Buildings.java +++ b/tiles/src/main/java/com/protomaps/basemap/layers/Buildings.java @@ -11,6 +11,7 @@ import com.onthegomap.planetiler.util.Parse; import com.protomaps.basemap.feature.FeatureId; import com.protomaps.basemap.postprocess.Area; + import java.util.List; import java.util.regex.Pattern; @@ -93,13 +94,46 @@ public void processOsm(SourceFeature sf, FeatureCollector features) { // Names should mostly just be for POIs // Sometimes building name and address are useful items, but only at zoom 17+ //OsmNames.setOsmNames(feature, sf, 13); + } else if (sf.hasTag("addr:housenumber")) { + FeatureCollector.Feature feature = null; + if (sf.isPoint()) { + feature = features.point(this.name()); + } else if (sf.canBePolygon()) { + feature = features.centroid(this.name()); + } + if (feature != null) { + feature + .setId(FeatureId.create(sf)) + .setAttr("addr_housenumber", sf.getString("addr:housenumber")) + .setAttr("addr_street", sf.getString("addr:street")) + .setAttr("kind", "address") + .setMinZoom(15); + } } } @Override public List postProcess(int zoom, List items) throws GeometryException { if (zoom == 15) { - return items; + List buildings = new ArrayList<>(); + + // deduplicate addresses + HashMap, List> groupedAddresses = new LinkedHashMap<>(); + for (VectorTile.Feature item : items) { + if (item.tags().containsKey("addr_housenumber")) { + groupedAddresses.computeIfAbsent(item.tags(), k -> new ArrayList<>()).add(item); + } else { + buildings.add(item); + } + } + + for (var address : groupedAddresses.values()) { + var feature = address.get(0); + feature.tags().remove("addr_street"); + buildings.add(feature); + } + + return buildings; } items = Area.filterArea(items, 0); diff --git a/tiles/src/main/java/com/protomaps/basemap/layers/Housenumbers.java b/tiles/src/main/java/com/protomaps/basemap/layers/Housenumbers.java deleted file mode 100644 index ee290cd1..00000000 --- a/tiles/src/main/java/com/protomaps/basemap/layers/Housenumbers.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.protomaps.basemap.layers; -import com.onthegomap.planetiler.FeatureCollector; -import com.onthegomap.planetiler.FeatureMerge; -import com.onthegomap.planetiler.ForwardingProfile; -import com.onthegomap.planetiler.VectorTile; -import com.onthegomap.planetiler.geo.GeometryException; -import com.onthegomap.planetiler.reader.SourceFeature; -import com.protomaps.basemap.feature.FeatureId; -import com.onthegomap.planetiler.geo.GeometryType; -import com.protomaps.basemap.feature.NaturalEarthDb; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; - -public class Housenumbers implements ForwardingProfile.LayerPostProcesser { - private static final Logger LOGGER = LoggerFactory.getLogger(Housenumbers.class); - - public void processOsm(SourceFeature sf, FeatureCollector features) { - if (!sf.hasTag("addr:housenumber")) { - return; - } - FeatureCollector.Feature feature = null; - if (sf.isPoint()) { - feature = features.point(this.name()); - } else if (sf.canBePolygon()) { - feature = features.centroid(this.name()); - } - if (feature != null) { - feature - .setId(FeatureId.create(sf)) - .setAttr("housenumber", sf.getString("addr:housenumber")) - .setAttr("street", sf.getString("addr:street")) - .setZoomRange(14, 15); - } - } - - @Override - public List postProcess(int zoom, List items) throws GeometryException { - HashMap, List> grouped = new LinkedHashMap<>(); - for (VectorTile.Feature item : items) { - grouped.computeIfAbsent(item.tags(), k -> new ArrayList<>()).add(item); - } - - return grouped.values().stream().map(g -> { - var feature = g.getFirst(); - // drop `addr:street` to save space - feature.tags().remove("addr:street"); - return feature; - }).toList(); - } - - @Override - public String name() { - return "housenumbers"; - } - -} From 752ce43c5a2fccc79a72be9bb2802a36bd199211 Mon Sep 17 00:00:00 2001 From: Siarhei Fedartsou Date: Sun, 15 Dec 2024 21:02:14 +0100 Subject: [PATCH 4/4] add imports --- .../src/main/java/com/protomaps/basemap/layers/Buildings.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tiles/src/main/java/com/protomaps/basemap/layers/Buildings.java b/tiles/src/main/java/com/protomaps/basemap/layers/Buildings.java index 73e95360..11499de0 100644 --- a/tiles/src/main/java/com/protomaps/basemap/layers/Buildings.java +++ b/tiles/src/main/java/com/protomaps/basemap/layers/Buildings.java @@ -13,6 +13,10 @@ import com.protomaps.basemap.postprocess.Area; import java.util.List; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.regex.Pattern; public class Buildings implements ForwardingProfile.LayerPostProcesser {