diff --git a/sprites/flavors/dark.json b/sprites/flavors/dark.json index 212eed4b2..498823e80 100644 --- a/sprites/flavors/dark.json +++ b/sprites/flavors/dark.json @@ -39,6 +39,7 @@ "nature_reserve": "green", "aerodrome": "lapis", "train_station": "lapis", + "aerialway": "lapis", "bus_stop": "lapis", "ferry_terminal": "lapis", "stadium": "slategray", @@ -65,4 +66,4 @@ "theatre": "pink", "artwork": "pink" } -} \ No newline at end of file +} diff --git a/sprites/flavors/light.json b/sprites/flavors/light.json index 888f71d2c..c11fb973f 100644 --- a/sprites/flavors/light.json +++ b/sprites/flavors/light.json @@ -39,6 +39,7 @@ "nature_reserve": "green", "aerodrome": "lapis", "train_station": "lapis", + "aerialway": "lapis", "bus_stop": "lapis", "ferry_terminal": "lapis", "stadium": "slategray", @@ -65,4 +66,4 @@ "theatre": "pink", "artwork": "pink" } -} \ No newline at end of file +} diff --git a/styles/src/base_layers.ts b/styles/src/base_layers.ts index 65980120f..d8f6cdff0 100644 --- a/styles/src/base_layers.ts +++ b/styles/src/base_layers.ts @@ -1061,6 +1061,29 @@ export function nolabels_layers( ], }, }, + { + id: "roads_aerialway", + type: "line", + source: source, + "source-layer": "roads", + filter: ["==", "kind", "aerialway"], + paint: { + "line-color": t.railway, + "line-dasharray": [4, 1], + "line-opacity": 0.5, + "line-width": [ + "interpolate", + ["exponential", 1.6], + ["zoom"], + 3, + 0, + 6, + 0.15, + 18, + 9, + ], + }, + }, { id: "boundaries_country", type: "line", @@ -1438,6 +1461,29 @@ export function labels_layers( "symbol-spacing": 100, }, }, + { + id: "roads_labels_aerialway", + type: "symbol", + source: source, + "source-layer": "roads", + minzoom: 13, + filter: ["==", "kind", "aerialway"], + layout: { + "symbol-placement": "line", + "text-font": [t.regular || "Noto Sans Regular"], + "text-field": get_multiline_name( + lang, + script, + t.regular, + ) as DataDrivenPropertyValueSpecification, + "text-size": 12, + }, + paint: { + "text-color": t.roads_label_minor, + "text-halo-color": t.roads_label_minor_halo, + "text-halo-width": 1, + }, + }, { id: "roads_labels_minor", type: "symbol", @@ -1662,9 +1708,14 @@ export function labels_layers( ], layout: { "icon-image": [ - "match", - ["get", "kind"], - "station", + "case", + [ + "all", + ["==", ["get", "kind"], "station"], + ["==", ["get", "kind_detail"], "aerialway"], + ], + "aerialway", + ["==", ["get", "kind"], "station"], "train_station", ["get", "kind"], ], diff --git a/tiles/src/main/java/com/protomaps/basemap/layers/Pois.java b/tiles/src/main/java/com/protomaps/basemap/layers/Pois.java index 21a420ec3..aab8e6811 100644 --- a/tiles/src/main/java/com/protomaps/basemap/layers/Pois.java +++ b/tiles/src/main/java/com/protomaps/basemap/layers/Pois.java @@ -85,6 +85,7 @@ static Integer parseElevation(String elevation) { rule( Expression.or( with("aeroway", "aerodrome"), + with("aerialway", "station"), with("amenity"), with("attraction"), with("boundary", "national_park", "protected_area"), @@ -190,7 +191,13 @@ static Integer parseElevation(String elevation) { rule(with("sport"), use("pm:kindDetail", fromTag("sport"))), rule(with("religion"), use("pm:kindDetail", fromTag("religion"))), - rule(with("cuisine"), use("pm:kindDetail", fromTag("cuisine"))) + rule(with("cuisine"), use("pm:kindDetail", fromTag("cuisine"))), + // Keep explicit aerialway stations ahead of generic railway classification on dual-tagged features. + rule( + with("aerialway", "station"), + use("pm:kind", fromTag("aerialway")), + use("pm:kindDetail", "aerialway") + ) )).index(); diff --git a/tiles/src/main/java/com/protomaps/basemap/layers/Roads.java b/tiles/src/main/java/com/protomaps/basemap/layers/Roads.java index 03be0498a..69963778c 100644 --- a/tiles/src/main/java/com/protomaps/basemap/layers/Roads.java +++ b/tiles/src/main/java/com/protomaps/basemap/layers/Roads.java @@ -129,11 +129,29 @@ public Roads(CountryCoder countryCoder) { use("minZoom", 13) ), rule( - with("aerialway", "cable_car"), + with("aerialway", "cable_car", "gondola", "mixed_lift"), use("kind", "aerialway"), - use("kindDetail", "cable_car"), + use("kindDetail", fromTag("aerialway")), use("minZoom", 11) ), + rule( + with("aerialway", "chair_lift"), + use("kind", "aerialway"), + use("kindDetail", fromTag("aerialway")), + use("minZoom", 12) + ), + rule( + with("aerialway", "drag_lift", "t-bar", "j-bar", "platter", "rope_tow"), + use("kind", "aerialway"), + use("kindDetail", fromTag("aerialway")), + use("minZoom", 13) + ), + rule( + with("aerialway", "magic_carpet", "zip_line", "goods"), + use("kind", "aerialway"), + use("kindDetail", fromTag("aerialway")), + use("minZoom", 14) + ), rule( with("man_made", "pier"), use("kind", "path"), diff --git a/tiles/src/test/java/com/protomaps/basemap/layers/PoisTest.java b/tiles/src/test/java/com/protomaps/basemap/layers/PoisTest.java index 26e417459..e1550123f 100644 --- a/tiles/src/test/java/com/protomaps/basemap/layers/PoisTest.java +++ b/tiles/src/test/java/com/protomaps/basemap/layers/PoisTest.java @@ -1083,6 +1083,33 @@ void kind_station_generic() { ))); } + @Test + void aerialwayStationNode() { + assertFeatures(15, + List.of(Map.of("kind", "station", "kind_detail", "aerialway", "min_zoom", 16)), + process(SimpleFeature.create( + newPoint(1, 1), + new HashMap<>(Map.of("aerialway", "station")), + "osm", null, 0 + ))); + } + + @Test + void aerialwayStationArea() { + assertFeatures(15, + List.of(Map.of( + "kind", "station", + "kind_detail", "aerialway", + "name", "Valley station", + "min_zoom", 16 + )), + process(SimpleFeature.create( + AREA_127_SQ_M, + new HashMap<>(Map.of("aerialway", "station", "name", "Valley station")), + "osm", null, 0 + ))); + } + @Test void kind_bakery_generic() { assertFeatures(15, diff --git a/tiles/src/test/java/com/protomaps/basemap/layers/RoadsTest.java b/tiles/src/test/java/com/protomaps/basemap/layers/RoadsTest.java index f39aadefd..444ed574e 100644 --- a/tiles/src/test/java/com/protomaps/basemap/layers/RoadsTest.java +++ b/tiles/src/test/java/com/protomaps/basemap/layers/RoadsTest.java @@ -459,16 +459,30 @@ void testRailwayDisused() { ); } - @Test - void testAerialwayCableCar() { + @ParameterizedTest + @CsvSource({ + "cable_car, 11", + "gondola, 11", + "mixed_lift, 11", + "chair_lift, 12", + "drag_lift, 13", + "t-bar, 13", + "j-bar, 13", + "platter, 13", + "rope_tow, 13", + "magic_carpet, 14", + "zip_line, 14", + "goods, 14" + }) + void testAerialways(String aerialway, int minZoom) { assertFeatures(12, List.of(Map.of("kind", "aerialway", - "kind_detail", "cable_car", - "_minzoom", 11 + "kind_detail", aerialway, + "_minzoom", minZoom )), processWithRelationAndCoords("", 0, 0, 1, 1, - "aerialway", "cable_car" + "aerialway", aerialway ) ); }