From 3d8ea2d72aa80915e14e43b392208307694ab1c7 Mon Sep 17 00:00:00 2001 From: Jannik Date: Mon, 5 Jan 2026 14:49:46 +0100 Subject: [PATCH] feat: add raw layer at z15, exclude everything else from z15 --- .../org/openmaptiles/addons/ExtraLayers.java | 1 + .../java/org/openmaptiles/addons/Raw.java | 89 +++++++++++++++++++ .../openmaptiles/layers/AerodromeLabel.java | 1 + .../java/org/openmaptiles/layers/Aeroway.java | 3 + .../org/openmaptiles/layers/Boundary.java | 9 +- .../org/openmaptiles/layers/Building.java | 1 + .../org/openmaptiles/layers/Housenumber.java | 3 +- .../org/openmaptiles/layers/Landcover.java | 5 +- .../java/org/openmaptiles/layers/Landuse.java | 3 +- .../org/openmaptiles/layers/MountainPeak.java | 2 + .../java/org/openmaptiles/layers/Park.java | 5 +- .../java/org/openmaptiles/layers/Place.java | 10 ++- .../java/org/openmaptiles/layers/Poi.java | 3 +- .../openmaptiles/layers/Transportation.java | 13 ++- .../layers/TransportationName.java | 12 ++- .../java/org/openmaptiles/layers/Water.java | 4 +- .../org/openmaptiles/layers/WaterName.java | 6 +- .../org/openmaptiles/layers/Waterway.java | 1 + 18 files changed, 148 insertions(+), 23 deletions(-) create mode 100644 src/main/java/org/openmaptiles/addons/Raw.java diff --git a/src/main/java/org/openmaptiles/addons/ExtraLayers.java b/src/main/java/org/openmaptiles/addons/ExtraLayers.java index d111163..0f66ad3 100644 --- a/src/main/java/org/openmaptiles/addons/ExtraLayers.java +++ b/src/main/java/org/openmaptiles/addons/ExtraLayers.java @@ -14,6 +14,7 @@ public class ExtraLayers { public static List create(Translations translations, PlanetilerConfig config, Stats stats) { return List.of( // Create classes that extend Layer interface in the addons package, then instantiate them here + new Raw() ); } } diff --git a/src/main/java/org/openmaptiles/addons/Raw.java b/src/main/java/org/openmaptiles/addons/Raw.java new file mode 100644 index 0000000..b25e769 --- /dev/null +++ b/src/main/java/org/openmaptiles/addons/Raw.java @@ -0,0 +1,89 @@ +package org.openmaptiles.addons; + +import com.onthegomap.planetiler.FeatureCollector; +import com.onthegomap.planetiler.reader.SourceFeature; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import org.openmaptiles.Layer; +import org.openmaptiles.OpenMapTilesProfile; + +public class Raw implements Layer, OpenMapTilesProfile.OsmAllProcessor { + + public static List TAG_WHITELIST = Arrays.asList("amenity", "shop", "name", "opening_hours", "email", "website", "phone", "internet_access", "wheelchair", "cuisine", "indoor_seating", "outdoor_seating", "takeaway", "drive_through"); + public static List TAG_PREFIX_WHITELIST = Arrays.asList("addr:", "contact:", "payment:", "wheelchair:", "fuel:", "internet_access:"); + + @Override + public String name() { + return "raw"; + } + + @Override + public void processAllOsm(SourceFeature feature, FeatureCollector features) { + boolean hasTag = false; + for (Map.Entry i : feature.tags().entrySet()) { + if (TAG_WHITELIST.contains(i.getKey())) { + hasTag = true; + break; + } + for (String prefix : TAG_PREFIX_WHITELIST) { + if(i.getKey().startsWith(prefix)) { + hasTag = true; + break; + } + } + } + + if(!hasTag) return; + + if(feature.canBePolygon()) { + FeatureCollector.Feature ft = features.polygon("raw") + .setBufferPixels(4) + .setMinZoom(15); + + for (Map.Entry i : feature.tags().entrySet()) { + if (TAG_WHITELIST.contains(i.getKey())) { + ft.setAttr(i.getKey(), i.getValue()); + } + for (String prefix : TAG_PREFIX_WHITELIST) { + if(i.getKey().startsWith(prefix)) { + ft.setAttr(i.getKey(), i.getValue()); + break; + } + } + } + } else if(feature.canBeLine()) { + FeatureCollector.Feature ft = features.line("raw") + .setBufferPixels(4) + .setMinZoom(15); + + for (Map.Entry i : feature.tags().entrySet()) { + if (TAG_WHITELIST.contains(i.getKey())) { + ft.setAttr(i.getKey(), i.getValue()); + } + for (String prefix : TAG_PREFIX_WHITELIST) { + if(i.getKey().startsWith(prefix)) { + ft.setAttr(i.getKey(), i.getValue()); + break; + } + } + } + } else if(feature.isPoint()) { + FeatureCollector.Feature ft = features.point("raw") + .setBufferPixels(4) + .setMinZoom(15); + + for(Map.Entry i : feature.tags().entrySet()) { + if(TAG_WHITELIST.contains(i.getKey())) { + ft.setAttr(i.getKey(), i.getValue()); + } + for (String prefix : TAG_PREFIX_WHITELIST) { + if(i.getKey().startsWith(prefix)) { + ft.setAttr(i.getKey(), i.getValue()); + break; + } + } + } + } + } +} diff --git a/src/main/java/org/openmaptiles/layers/AerodromeLabel.java b/src/main/java/org/openmaptiles/layers/AerodromeLabel.java index 7f5b39c..727024a 100644 --- a/src/main/java/org/openmaptiles/layers/AerodromeLabel.java +++ b/src/main/java/org/openmaptiles/layers/AerodromeLabel.java @@ -74,6 +74,7 @@ public class AerodromeLabel implements features.centroid(LAYER_NAME) .setBufferPixels(BUFFER_SIZE) .setMinZoom(important ? 8 : 10) + .setMaxZoom(14) .putAttrs(OmtLanguageUtils.getNames(element.source().tags(), translations)) .putAttrs(Utils.elevationTags(element.ele())) .setAttr(Fields.IATA, nullIfEmpty(element.iata())) diff --git a/src/main/java/org/openmaptiles/layers/Aeroway.java b/src/main/java/org/openmaptiles/layers/Aeroway.java index 1f45f44..69eb350 100644 --- a/src/main/java/org/openmaptiles/layers/Aeroway.java +++ b/src/main/java/org/openmaptiles/layers/Aeroway.java @@ -60,6 +60,7 @@ public class Aeroway implements public void process(Tables.OsmAerowayPolygon element, FeatureCollector features) { features.polygon(LAYER_NAME) .setMinZoom(10) + .setMaxZoom(14) .setMinPixelSize(2) .setAttr(Fields.CLASS, element.aeroway()) .setAttr(Fields.REF, element.ref()); @@ -69,6 +70,7 @@ public class Aeroway implements public void process(Tables.OsmAerowayLinestring element, FeatureCollector features) { features.line(LAYER_NAME) .setMinZoom(10) + .setMaxZoom(14) .setAttr(Fields.CLASS, element.aeroway()) .setAttr(Fields.REF, element.ref()); } @@ -77,6 +79,7 @@ public class Aeroway implements public void process(Tables.OsmAerowayPoint element, FeatureCollector features) { features.point(LAYER_NAME) .setMinZoom(14) + .setMaxZoom(14) .setAttr(Fields.CLASS, element.aeroway()) .setAttr(Fields.REF, element.ref()); } diff --git a/src/main/java/org/openmaptiles/layers/Boundary.java b/src/main/java/org/openmaptiles/layers/Boundary.java index 3b801db..90014c0 100644 --- a/src/main/java/org/openmaptiles/layers/Boundary.java +++ b/src/main/java/org/openmaptiles/layers/Boundary.java @@ -207,7 +207,7 @@ public class Boundary implements }; if (info != null) { features.line(LAYER_NAME).setBufferPixels(BUFFER_SIZE) - .setZoomRange(info.minzoom, info.maxzoom) + .setZoomRange(info.minzoom, Math.max(info.maxzoom, 14)) .setMinPixelSizeAtAllZooms(0) .setAttr(Fields.ADMIN_LEVEL, info.adminLevel) .setAttr(Fields.MARITIME, 0) @@ -320,6 +320,7 @@ public class Boundary implements .setAttr(Fields.MARITIME, maritime ? 1 : 0) .setMinPixelSizeAtAllZooms(0) .setMinZoom(minzoom) + .setMaxZoom(14) .setAttr(Fields.CLAIMED_BY, claimedBy) .setAttr(Fields.DISPUTED_NAME, editName(disputedName)); } @@ -333,7 +334,8 @@ public class Boundary implements .putAttrs(OmtLanguageUtils.getNames(element.source().tags(), translations)) .setAttr(OpenMapTilesSchema.Boundary.Fields.CLASS, element.boundary()) .setMinPixelSizeBelowZoom(13, 4) // for Z4: `sql_filter: area>power(ZRES3,2)`, etc. - .setMinZoom(4); + .setMinZoom(4) + .setMaxZoom(14); } @Override @@ -362,7 +364,8 @@ public class Boundary implements .setAttr(Fields.CLAIMED_BY, key.claimedBy) .setAttr(Fields.DISPUTED_NAME, key.disputed ? editName(key.name) : null) .setMinPixelSizeAtAllZooms(0) - .setMinZoom(key.minzoom); + .setMinZoom(key.minzoom) + .setMaxZoom(14); if (key.adminLevel == 2 && !key.disputed) { // only non-disputed admin 2 boundaries get to have adm0_{l,r}, at zoom 5 and more newFeature diff --git a/src/main/java/org/openmaptiles/layers/Building.java b/src/main/java/org/openmaptiles/layers/Building.java index d255ea8..db6f290 100644 --- a/src/main/java/org/openmaptiles/layers/Building.java +++ b/src/main/java/org/openmaptiles/layers/Building.java @@ -161,6 +161,7 @@ public class Building implements if (renderHeight < 3660 && renderMinHeight < 3660) { var feature = features.polygon(LAYER_NAME).setBufferPixels(BUFFER_SIZE) .setMinZoom(13) + .setMaxZoom(14) .setMinPixelSize(2) .setAttrWithMinzoom(Fields.RENDER_HEIGHT, renderHeight, 14) .setAttrWithMinzoom(Fields.RENDER_MIN_HEIGHT, renderMinHeight, 14) diff --git a/src/main/java/org/openmaptiles/layers/Housenumber.java b/src/main/java/org/openmaptiles/layers/Housenumber.java index 85f487e..81ce887 100644 --- a/src/main/java/org/openmaptiles/layers/Housenumber.java +++ b/src/main/java/org/openmaptiles/layers/Housenumber.java @@ -137,7 +137,8 @@ public class Housenumber implements .setAttr(Fields.HOUSENUMBER, housenumber) .setAttr(TEMP_PARTITION, partition) .setAttr(TEMP_HAS_NAME, hasName) - .setMinZoom(14); + .setMinZoom(14) + .setMaxZoom(14); } @Override diff --git a/src/main/java/org/openmaptiles/layers/Landcover.java b/src/main/java/org/openmaptiles/layers/Landcover.java index c06fa5c..8665912 100644 --- a/src/main/java/org/openmaptiles/layers/Landcover.java +++ b/src/main/java/org/openmaptiles/layers/Landcover.java @@ -114,7 +114,7 @@ public class Landcover implements features.polygon(LAYER_NAME).setBufferPixels(BUFFER_SIZE) .setAttr(Fields.CLASS, clazz) .setAttr(Fields.SUBCLASS, info.subclass) - .setZoomRange(info.minzoom, info.maxzoom); + .setZoomRange(info.minzoom, Math.max(info.maxzoom, 14)); } } } @@ -131,7 +131,8 @@ public class Landcover implements .setAttr(Fields.CLASS, clazz) .setAttr(Fields.SUBCLASS, subclass) .setNumPointsAttr(TEMP_NUM_POINTS_ATTR) - .setMinZoom(7); + .setMinZoom(7) + .setMaxZoom(14); } } diff --git a/src/main/java/org/openmaptiles/layers/Landuse.java b/src/main/java/org/openmaptiles/layers/Landuse.java index 44839a0..160f024 100644 --- a/src/main/java/org/openmaptiles/layers/Landuse.java +++ b/src/main/java/org/openmaptiles/layers/Landuse.java @@ -120,7 +120,8 @@ public class Landuse implements } var feature = features.polygon(LAYER_NAME).setBufferPixels(BUFFER_SIZE) .setAttr(Fields.CLASS, clazz) - .setMinZoom(Z6_CLASSES.contains(clazz) ? 6 : 9); + .setMinZoom(Z6_CLASSES.contains(clazz) ? 6 : 9) + .setMaxZoom(14); if (FieldValues.CLASS_RESIDENTIAL.equals(clazz)) { feature .setMinPixelSize(0.1) diff --git a/src/main/java/org/openmaptiles/layers/MountainPeak.java b/src/main/java/org/openmaptiles/layers/MountainPeak.java index 37f5606..bbd3a21 100644 --- a/src/main/java/org/openmaptiles/layers/MountainPeak.java +++ b/src/main/java/org/openmaptiles/layers/MountainPeak.java @@ -126,6 +126,7 @@ public class MountainPeak implements (nullIfEmpty(element.name()) != null ? 10_000 : 0) ) .setMinZoom(7) + .setMaxZoom(14) // need to use a larger buffer size to allow enough points through to not cut off // any label grid squares which could lead to inconsistent label ranks for a feature // in adjacent tiles. postProcess() will remove anything outside the desired buffer. @@ -150,6 +151,7 @@ public class MountainPeak implements .putAttrs(OmtLanguageUtils.getNames(element.source().tags(), translations)) .setSortKey(rank) .setMinZoom(13) + .setMaxZoom(14) .setBufferPixels(100); } diff --git a/src/main/java/org/openmaptiles/layers/Park.java b/src/main/java/org/openmaptiles/layers/Park.java index 40b1562..96fd752 100644 --- a/src/main/java/org/openmaptiles/layers/Park.java +++ b/src/main/java/org/openmaptiles/layers/Park.java @@ -100,7 +100,8 @@ public class Park implements var outline = features.polygon(LAYER_NAME).setBufferPixels(BUFFER_SIZE) .setAttrWithMinzoom(Fields.CLASS, clazz, 5) .setMinPixelSize(2) - .setMinZoom(4); + .setMinZoom(4) + .setMaxZoom(14); // park name label point (if it has one) if (element.name() != null) { @@ -122,7 +123,7 @@ public class Park implements .thenByTruesFirst(element.source().hasTag("wikipedia") || element.source().hasTag("wikidata")) .thenByLog(area, 1d, SMALLEST_PARK_WORLD_AREA, 1 << (SORT_KEY_BITS - 2) - 1) .get() - ).setMinZoom(minzoom); + ).setMinZoom(minzoom).setMaxZoom(14); } catch (GeometryException e) { e.log(stats, "omt_park_area", "Unable to get park area for " + element.source().id()); } diff --git a/src/main/java/org/openmaptiles/layers/Place.java b/src/main/java/org/openmaptiles/layers/Place.java index 8fcd17f..2f156ea 100644 --- a/src/main/java/org/openmaptiles/layers/Place.java +++ b/src/main/java/org/openmaptiles/layers/Place.java @@ -247,6 +247,7 @@ public class Place implements .setAttr(Fields.CLASS, FieldValues.CLASS_COUNTRY) .setAttr(Fields.RANK, rank) .setMinZoom(rank - 1) + .setMaxZoom(14) .setSortKey(rank); } catch (GeometryException e) { e.log(stats, "omt_place_country", @@ -274,6 +275,7 @@ public class Place implements // TODO: This starts including every "state" point at z2, even before many countries show up. // Instead we might want to set state min zooms based on rank from natural earth? .setMinZoom(2) + .setMaxZoom(14) .setSortKey(rank); } } catch (GeometryException e) { @@ -294,6 +296,7 @@ public class Place implements .setAttr(Fields.CLASS, "island") .setAttr(Fields.RANK, rank) .setMinZoom(minzoom) + .setMaxZoom(14) .setSortKey(SortKey.orderByLog(area, 1d, MIN_ISLAND_WORLD_AREA).get()); } catch (GeometryException e) { e.log(stats, "omt_place_island_poly", @@ -307,7 +310,8 @@ public class Place implements .putAttrs(OmtLanguageUtils.getNames(element.source().tags(), translations)) .setAttr(Fields.CLASS, "island") .setAttr(Fields.RANK, 7) - .setMinZoom(12); + .setMinZoom(12) + .setMaxZoom(14); } @Override @@ -355,6 +359,7 @@ public class Place implements .setAttr(Fields.CLASS, element.place()) .setAttr(Fields.RANK, rank) .setMinZoom(minzoom) + .setMaxZoom(14) .setSortKey(getSortKey(rank, placeType, element.population(), element.name())) .setPointLabelGridPixelSize(12, 128); @@ -383,7 +388,8 @@ public class Place implements .putAttrs(OmtLanguageUtils.getNames(element.source().tags(), translations)) .setAttr(OpenMapTilesSchema.Boundary.Fields.CLASS, element.boundary()) .setAttr(Fields.RANK, rank) - .setMinZoom(minzoom); + .setMinZoom(minzoom) + .setMaxZoom(14); } catch (GeometryException e) { e.log(stats, "omt_boundary_poly", "Unable to get point for OSM boundary polygon " + element.source().id()); diff --git a/src/main/java/org/openmaptiles/layers/Poi.java b/src/main/java/org/openmaptiles/layers/Poi.java index bc93e62..fcd2314 100644 --- a/src/main/java/org/openmaptiles/layers/Poi.java +++ b/src/main/java/org/openmaptiles/layers/Poi.java @@ -321,7 +321,8 @@ public class Poi implements .putAttrs(OmtLanguageUtils.getNames(element.source().tags(), translations)) .setPointLabelGridPixelSize(14, 64) .setSortKey(rankOrder) - .setMinZoom(minzoom); + .setMinZoom(minzoom) + .setMaxZoom(14); } @Override diff --git a/src/main/java/org/openmaptiles/layers/Transportation.java b/src/main/java/org/openmaptiles/layers/Transportation.java index 7724aae..6c56996 100644 --- a/src/main/java/org/openmaptiles/layers/Transportation.java +++ b/src/main/java/org/openmaptiles/layers/Transportation.java @@ -519,7 +519,8 @@ public class Transportation implements .setAttrWithMinzoom(Fields.SURFACE, surface(coalesce(element.surface(), element.tracktype())), 12) .setMinPixelSize(0) // merge during post-processing, then limit by size .setSortKey(element.zOrder()) - .setMinZoom(minzoom); + .setMinZoom(minzoom) + .setMaxZoom(14); if (isFootwayOrSteps(highway)) { feature @@ -616,7 +617,8 @@ public class Transportation implements .setAttrWithMinzoom(Fields.LAYER, nullIfLong(element.layer(), 0), 9) .setSortKey(element.zOrder()) .setMinPixelSize(0) // merge during post-processing, then limit by size - .setMinZoom(minzoom); + .setMinZoom(minzoom) + .setMaxZoom(14); } } @@ -632,7 +634,8 @@ public class Transportation implements .setAttr(Fields.LAYER, nullIfLong(element.layer(), 0)) .setSortKey(element.zOrder()) .setMinPixelSize(0) // merge during post-processing, then limit by size - .setMinZoom(12); + .setMinZoom(12) + .setMaxZoom(14); } @Override @@ -647,6 +650,7 @@ public class Transportation implements .setSortKey(element.zOrder()) .setMinPixelSize(0) // merge during post-processing, then limit by size .setMinZoom(4) + .setMaxZoom(14) .setMinPixelSizeBelowZoom(10, 32); // `sql_filter: ST_Length(...)` used in OpenMapTiles translates to 32px } @@ -665,7 +669,8 @@ public class Transportation implements .setAttr(Fields.BRUNNEL, brunnel("bridge".equals(manMade), false, false)) .setAttr(Fields.LAYER, nullIfLong(element.layer(), 0)) .setSortKey(element.zOrder()) - .setMinZoom(13); + .setMinZoom(13) + .setMaxZoom(14); } } } diff --git a/src/main/java/org/openmaptiles/layers/TransportationName.java b/src/main/java/org/openmaptiles/layers/TransportationName.java index a861dd0..cb8438d 100644 --- a/src/main/java/org/openmaptiles/layers/TransportationName.java +++ b/src/main/java/org/openmaptiles/layers/TransportationName.java @@ -204,7 +204,8 @@ public class TransportationName implements .setAttr(Fields.SUBCLASS, subclass) .setAttr(Fields.LAYER, nullIfLong(element.layer(), 0)) .setSortKeyDescending(element.zOrder()) - .setMinZoom(10); + .setMinZoom(10) + .setMaxZoom(14); } } } @@ -267,7 +268,8 @@ public class TransportationName implements .setAttr(Fields.SUBCLASS, highwaySubclass(highwayClass, null, highway)) .setMinPixelSize(0) .setSortKey(element.zOrder()) - .setMinZoom(minzoom); + .setMinZoom(minzoom) + .setMaxZoom(14); // populate route_1_, route_2_, ... route_n_ tags and remove duplicates Set routes = new HashSet<>(); @@ -322,7 +324,8 @@ public class TransportationName implements .setAttr(Fields.SUBCLASS, element.aerialway()) .setMinPixelSize(0) .setSortKey(element.zOrder()) - .setMinZoom(12); + .setMinZoom(12) + .setMaxZoom(14); } } @@ -336,7 +339,8 @@ public class TransportationName implements .setAttr(Fields.CLASS, element.shipway()) .setMinPixelSize(0) .setSortKey(element.zOrder()) - .setMinZoom(12); + .setMinZoom(12) + .setMaxZoom(14); } } diff --git a/src/main/java/org/openmaptiles/layers/Water.java b/src/main/java/org/openmaptiles/layers/Water.java index c0c3359..4b34568 100644 --- a/src/main/java/org/openmaptiles/layers/Water.java +++ b/src/main/java/org/openmaptiles/layers/Water.java @@ -166,7 +166,8 @@ public class Water implements features.polygon(LAYER_NAME) .setBufferPixels(BUFFER_SIZE) .setAttr(Fields.CLASS, FieldValues.CLASS_OCEAN) - .setMinZoom(6); + .setMinZoom(6) + .setMaxZoom(14); } @Override @@ -177,6 +178,7 @@ public class Water implements .setBufferPixels(BUFFER_SIZE) .setMinPixelSizeBelowZoom(11, 2) .setMinZoom(6) + .setMaxZoom(14) .setAttr(Fields.ID, element.source().id()) .setAttr(Fields.INTERMITTENT, element.isIntermittent() ? 1 : 0) .setAttrWithMinzoom(Fields.BRUNNEL, Utils.brunnel(element.isBridge(), element.isTunnel()), 12) diff --git a/src/main/java/org/openmaptiles/layers/WaterName.java b/src/main/java/org/openmaptiles/layers/WaterName.java index bd48b18..df6b8b5 100644 --- a/src/main/java/org/openmaptiles/layers/WaterName.java +++ b/src/main/java/org/openmaptiles/layers/WaterName.java @@ -210,7 +210,8 @@ public class WaterName implements .putAttrs(OmtLanguageUtils.getNames(source.tags(), translations)) .setAttr(Fields.CLASS, clazz) .setAttr(Fields.INTERMITTENT, element.isIntermittent() ? 1 : 0) - .setMinZoom(minZoom); + .setMinZoom(minZoom) + .setMaxZoom(14); } } @@ -258,7 +259,8 @@ public class WaterName implements .setBufferPixels(BUFFER_SIZE) .putAttrs(OmtLanguageUtils.getNames(element.source().tags(), translations)) .setAttr(Fields.INTERMITTENT, element.isIntermittent() ? 1 : 0) - .setMinZoom(minzoom); + .setMinZoom(minzoom) + .setMaxZoom(14); return output; } diff --git a/src/main/java/org/openmaptiles/layers/Waterway.java b/src/main/java/org/openmaptiles/layers/Waterway.java index a70c859..a20417f 100644 --- a/src/main/java/org/openmaptiles/layers/Waterway.java +++ b/src/main/java/org/openmaptiles/layers/Waterway.java @@ -195,6 +195,7 @@ public class Waterway implements .setAttr(Fields.CLASS, element.waterway()) .putAttrs(OmtLanguageUtils.getNames(element.source().tags(), translations)) .setMinZoom(minzoom) + .setMaxZoom(14) // details only at higher zoom levels so that named rivers can be merged more aggressively .setAttrWithMinzoom(Fields.BRUNNEL, Utils.brunnel(element.isBridge(), element.isTunnel()), 12) .setAttrWithMinzoom(Fields.INTERMITTENT, element.isIntermittent() ? 1 : 0, 12)