summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--benchmark/api/render.benchmark.cpp13
-rw-r--r--benchmark/fixtures/api/style_formatted_labels.json3993
-rw-r--r--benchmark/parse/filter.benchmark.cpp2
-rw-r--r--include/mbgl/style/expression/expression.hpp17
-rw-r--r--include/mbgl/style/expression/format_expression.hpp17
-rw-r--r--include/mbgl/style/expression/format_section_override.hpp82
-rw-r--r--include/mbgl/style/expression/formatted.hpp16
-rw-r--r--include/mbgl/style/property_expression.hpp103
-rwxr-xr-xscripts/generate-style-code.js25
-rw-r--r--src/core-files.json2
-rw-r--r--src/mbgl/layout/symbol_layout.cpp138
-rw-r--r--src/mbgl/layout/symbol_layout.hpp32
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp29
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.hpp20
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.cpp2
-rw-r--r--src/mbgl/renderer/paint_property_binder.hpp36
-rw-r--r--src/mbgl/style/conversion/function.cpp2
-rw-r--r--src/mbgl/style/expression/dsl.cpp6
-rw-r--r--src/mbgl/style/expression/format_expression.cpp62
-rw-r--r--src/mbgl/style/expression/formatted.cpp36
-rw-r--r--src/mbgl/style/expression/is_constant.cpp10
-rw-r--r--src/mbgl/style/layers/layer_properties.hpp.ejs5
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.cpp15
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.hpp98
-rw-r--r--src/mbgl/style/layers/symbol_layer_properties.hpp5
-rw-r--r--src/mbgl/style/layout_property.hpp2
-rw-r--r--src/mbgl/style/light_impl.hpp1
-rw-r--r--src/mbgl/style/paint_property.hpp7
-rw-r--r--src/mbgl/style/properties.hpp4
-rw-r--r--src/mbgl/style/property_expression.cpp68
-rw-r--r--src/mbgl/text/glyph.hpp8
-rw-r--r--src/mbgl/text/quads.cpp2
-rw-r--r--src/mbgl/text/quads.hpp7
-rw-r--r--src/mbgl/text/shaping.cpp7
-rw-r--r--src/mbgl/text/tagged_string.cpp7
-rw-r--r--src/mbgl/text/tagged_string.hpp20
-rw-r--r--test/style/property_expression.test.cpp50
-rw-r--r--test/style/style_layer.test.cpp87
-rw-r--r--test/text/tagged_string.test.cpp10
-rw-r--r--test/util/merge_lines.test.cpp2
40 files changed, 4792 insertions, 256 deletions
diff --git a/benchmark/api/render.benchmark.cpp b/benchmark/api/render.benchmark.cpp
index 8709f18d9c..f74a31647c 100644
--- a/benchmark/api/render.benchmark.cpp
+++ b/benchmark/api/render.benchmark.cpp
@@ -51,6 +51,18 @@ static void API_renderStill_reuse_map(::benchmark::State& state) {
}
}
+static void API_renderStill_reuse_map_formatted_labels(::benchmark::State& state) {
+ RenderBenchmark bench;
+ HeadlessFrontend frontend { { 1000, 1000 }, 1, bench.fileSource, bench.threadPool };
+ Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1,
+ bench.fileSource, bench.threadPool, MapOptions().withMapMode(MapMode::Static) };
+ prepare(map, util::read_file("benchmark/fixtures/api/style_formatted_labels.json"));
+
+ while (state.KeepRunning()) {
+ frontend.render(map);
+ }
+}
+
static void API_renderStill_reuse_map_switch_styles(::benchmark::State& state) {
RenderBenchmark bench;
HeadlessFrontend frontend { { 1000, 1000 }, 1, bench.fileSource, bench.threadPool };
@@ -78,5 +90,6 @@ static void API_renderStill_recreate_map(::benchmark::State& state) {
}
BENCHMARK(API_renderStill_reuse_map);
+BENCHMARK(API_renderStill_reuse_map_formatted_labels);
BENCHMARK(API_renderStill_reuse_map_switch_styles);
BENCHMARK(API_renderStill_recreate_map);
diff --git a/benchmark/fixtures/api/style_formatted_labels.json b/benchmark/fixtures/api/style_formatted_labels.json
new file mode 100644
index 0000000000..c627770385
--- /dev/null
+++ b/benchmark/fixtures/api/style_formatted_labels.json
@@ -0,0 +1,3993 @@
+{
+ "version": 8,
+ "name": "Mapbox Streets",
+ "metadata": {
+ "mapbox:autocomposite": true,
+ "mapbox:type": "default",
+ "mapbox:groups": {
+ "1444934828655.3389": { "name": "Aeroways", "collapsed": true },
+ "1444933322393.2852": { "name": "POI labels (scalerank 1)", "collapsed": true },
+ "1444855786460.0557": { "name": "Roads", "collapsed": true },
+ "1444933575858.6992": { "name": "Highway shields", "collapsed": true },
+ "1444934295202.7542": { "name": "Admin boundaries", "collapsed": true },
+ "1444856151690.9143": { "name": "State labels", "collapsed": true },
+ "1444933721429.3076": { "name": "Road labels", "collapsed": true },
+ "1444933358918.2366": { "name": "POI labels (scalerank 2)", "collapsed": true },
+ "1444933808272.805": { "name": "Water labels", "collapsed": true },
+ "1444933372896.5967": { "name": "POI labels (scalerank 3)", "collapsed": true },
+ "1444855799204.86": { "name": "Bridges", "collapsed": true },
+ "1444856087950.3635": { "name": "Marine labels", "collapsed": true },
+ "1456969573402.7817": { "name": "Hillshading", "collapsed": true },
+ "1444862510685.128": { "name": "City labels", "collapsed": true },
+ "1444855769305.6016": { "name": "Tunnels", "collapsed": true },
+ "1456970288113.8113": { "name": "Landcover", "collapsed": true },
+ "1444856144497.7825": { "name": "Country labels", "collapsed": true },
+ "1444933456003.5437": { "name": "POI labels (scalerank 4)", "collapsed": true }
+ }
+ },
+ "sources": {
+ "composite": { "url": "mapbox://mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v7", "type": "vector" }
+ },
+ "sprite": "mapbox://sprites/mapbox/streets-v10",
+ "glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf",
+ "visibility": "public",
+ "layers": [
+ {
+ "id": "background",
+ "type": "background",
+ "layout": {},
+ "paint": {
+ "background-color": { "base": 1, "stops": [ [ 11, "hsl(35, 32%, 91%)" ], [ 13, "hsl(35, 12%, 89%)" ] ] }
+ }
+ },
+ {
+ "id": "landcover_snow",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1456970288113.8113" },
+ "source": "composite",
+ "source-layer": "landcover",
+ "filter": [ "==", "class", "snow" ],
+ "layout": {},
+ "paint": { "fill-color": "hsl(0, 0%, 100%)", "fill-opacity": 0.2, "fill-antialias": false }
+ },
+ {
+ "id": "landcover_wood",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1456970288113.8113" },
+ "source": "composite",
+ "source-layer": "landcover",
+ "maxzoom": 14,
+ "filter": [ "==", "class", "wood" ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(75, 62%, 81%)",
+ "fill-opacity": { "base": 1.5, "stops": [ [ 2, 0.3 ], [ 7, 0 ] ] },
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "landcover_scrub",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1456970288113.8113" },
+ "source": "composite",
+ "source-layer": "landcover",
+ "maxzoom": 14,
+ "filter": [ "==", "class", "scrub" ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(75, 62%, 81%)",
+ "fill-opacity": { "base": 1.5, "stops": [ [ 2, 0.3 ], [ 7, 0 ] ] },
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "landcover_grass",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1456970288113.8113" },
+ "source": "composite",
+ "source-layer": "landcover",
+ "maxzoom": 14,
+ "filter": [ "==", "class", "grass" ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(75, 62%, 81%)",
+ "fill-opacity": { "base": 1.5, "stops": [ [ 2, 0.3 ], [ 7, 0 ] ] },
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "landcover_crop",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1456970288113.8113" },
+ "source": "composite",
+ "source-layer": "landcover",
+ "maxzoom": 14,
+ "filter": [ "==", "class", "crop" ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(75, 62%, 81%)",
+ "fill-opacity": { "base": 1.5, "stops": [ [ 2, 0.3 ], [ 7, 0 ] ] },
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "national_park",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse_overlay",
+ "filter": [ "==", "class", "national_park" ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(100, 58%, 76%)",
+ "fill-opacity": { "base": 1, "stops": [ [ 5, 0 ], [ 6, 0.5 ] ] }
+ }
+ },
+ {
+ "id": "hospital",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": [ "==", "class", "hospital" ],
+ "layout": {},
+ "paint": {
+ "fill-color": { "base": 1, "stops": [ [ 15.5, "hsl(340, 37%, 87%)" ], [ 16, "hsl(340, 63%, 89%)" ] ] }
+ }
+ },
+ {
+ "id": "school",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": [ "==", "class", "school" ],
+ "layout": {},
+ "paint": {
+ "fill-color": { "base": 1, "stops": [ [ 15.5, "hsl(50, 47%, 81%)" ], [ 16, "hsl(50, 63%, 84%)" ] ] }
+ }
+ },
+ {
+ "id": "park",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": [ "==", "class", "park" ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(100, 58%, 76%)",
+ "fill-opacity": { "base": 1, "stops": [ [ 5, 0 ], [ 6, 1 ] ] }
+ }
+ },
+ {
+ "id": "pitch",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": [ "==", "class", "pitch" ],
+ "layout": {},
+ "paint": { "fill-color": "hsl(100, 57%, 72%)" }
+ },
+ {
+ "id": "pitch-line",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "landuse",
+ "minzoom": 15,
+ "filter": [ "==", "class", "pitch" ],
+ "layout": { "line-join": "miter" },
+ "paint": { "line-color": "hsl(75, 57%, 84%)" }
+ },
+ {
+ "id": "cemetery",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": [ "==", "class", "cemetery" ],
+ "layout": {},
+ "paint": { "fill-color": "hsl(75, 37%, 81%)" }
+ },
+ {
+ "id": "industrial",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": [ "==", "class", "industrial" ],
+ "layout": {},
+ "paint": {
+ "fill-color": { "base": 1, "stops": [ [ 15.5, "hsl(230, 15%, 86%)" ], [ 16, "hsl(230, 29%, 89%)" ] ] }
+ }
+ },
+ {
+ "id": "sand",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "landuse",
+ "filter": [ "==", "class", "sand" ],
+ "layout": {},
+ "paint": { "fill-color": "hsl(60, 46%, 87%)" }
+ },
+ {
+ "id": "hillshade_highlight_bright",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1456969573402.7817" },
+ "source": "composite",
+ "source-layer": "hillshade",
+ "maxzoom": 16,
+ "filter": [ "==", "level", 94 ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(0, 0%, 100%)",
+ "fill-opacity": { "stops": [ [ 14, 0.12 ], [ 16, 0 ] ] },
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "hillshade_highlight_med",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1456969573402.7817" },
+ "source": "composite",
+ "source-layer": "hillshade",
+ "maxzoom": 16,
+ "filter": [ "==", "level", 90 ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(0, 0%, 100%)",
+ "fill-opacity": { "stops": [ [ 14, 0.12 ], [ 16, 0 ] ] },
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "hillshade_shadow_faint",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1456969573402.7817" },
+ "source": "composite",
+ "source-layer": "hillshade",
+ "maxzoom": 16,
+ "filter": [ "==", "level", 89 ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(56, 59%, 22%)",
+ "fill-opacity": { "stops": [ [ 14, 0.05 ], [ 16, 0 ] ] },
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "hillshade_shadow_med",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1456969573402.7817" },
+ "source": "composite",
+ "source-layer": "hillshade",
+ "maxzoom": 16,
+ "filter": [ "==", "level", 78 ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(56, 59%, 22%)",
+ "fill-opacity": { "stops": [ [ 14, 0.05 ], [ 16, 0 ] ] },
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "hillshade_shadow_dark",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1456969573402.7817" },
+ "source": "composite",
+ "source-layer": "hillshade",
+ "maxzoom": 16,
+ "filter": [ "==", "level", 67 ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(56, 59%, 22%)",
+ "fill-opacity": { "stops": [ [ 14, 0.06 ], [ 16, 0 ] ] },
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "hillshade_shadow_extreme",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1456969573402.7817" },
+ "source": "composite",
+ "source-layer": "hillshade",
+ "maxzoom": 16,
+ "filter": [ "==", "level", 56 ],
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(56, 59%, 22%)",
+ "fill-opacity": { "stops": [ [ 14, 0.06 ], [ 16, 0 ] ] },
+ "fill-antialias": false
+ }
+ },
+ {
+ "id": "waterway-river-canal",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "waterway",
+ "minzoom": 8,
+ "filter": [ "in", "class", "canal", "river" ],
+ "layout": {
+ "line-cap": { "base": 1, "stops": [ [ 0, "butt" ], [ 11, "round" ] ] },
+ "line-join": "round"
+ },
+ "paint": {
+ "line-color": "hsl(205, 87%, 76%)",
+ "line-width": { "base": 1.3, "stops": [ [ 8.5, 0.1 ], [ 20, 8 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 8, 0 ], [ 8.5, 1 ] ] }
+ }
+ },
+ {
+ "id": "waterway-small",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "waterway",
+ "minzoom": 13,
+ "filter": [ "!in", "class", "canal", "river" ],
+ "layout": { "line-join": "round", "line-cap": "round" },
+ "paint": {
+ "line-color": "hsl(205, 87%, 76%)",
+ "line-width": { "base": 1.35, "stops": [ [ 13.5, 0.1 ], [ 20, 3 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 13, 0 ], [ 13.5, 1 ] ] }
+ }
+ },
+ {
+ "id": "water-shadow",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "water",
+ "layout": {},
+ "paint": {
+ "fill-color": "hsl(215, 84%, 69%)",
+ "fill-translate": { "base": 1.2, "stops": [ [ 7, [ 0, 0 ] ], [ 16, [ -1, -1 ] ] ] },
+ "fill-translate-anchor": "viewport",
+ "fill-opacity": 1
+ }
+ },
+ { "id": "water", "ref": "water-shadow", "paint": { "fill-color": "hsl(196, 80%, 70%)" } },
+ {
+ "id": "barrier_line-land-polygon",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "barrier_line",
+ "filter": [ "all", [ "==", "$type", "Polygon" ], [ "==", "class", "land" ] ],
+ "layout": {},
+ "paint": { "fill-color": "hsl(35, 12%, 89%)" }
+ },
+ {
+ "id": "barrier_line-land-line",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "barrier_line",
+ "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "class", "land" ] ],
+ "layout": { "line-cap": "round" },
+ "paint": {
+ "line-width": { "base": 1.99, "stops": [ [ 14, 0.75 ], [ 20, 40 ] ] },
+ "line-color": "hsl(35, 12%, 89%)"
+ }
+ },
+ {
+ "id": "aeroway-polygon",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1444934828655.3389" },
+ "source": "composite",
+ "source-layer": "aeroway",
+ "minzoom": 11,
+ "filter": [ "all", [ "==", "$type", "Polygon" ], [ "!=", "type", "apron" ] ],
+ "layout": {},
+ "paint": {
+ "fill-color": { "base": 1, "stops": [ [ 15, "hsl(230, 23%, 82%)" ], [ 16, "hsl(230, 37%, 84%)" ] ] },
+ "fill-opacity": { "base": 1, "stops": [ [ 11, 0 ], [ 11.5, 1 ] ] }
+ }
+ },
+ {
+ "id": "aeroway-runway",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444934828655.3389" },
+ "source": "composite",
+ "source-layer": "aeroway",
+ "minzoom": 9,
+ "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "type", "runway" ] ],
+ "layout": {},
+ "paint": {
+ "line-color": { "base": 1, "stops": [ [ 15, "hsl(230, 23%, 82%)" ], [ 16, "hsl(230, 37%, 84%)" ] ] },
+ "line-width": { "base": 1.5, "stops": [ [ 9, 1 ], [ 18, 80 ] ] }
+ }
+ },
+ {
+ "id": "aeroway-taxiway",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444934828655.3389" },
+ "source": "composite",
+ "source-layer": "aeroway",
+ "minzoom": 9,
+ "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "type", "taxiway" ] ],
+ "layout": {},
+ "paint": {
+ "line-color": { "base": 1, "stops": [ [ 15, "hsl(230, 23%, 82%)" ], [ 16, "hsl(230, 37%, 84%)" ] ] },
+ "line-width": { "base": 1.5, "stops": [ [ 10, 0.5 ], [ 18, 20 ] ] }
+ }
+ },
+ {
+ "id": "building-line",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "building",
+ "minzoom": 15,
+ "filter": [ "all", [ "!=", "type", "building:part" ], [ "==", "underground", "false" ] ],
+ "layout": {},
+ "paint": {
+ "line-color": "hsl(35, 6%, 79%)",
+ "line-width": { "base": 1.5, "stops": [ [ 15, 0.75 ], [ 20, 3 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 15.5, 0 ], [ 16, 1 ] ] }
+ }
+ },
+ {
+ "id": "building",
+ "type": "fill",
+ "source": "composite",
+ "source-layer": "building",
+ "minzoom": 15,
+ "filter": [ "all", [ "!=", "type", "building:part" ], [ "==", "underground", "false" ] ],
+ "layout": {},
+ "paint": {
+ "fill-color": { "base": 1, "stops": [ [ 15, "hsl(35, 11%, 88%)" ], [ 16, "hsl(35, 8%, 85%)" ] ] },
+ "fill-opacity": { "base": 1, "stops": [ [ 15.5, 0 ], [ 16, 1 ] ] },
+ "fill-outline-color": "hsl(35, 6%, 79%)"
+ }
+ },
+ {
+ "id": "tunnel-street-low",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "street" ], [ "==", "structure", "tunnel" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": { "stops": [ [ 11.5, 0 ], [ 12, 1 ], [ 14, 1 ], [ 14.01, 0 ] ] }
+ }
+ },
+ {
+ "id": "tunnel-street_limited-low",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "street_limited" ], [ "==", "structure", "tunnel" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": { "stops": [ [ 11.5, 0 ], [ 12, 1 ], [ 14, 1 ], [ 14.01, 0 ] ] }
+ }
+ },
+ {
+ "id": "tunnel-service-link-track-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "link", "service", "track" ],
+ [ "==", "structure", "tunnel" ],
+ [ "!=", "type", "trunk_link" ]
+ ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(230, 19%, 75%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] },
+ "line-dasharray": [ 3, 3 ]
+ }
+ },
+ {
+ "id": "tunnel-street_limited-case",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "ref": "tunnel-street_limited-low",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(230, 19%, 75%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 13, 0 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-dasharray": [ 3, 3 ],
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }
+ }
+ },
+ {
+ "id": "tunnel-street-case",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "ref": "tunnel-street-low",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(230, 19%, 75%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 13, 0 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-dasharray": [ 3, 3 ],
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }
+ }
+ },
+ {
+ "id": "tunnel-secondary-tertiary-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "in", "class", "secondary", "tertiary" ], [ "==", "structure", "tunnel" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.2, "stops": [ [ 10, 0.75 ], [ 18, 2 ] ] },
+ "line-dasharray": [ 3, 3 ],
+ "line-gap-width": { "base": 1.5, "stops": [ [ 8.5, 0.5 ], [ 10, 0.75 ], [ 18, 26 ] ] },
+ "line-color": "hsl(230, 19%, 75%)"
+ }
+ },
+ {
+ "id": "tunnel-primary-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "primary" ], [ "==", "structure", "tunnel" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] },
+ "line-dasharray": [ 3, 3 ],
+ "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-color": "hsl(230, 19%, 75%)"
+ }
+ },
+ {
+ "id": "tunnel-trunk_link-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "structure", "tunnel" ], [ "==", "type", "trunk_link" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-dasharray": [ 3, 3 ]
+ }
+ },
+ {
+ "id": "tunnel-motorway_link-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "motorway_link" ], [ "==", "structure", "tunnel" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-dasharray": [ 3, 3 ]
+ }
+ },
+ {
+ "id": "tunnel-trunk-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "structure", "tunnel" ], [ "==", "type", "trunk" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-opacity": 1,
+ "line-dasharray": [ 3, 3 ]
+ }
+ },
+ {
+ "id": "tunnel-motorway-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "motorway" ], [ "==", "structure", "tunnel" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-opacity": 1,
+ "line-dasharray": [ 3, 3 ]
+ }
+ },
+ {
+ "id": "tunnel-construction",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "construction" ], [ "==", "structure", "tunnel" ] ]
+ ],
+ "layout": { "line-join": "miter" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] },
+ "line-dasharray": {
+ "base": 1,
+ "stops": [
+ [ 14, [ 0.4, 0.8 ] ],
+ [ 15, [ 0.3, 0.6 ] ],
+ [ 16, [ 0.2, 0.3 ] ],
+ [ 17, [ 0.2, 0.25 ] ],
+ [ 18, [ 0.15, 0.15 ] ]
+ ]
+ }
+ }
+ },
+ {
+ "id": "tunnel-path",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "path" ],
+ [ "==", "structure", "tunnel" ],
+ [ "!=", "type", "steps" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 18, 4 ] ] },
+ "line-dasharray": {
+ "base": 1,
+ "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 1, 0.5 ] ] ]
+ },
+ "line-color": "hsl(35, 26%, 95%)",
+ "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 1 ] ] }
+ }
+ },
+ {
+ "id": "tunnel-steps",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "structure", "tunnel" ], [ "==", "type", "steps" ] ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 16, 1.6 ], [ 18, 6 ] ] },
+ "line-color": "hsl(35, 26%, 95%)",
+ "line-dasharray": {
+ "base": 1,
+ "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 0.3, 0.3 ] ] ]
+ },
+ "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 1 ] ] }
+ }
+ },
+ {
+ "id": "tunnel-trunk_link",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "ref": "tunnel-trunk_link-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(46, 77%, 78%)",
+ "line-opacity": 1,
+ "line-dasharray": [ 1, 0 ]
+ }
+ },
+ {
+ "id": "tunnel-motorway_link",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "ref": "tunnel-motorway_link-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(26, 100%, 78%)",
+ "line-opacity": 1,
+ "line-dasharray": [ 1, 0 ]
+ }
+ },
+ {
+ "id": "tunnel-pedestrian",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "pedestrian" ], [ "==", "structure", "tunnel" ] ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": 1,
+ "line-dasharray": { "base": 1, "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.5, 0.4 ] ], [ 16, [ 1, 0.2 ] ] ] }
+ }
+ },
+ {
+ "id": "tunnel-service-link-track",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "ref": "tunnel-service-link-track-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-dasharray": [ 1, 0 ]
+ }
+ },
+ {
+ "id": "tunnel-street_limited",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "ref": "tunnel-street_limited-low",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(35, 14%, 93%)",
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }
+ }
+ },
+ {
+ "id": "tunnel-street",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "ref": "tunnel-street-low",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }
+ }
+ },
+ {
+ "id": "tunnel-secondary-tertiary",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "ref": "tunnel-secondary-tertiary-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 8.5, 0.5 ], [ 10, 0.75 ], [ 18, 26 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": 1,
+ "line-dasharray": [ 1, 0 ],
+ "line-blur": 0
+ }
+ },
+ {
+ "id": "tunnel-primary",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "ref": "tunnel-primary-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": 1,
+ "line-dasharray": [ 1, 0 ],
+ "line-blur": 0
+ }
+ },
+ {
+ "id": "tunnel-oneway-arrows-blue-minor",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "link", "path", "pedestrian", "service", "track" ],
+ [ "==", "oneway", "true" ],
+ [ "==", "structure", "tunnel" ],
+ [ "!=", "type", "trunk_link" ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": { "base": 1, "stops": [ [ 17, "oneway-small" ], [ 18, "oneway-large" ] ] },
+ "symbol-spacing": 200,
+ "icon-padding": 2
+ },
+ "paint": {}
+ },
+ {
+ "id": "tunnel-oneway-arrows-blue-major",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "primary", "secondary", "street", "street_limited", "tertiary" ],
+ [ "==", "oneway", "true" ],
+ [ "==", "structure", "tunnel" ],
+ [ "!=", "type", "trunk_link" ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": { "base": 1, "stops": [ [ 16, "oneway-small" ], [ 17, "oneway-large" ] ] },
+ "symbol-spacing": 200,
+ "icon-padding": 2
+ },
+ "paint": {}
+ },
+ {
+ "id": "tunnel-trunk",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "trunk" ], [ "==", "structure", "tunnel" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-color": "hsl(46, 77%, 78%)"
+ }
+ },
+ {
+ "id": "tunnel-motorway",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "ref": "tunnel-motorway-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-dasharray": [ 1, 0 ],
+ "line-opacity": 1,
+ "line-color": "hsl(26, 100%, 78%)",
+ "line-blur": 0
+ }
+ },
+ {
+ "id": "tunnel-oneway-arrows-white",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444855769305.6016" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "link", "motorway", "motorway_link", "trunk" ],
+ [ "==", "oneway", "true" ],
+ [ "==", "structure", "tunnel" ],
+ [ "!in", "type", "primary_link", "secondary_link", "tertiary_link" ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": { "base": 1, "stops": [ [ 16, "oneway-white-small" ], [ 17, "oneway-white-large" ] ] },
+ "symbol-spacing": 200,
+ "icon-padding": 2
+ },
+ "paint": {}
+ },
+ {
+ "id": "ferry",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "type", "ferry" ] ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-color": { "base": 1, "stops": [ [ 15, "hsl(205, 73%, 63%)" ], [ 17, "hsl(230, 73%, 63%)" ] ] },
+ "line-opacity": 1,
+ "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 20, 1 ] ] },
+ "line-dasharray": { "base": 1, "stops": [ [ 12, [ 1, 0 ] ], [ 13, [ 12, 4 ] ] ] }
+ }
+ },
+ {
+ "id": "ferry_auto",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "type", "ferry_auto" ] ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-color": { "base": 1, "stops": [ [ 15, "hsl(205, 73%, 63%)" ], [ 17, "hsl(230, 73%, 63%)" ] ] },
+ "line-opacity": 1,
+ "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 20, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-path-bg",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "path" ],
+ [ "!in", "structure", "bridge", "tunnel" ],
+ [ "!in", "type", "crossing", "sidewalk", "steps" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 15, 2 ], [ 18, 7 ] ] },
+ "line-dasharray": [ 1, 0 ],
+ "line-color": "hsl(230, 17%, 82%)",
+ "line-blur": 0,
+ "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 0.75 ] ] }
+ }
+ },
+ {
+ "id": "road-steps-bg",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "!in", "structure", "bridge", "tunnel" ], [ "==", "type", "steps" ] ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 15, 2 ], [ 17, 4.6 ], [ 18, 7 ] ] },
+ "line-color": "hsl(230, 17%, 82%)",
+ "line-dasharray": [ 1, 0 ],
+ "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 0.75 ] ] }
+ }
+ },
+ {
+ "id": "road-sidewalk-bg",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "!in", "structure", "bridge", "tunnel" ],
+ [ "in", "type", "crossing", "sidewalk" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 15, 2 ], [ 18, 7 ] ] },
+ "line-dasharray": [ 1, 0 ],
+ "line-color": "hsl(230, 17%, 82%)",
+ "line-blur": 0,
+ "line-opacity": { "base": 1, "stops": [ [ 16, 0 ], [ 16.25, 0.75 ] ] }
+ }
+ },
+ {
+ "id": "turning-features-outline",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 15,
+ "filter": [ "all", [ "==", "$type", "Point" ], [ "in", "class", "turning_circle", "turning_loop" ] ],
+ "layout": {
+ "icon-image": "turning-circle-outline",
+ "icon-size": { "base": 1.5, "stops": [ [ 14, 0.122 ], [ 18, 0.969 ], [ 20, 1 ] ] },
+ "icon-allow-overlap": true,
+ "icon-ignore-placement": true,
+ "icon-padding": 0,
+ "icon-rotation-alignment": "map"
+ },
+ "paint": {}
+ },
+ {
+ "id": "road-pedestrian-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 12,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "pedestrian" ], [ "==", "structure", "none" ] ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 14, 2 ], [ 18, 14.5 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": 0,
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-street-low",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "street" ], [ "==", "structure", "none" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": { "stops": [ [ 11, 0 ], [ 11.25, 1 ], [ 14, 1 ], [ 14.01, 0 ] ] }
+ }
+ },
+ {
+ "id": "road-street_limited-low",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "street_limited" ], [ "==", "structure", "none" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": { "stops": [ [ 11, 0 ], [ 11.25, 1 ], [ 14, 1 ], [ 14.01, 0 ] ] }
+ }
+ },
+ {
+ "id": "road-service-link-track-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "link", "service", "track" ],
+ [ "!in", "structure", "bridge", "tunnel" ],
+ [ "!=", "type", "trunk_link" ]
+ ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] }
+ }
+ },
+ {
+ "id": "road-street_limited-case",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-street_limited-low",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 13, 0 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-street-case",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-street-low",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 13, 0 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-secondary-tertiary-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "secondary", "tertiary" ],
+ [ "!in", "structure", "bridge", "tunnel" ]
+ ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.2, "stops": [ [ 10, 0.75 ], [ 18, 2 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 8.5, 0.5 ], [ 10, 0.75 ], [ 18, 26 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 9.99, 0 ], [ 10, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-primary-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "primary" ], [ "!in", "structure", "bridge", "tunnel" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 9.99, 0 ], [ 10, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-motorway_link-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 10,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "motorway_link" ], [ "!in", "structure", "bridge", "tunnel" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 10.99, 0 ], [ 11, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-trunk_link-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "!in", "structure", "bridge", "tunnel" ], [ "==", "type", "trunk_link" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 10.99, 0 ], [ 11, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-trunk-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "trunk" ], [ "!in", "structure", "bridge", "tunnel" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 6, 0 ], [ 6.1, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-motorway-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "motorway" ], [ "!in", "structure", "bridge", "tunnel" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }
+ }
+ },
+ {
+ "id": "road-construction",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "construction" ], [ "==", "structure", "none" ] ]
+ ],
+ "layout": { "line-join": "miter" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] },
+ "line-dasharray": {
+ "base": 1,
+ "stops": [
+ [ 14, [ 0.4, 0.8 ] ],
+ [ 15, [ 0.3, 0.6 ] ],
+ [ 16, [ 0.2, 0.3 ] ],
+ [ 17, [ 0.2, 0.25 ] ],
+ [ 18, [ 0.15, 0.15 ] ]
+ ]
+ }
+ }
+ },
+ {
+ "id": "road-sidewalks",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-sidewalk-bg",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 18, 4 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-dasharray": {
+ "base": 1,
+ "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 1, 0.5 ] ] ]
+ },
+ "line-opacity": { "base": 1, "stops": [ [ 16, 0 ], [ 16.25, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-path",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-path-bg",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 18, 4 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-dasharray": {
+ "base": 1,
+ "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 1, 0.5 ] ] ]
+ },
+ "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-steps",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-steps-bg",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 16, 1.6 ], [ 18, 6 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-dasharray": {
+ "base": 1,
+ "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 0.3, 0.3 ] ] ]
+ },
+ "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-trunk_link",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-trunk_link-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(46, 85%, 67%)",
+ "line-opacity": 1
+ }
+ },
+ {
+ "id": "road-motorway_link",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-motorway_link-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(26, 100%, 68%)",
+ "line-opacity": 1
+ }
+ },
+ {
+ "id": "road-pedestrian",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-pedestrian-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": 1,
+ "line-dasharray": { "base": 1, "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.5, 0.4 ] ], [ 16, [ 1, 0.2 ] ] ] }
+ }
+ },
+ {
+ "id": "road-pedestrian-polygon-fill",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 12,
+ "filter": [
+ "all",
+ [ "==", "$type", "Polygon" ],
+ [ "all", [ "in", "class", "path", "pedestrian" ], [ "==", "structure", "none" ] ]
+ ],
+ "layout": {},
+ "paint": {
+ "fill-color": { "base": 1, "stops": [ [ 16, "hsl(230, 16%, 94%)" ], [ 16.25, "hsl(230, 50%, 98%)" ] ] },
+ "fill-outline-color": "hsl(230, 26%, 88%)",
+ "fill-opacity": 1
+ }
+ },
+ {
+ "id": "road-pedestrian-polygon-pattern",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-pedestrian-polygon-fill",
+ "paint": {
+ "fill-color": "hsl(0, 0%, 100%)",
+ "fill-outline-color": "hsl(35, 10%, 83%)",
+ "fill-pattern": "pedestrian-polygon",
+ "fill-opacity": { "base": 1, "stops": [ [ 16, 0 ], [ 16.25, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-polygon",
+ "type": "fill",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 12,
+ "filter": [
+ "all",
+ [ "==", "$type", "Polygon" ],
+ [
+ "all",
+ [ "!in", "class", "motorway", "path", "pedestrian", "trunk" ],
+ [ "!in", "structure", "bridge", "tunnel" ]
+ ]
+ ],
+ "layout": {},
+ "paint": { "fill-color": "hsl(0, 0%, 100%)", "fill-outline-color": "#d6d9e6" }
+ },
+ {
+ "id": "road-service-link-track",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-service-link-track-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] },
+ "line-color": "hsl(0, 0%, 100%)"
+ }
+ },
+ {
+ "id": "road-street_limited",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-street_limited-low",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(35, 14%, 93%)",
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-street",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-street-low",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-secondary-tertiary",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-secondary-tertiary-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 8.5, 0.5 ], [ 10, 0.75 ], [ 18, 26 ] ] },
+ "line-color": { "base": 1, "stops": [ [ 5, "hsl(35, 32%, 91%)" ], [ 8, "hsl(0, 0%, 100%)" ] ] },
+ "line-opacity": { "base": 1.2, "stops": [ [ 5, 0 ], [ 5.5, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-primary",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-primary-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-color": { "base": 1, "stops": [ [ 5, "hsl(35, 32%, 91%)" ], [ 7, "hsl(0, 0%, 100%)" ] ] },
+ "line-opacity": 1
+ }
+ },
+ {
+ "id": "road-oneway-arrows-blue-minor",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "link", "path", "pedestrian", "service", "track" ],
+ [ "==", "oneway", "true" ],
+ [ "!in", "structure", "bridge", "tunnel" ],
+ [ "!=", "type", "trunk_link" ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": { "base": 1, "stops": [ [ 17, "oneway-small" ], [ 18, "oneway-large" ] ] },
+ "icon-rotation-alignment": "map",
+ "icon-padding": 2,
+ "symbol-spacing": 200
+ },
+ "paint": {}
+ },
+ {
+ "id": "road-oneway-arrows-blue-major",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "primary", "secondary", "street", "street_limited", "tertiary" ],
+ [ "==", "oneway", "true" ],
+ [ "!in", "structure", "bridge", "tunnel" ],
+ [ "!=", "type", "trunk_link" ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": { "base": 1, "stops": [ [ 16, "oneway-small" ], [ 17, "oneway-large" ] ] },
+ "icon-rotation-alignment": "map",
+ "icon-padding": 2,
+ "symbol-spacing": 200
+ },
+ "paint": {}
+ },
+ {
+ "id": "road-trunk",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-trunk-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-color": {
+ "base": 1,
+ "stops": [ [ 6, "hsl(0, 0%, 100%)" ], [ 6.1, "hsl(46, 80%, 60%)" ], [ 9, "hsl(46, 85%, 67%)" ] ]
+ }
+ }
+ },
+ {
+ "id": "road-motorway",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-motorway-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-color": { "base": 1, "stops": [ [ 8, "hsl(26, 87%, 62%)" ], [ 9, "hsl(26, 100%, 68%)" ] ] }
+ }
+ },
+ {
+ "id": "road-rail",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "major_rail", "minor_rail" ],
+ [ "!in", "structure", "bridge", "tunnel" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-color": { "stops": [ [ 13, "hsl(50, 17%, 82%)" ], [ 16, "hsl(230, 10%, 74%)" ] ] },
+ "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 20, 1 ] ] }
+ }
+ },
+ {
+ "id": "road-rail-tracks",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "ref": "road-rail",
+ "paint": {
+ "line-color": { "stops": [ [ 13, "hsl(50, 17%, 82%)" ], [ 16, "hsl(230, 10%, 74%)" ] ] },
+ "line-width": { "base": 1.5, "stops": [ [ 14, 4 ], [ 20, 8 ] ] },
+ "line-dasharray": [ 0.1, 15 ],
+ "line-opacity": { "base": 1, "stops": [ [ 13.75, 0 ], [ 14, 1 ] ] }
+ }
+ },
+ {
+ "id": "level-crossings",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [ "all", [ "==", "$type", "Point" ], [ "==", "class", "level_crossing" ] ],
+ "layout": { "icon-size": 1, "icon-image": "level-crossing", "icon-allow-overlap": true },
+ "paint": {}
+ },
+ {
+ "id": "road-oneway-arrows-white",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "link", "motorway", "motorway_link", "trunk" ],
+ [ "==", "oneway", "true" ],
+ [ "!in", "structure", "bridge", "tunnel" ],
+ [ "!in", "type", "primary_link", "secondary_link", "tertiary_link" ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": { "base": 1, "stops": [ [ 16, "oneway-white-small" ], [ 17, "oneway-white-large" ] ] },
+ "icon-padding": 2,
+ "symbol-spacing": 200
+ },
+ "paint": {}
+ },
+ {
+ "id": "turning-features",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444855786460.0557" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 15,
+ "filter": [ "all", [ "==", "$type", "Point" ], [ "in", "class", "turning_circle", "turning_loop" ] ],
+ "layout": {
+ "icon-image": "turning-circle",
+ "icon-size": { "base": 1.5, "stops": [ [ 14, 0.095 ], [ 18, 1 ] ] },
+ "icon-allow-overlap": true,
+ "icon-ignore-placement": true,
+ "icon-padding": 0,
+ "icon-rotation-alignment": "map"
+ },
+ "paint": {}
+ },
+ {
+ "id": "bridge-path-bg",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "path" ],
+ [ "==", "structure", "bridge" ],
+ [ "!=", "type", "steps" ]
+ ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 15, 2 ], [ 18, 7 ] ] },
+ "line-dasharray": [ 1, 0 ],
+ "line-color": "hsl(230, 17%, 82%)",
+ "line-blur": 0,
+ "line-opacity": { "base": 1, "stops": [ [ 15, 0 ], [ 15.25, 1 ] ] }
+ }
+ },
+ {
+ "id": "bridge-steps-bg",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "structure", "bridge" ], [ "==", "type", "steps" ] ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 15, 2 ], [ 17, 4.6 ], [ 18, 7 ] ] },
+ "line-color": "hsl(230, 17%, 82%)",
+ "line-dasharray": [ 1, 0 ],
+ "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 0.75 ] ] }
+ }
+ },
+ {
+ "id": "bridge-pedestrian-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "pedestrian" ], [ "==", "structure", "bridge" ] ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 14, 2 ], [ 18, 14.5 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": 0,
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }
+ }
+ },
+ {
+ "id": "bridge-street-low",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "street" ], [ "==", "structure", "bridge" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": { "stops": [ [ 11.5, 0 ], [ 12, 1 ], [ 14, 1 ], [ 14.01, 0 ] ] }
+ }
+ },
+ {
+ "id": "bridge-street_limited-low",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "street_limited" ], [ "==", "structure", "bridge" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": { "stops": [ [ 11.5, 0 ], [ 12, 1 ], [ 14, 1 ], [ 14.01, 0 ] ] }
+ }
+ },
+ {
+ "id": "bridge-service-link-track-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "link", "service", "track" ],
+ [ "==", "structure", "bridge" ],
+ [ "!=", "type", "trunk_link" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] }
+ }
+ },
+ {
+ "id": "bridge-street_limited-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "street_limited" ], [ "==", "structure", "bridge" ] ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 13, 0 ], [ 14, 2 ], [ 18, 18 ] ] }
+ }
+ },
+ {
+ "id": "bridge-street-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "street" ], [ "==", "structure", "bridge" ] ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] },
+ "line-gap-width": { "base": 1.5, "stops": [ [ 13, 0 ], [ 14, 2 ], [ 18, 18 ] ] }
+ }
+ },
+ {
+ "id": "bridge-secondary-tertiary-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "in", "class", "secondary", "tertiary" ], [ "==", "structure", "bridge" ] ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.2, "stops": [ [ 10, 0.75 ], [ 18, 2 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 8.5, 0.5 ], [ 10, 0.75 ], [ 18, 26 ] ] },
+ "line-translate": [ 0, 0 ]
+ }
+ },
+ {
+ "id": "bridge-primary-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "primary" ], [ "==", "structure", "bridge" ] ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-translate": [ 0, 0 ]
+ }
+ },
+ {
+ "id": "bridge-trunk_link-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "!in", "layer", 2, 3, 4, 5 ],
+ [ "==", "structure", "bridge" ],
+ [ "==", "type", "trunk_link" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 10.99, 0 ], [ 11, 1 ] ] }
+ }
+ },
+ {
+ "id": "bridge-motorway_link-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "motorway_link" ],
+ [ "!in", "layer", 2, 3, 4, 5 ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-opacity": 1
+ }
+ },
+ {
+ "id": "bridge-trunk-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "trunk" ],
+ [ "!in", "layer", 2, 3, 4, 5 ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }
+ }
+ },
+ {
+ "id": "bridge-motorway-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "motorway" ],
+ [ "!in", "layer", 2, 3, 4, 5 ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }
+ }
+ },
+ {
+ "id": "bridge-construction",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "class", "construction" ], [ "==", "structure", "bridge" ] ]
+ ],
+ "layout": { "line-join": "miter" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(230, 24%, 87%)",
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] },
+ "line-dasharray": {
+ "base": 1,
+ "stops": [
+ [ 14, [ 0.4, 0.8 ] ],
+ [ 15, [ 0.3, 0.6 ] ],
+ [ 16, [ 0.2, 0.3 ] ],
+ [ 17, [ 0.2, 0.25 ] ],
+ [ 18, [ 0.15, 0.15 ] ]
+ ]
+ }
+ }
+ },
+ {
+ "id": "bridge-path",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "path" ],
+ [ "==", "structure", "bridge" ],
+ [ "!=", "type", "steps" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 18, 4 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-dasharray": {
+ "base": 1,
+ "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 1, 0.5 ] ] ]
+ },
+ "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 1 ] ] }
+ }
+ },
+ {
+ "id": "bridge-steps",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "ref": "bridge-steps-bg",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 15, 1 ], [ 16, 1.6 ], [ 18, 6 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-dasharray": {
+ "base": 1,
+ "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.75, 1 ] ], [ 16, [ 1, 0.75 ] ], [ 17, [ 0.3, 0.3 ] ] ]
+ },
+ "line-opacity": { "base": 1, "stops": [ [ 14, 0 ], [ 14.25, 1 ] ] }
+ }
+ },
+ {
+ "id": "bridge-trunk_link",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "!in", "layer", 2, 3, 4, 5 ],
+ [ "==", "structure", "bridge" ],
+ [ "==", "type", "trunk_link" ]
+ ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(46, 85%, 67%)"
+ }
+ },
+ {
+ "id": "bridge-motorway_link",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "motorway_link" ],
+ [ "!in", "layer", 2, 3, 4, 5 ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(26, 100%, 68%)"
+ }
+ },
+ {
+ "id": "bridge-pedestrian",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "ref": "bridge-pedestrian-case",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": 1,
+ "line-dasharray": { "base": 1, "stops": [ [ 14, [ 1, 0 ] ], [ 15, [ 1.5, 0.4 ] ], [ 16, [ 1, 0.2 ] ] ] }
+ }
+ },
+ {
+ "id": "bridge-service-link-track",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 14,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "link", "service", "track" ],
+ [ "==", "structure", "bridge" ],
+ [ "!=", "type", "trunk_link" ]
+ ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 18, 12 ] ] },
+ "line-color": "hsl(0, 0%, 100%)"
+ }
+ },
+ {
+ "id": "bridge-street_limited",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "ref": "bridge-street_limited-low",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(35, 14%, 93%)",
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }
+ }
+ },
+ {
+ "id": "bridge-street",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "ref": "bridge-street-low",
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12.5, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] }
+ }
+ },
+ {
+ "id": "bridge-secondary-tertiary",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "structure", "bridge" ], [ "in", "type", "secondary", "tertiary" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 8.5, 0.5 ], [ 10, 0.75 ], [ 18, 26 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": { "base": 1.2, "stops": [ [ 5, 0 ], [ 5.5, 1 ] ] }
+ }
+ },
+ {
+ "id": "bridge-primary",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "==", "structure", "bridge" ], [ "==", "type", "primary" ] ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-opacity": 1
+ }
+ },
+ {
+ "id": "bridge-oneway-arrows-blue-minor",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "link", "path", "pedestrian", "service", "track" ],
+ [ "==", "oneway", "true" ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": { "base": 1, "stops": [ [ 17, "oneway-small" ], [ 18, "oneway-large" ] ] },
+ "symbol-spacing": 200,
+ "icon-rotation-alignment": "map",
+ "icon-padding": 2
+ },
+ "paint": {}
+ },
+ {
+ "id": "bridge-oneway-arrows-blue-major",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "primary", "secondary", "street", "street_limited", "tertiary" ],
+ [ "==", "oneway", "true" ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": { "base": 1, "stops": [ [ 16, "oneway-small" ], [ 17, "oneway-large" ] ] },
+ "symbol-spacing": 200,
+ "icon-rotation-alignment": "map",
+ "icon-padding": 2
+ },
+ "paint": {}
+ },
+ {
+ "id": "bridge-trunk",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "trunk" ],
+ [ "!in", "layer", 2, 3, 4, 5 ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-color": "hsl(46, 85%, 67%)"
+ }
+ },
+ {
+ "id": "bridge-motorway",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "motorway" ],
+ [ "!in", "layer", 2, 3, 4, 5 ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-color": "hsl(26, 100%, 68%)"
+ }
+ },
+ {
+ "id": "bridge-rail",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "all", [ "in", "class", "major_rail", "minor_rail" ], [ "==", "structure", "bridge" ] ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-color": { "stops": [ [ 13, "hsl(50, 17%, 82%)" ], [ 16, "hsl(230, 10%, 74%)" ] ] },
+ "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 20, 1 ] ] }
+ }
+ },
+ {
+ "id": "bridge-rail-tracks",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "ref": "bridge-rail",
+ "paint": {
+ "line-color": { "stops": [ [ 13, "hsl(50, 17%, 82%)" ], [ 16, "hsl(230, 10%, 74%)" ] ] },
+ "line-width": { "base": 1.5, "stops": [ [ 14, 4 ], [ 20, 8 ] ] },
+ "line-dasharray": [ 0.1, 15 ],
+ "line-opacity": { "base": 1, "stops": [ [ 13.75, 0 ], [ 20, 1 ] ] }
+ }
+ },
+ {
+ "id": "bridge-trunk_link-2-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ ">=", "layer", 2 ],
+ [ "==", "structure", "bridge" ],
+ [ "==", "type", "trunk_link" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 10.99, 0 ], [ 11, 1 ] ] }
+ }
+ },
+ {
+ "id": "bridge-motorway_link-2-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "motorway_link" ],
+ [ ">=", "layer", 2 ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.75 ], [ 20, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-opacity": 1
+ }
+ },
+ {
+ "id": "bridge-trunk-2-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "trunk" ],
+ [ ">=", "layer", 2 ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }
+ }
+ },
+ {
+ "id": "bridge-motorway-2-case",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "motorway" ],
+ [ ">=", "layer", 2 ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 10, 1 ], [ 16, 2 ] ] },
+ "line-color": "hsl(0, 0%, 100%)",
+ "line-gap-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] }
+ }
+ },
+ {
+ "id": "bridge-trunk_link-2",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ ">=", "layer", 2 ],
+ [ "==", "structure", "bridge" ],
+ [ "==", "type", "trunk_link" ]
+ ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(46, 85%, 67%)"
+ }
+ },
+ {
+ "id": "bridge-motorway_link-2",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "motorway_link" ],
+ [ ">=", "layer", 2 ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 12, 0.5 ], [ 14, 2 ], [ 18, 18 ] ] },
+ "line-color": "hsl(26, 100%, 68%)"
+ }
+ },
+ {
+ "id": "bridge-trunk-2",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "trunk" ],
+ [ ">=", "layer", 2 ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-color": "hsl(46, 85%, 67%)"
+ }
+ },
+ {
+ "id": "bridge-motorway-2",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "==", "class", "motorway" ],
+ [ ">=", "layer", 2 ],
+ [ "==", "structure", "bridge" ]
+ ]
+ ],
+ "layout": { "line-cap": "round", "line-join": "round" },
+ "paint": {
+ "line-width": { "base": 1.5, "stops": [ [ 5, 0.75 ], [ 18, 32 ] ] },
+ "line-color": "hsl(26, 100%, 68%)"
+ }
+ },
+ {
+ "id": "bridge-oneway-arrows-white",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444855799204.86" },
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 16,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "all",
+ [ "in", "class", "link", "motorway", "motorway_link", "trunk" ],
+ [ "==", "oneway", "true" ],
+ [ "==", "structure", "bridge" ],
+ [ "!in", "type", "primary_link", "secondary_link", "tertiary_link" ]
+ ]
+ ],
+ "layout": {
+ "symbol-placement": "line",
+ "icon-image": { "base": 1, "stops": [ [ 16, "oneway-white-small" ], [ 17, "oneway-white-large" ] ] },
+ "symbol-spacing": 200,
+ "icon-padding": 2
+ },
+ "paint": {}
+ },
+ {
+ "id": "aerialway",
+ "type": "line",
+ "source": "composite",
+ "source-layer": "road",
+ "minzoom": 13,
+ "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "class", "aerialway" ] ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-color": "hsl(230, 10%, 74%)",
+ "line-width": { "base": 1.5, "stops": [ [ 14, 0.5 ], [ 20, 1 ] ] }
+ }
+ },
+ {
+ "id": "admin-3-4-boundaries-bg",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444934295202.7542" },
+ "source": "composite",
+ "source-layer": "admin",
+ "filter": [ "all", [ ">=", "admin_level", 3 ], [ "==", "maritime", 0 ] ],
+ "layout": { "line-join": "bevel" },
+ "paint": {
+ "line-color": { "base": 1, "stops": [ [ 8, "hsl(35, 12%, 89%)" ], [ 16, "hsl(230, 49%, 90%)" ] ] },
+ "line-width": { "base": 1, "stops": [ [ 7, 3.75 ], [ 12, 5.5 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 7, 0 ], [ 8, 0.75 ] ] },
+ "line-dasharray": [ 1, 0 ],
+ "line-translate": [ 0, 0 ],
+ "line-blur": { "base": 1, "stops": [ [ 3, 0 ], [ 8, 3 ] ] }
+ }
+ },
+ {
+ "id": "admin-2-boundaries-bg",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444934295202.7542" },
+ "source": "composite",
+ "source-layer": "admin",
+ "minzoom": 1,
+ "filter": [ "all", [ "==", "admin_level", 2 ], [ "==", "maritime", 0 ] ],
+ "layout": { "line-join": "miter" },
+ "paint": {
+ "line-width": { "base": 1, "stops": [ [ 3, 3.5 ], [ 10, 8 ] ] },
+ "line-color": { "base": 1, "stops": [ [ 6, "hsl(35, 12%, 89%)" ], [ 8, "hsl(230, 49%, 90%)" ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 3, 0 ], [ 4, 0.5 ] ] },
+ "line-translate": [ 0, 0 ],
+ "line-blur": { "base": 1, "stops": [ [ 3, 0 ], [ 10, 2 ] ] }
+ }
+ },
+ {
+ "id": "admin-3-4-boundaries",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444934295202.7542" },
+ "source": "composite",
+ "source-layer": "admin",
+ "filter": [ "all", [ ">=", "admin_level", 3 ], [ "==", "maritime", 0 ] ],
+ "layout": { "line-join": "round", "line-cap": "round" },
+ "paint": {
+ "line-dasharray": { "base": 1, "stops": [ [ 6, [ 2, 0 ] ], [ 7, [ 2, 2, 6, 2 ] ] ] },
+ "line-width": { "base": 1, "stops": [ [ 7, 0.75 ], [ 12, 1.5 ] ] },
+ "line-opacity": { "base": 1, "stops": [ [ 2, 0 ], [ 3, 1 ] ] },
+ "line-color": { "base": 1, "stops": [ [ 3, "hsl(230, 14%, 77%)" ], [ 7, "hsl(230, 8%, 62%)" ] ] }
+ }
+ },
+ {
+ "id": "admin-2-boundaries",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444934295202.7542" },
+ "source": "composite",
+ "source-layer": "admin",
+ "minzoom": 1,
+ "filter": [ "all", [ "==", "admin_level", 2 ], [ "==", "disputed", 0 ], [ "==", "maritime", 0 ] ],
+ "layout": { "line-join": "round", "line-cap": "round" },
+ "paint": {
+ "line-color": "hsl(230, 8%, 51%)",
+ "line-width": { "base": 1, "stops": [ [ 3, 0.5 ], [ 10, 2 ] ] }
+ }
+ },
+ {
+ "id": "admin-2-boundaries-dispute",
+ "type": "line",
+ "metadata": { "mapbox:group": "1444934295202.7542" },
+ "source": "composite",
+ "source-layer": "admin",
+ "minzoom": 1,
+ "filter": [ "all", [ "==", "admin_level", 2 ], [ "==", "disputed", 1 ], [ "==", "maritime", 0 ] ],
+ "layout": { "line-join": "round" },
+ "paint": {
+ "line-dasharray": [ 1.5, 1.5 ],
+ "line-color": "hsl(230, 8%, 51%)",
+ "line-width": { "base": 1, "stops": [ [ 3, 0.5 ], [ 10, 2 ] ] }
+ }
+ },
+ {
+ "id": "housenum-label",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "housenum_label",
+ "minzoom": 17,
+ "layout": {
+ "text-field": "{house_num}",
+ "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ],
+ "text-padding": 4,
+ "text-max-width": 7,
+ "text-size": 9.5
+ },
+ "paint": {
+ "text-color": "hsl(35, 2%, 69%)",
+ "text-halo-color": "hsl(35, 8%, 85%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0
+ }
+ },
+ {
+ "id": "waterway-label",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "waterway_label",
+ "minzoom": 12,
+ "filter": [ "in", "class", "canal", "river" ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ],
+ "symbol-placement": "line",
+ "text-max-angle": 30,
+ "text-size": { "base": 1, "stops": [ [ 13, 12 ], [ 18, 16 ] ] }
+ },
+ "paint": {
+ "text-halo-width": 0.5,
+ "text-halo-color": "hsl(196, 80%, 70%)",
+ "text-color": "hsl(230, 48%, 44%)",
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-scalerank4-l15",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933456003.5437" },
+ "source": "composite",
+ "source-layer": "poi_label",
+ "minzoom": 17,
+ "filter": [
+ "all",
+ [ ">=", "localrank", 15 ],
+ [
+ "!in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ [ "==", "scalerank", 4 ]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": { "base": 1, "stops": [ [ 16, 11 ], [ 20, 13 ] ] },
+ "icon-image": "{maki}-11",
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-padding": 2,
+ "text-offset": [ 0, 0.65 ],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(26, 25%, 32%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-scalerank4-l1",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933456003.5437" },
+ "source": "composite",
+ "source-layer": "poi_label",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ [ "<=", "localrank", 14 ],
+ [
+ "!in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ [ "==", "scalerank", 4 ]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": { "base": 1, "stops": [ [ 16, 11 ], [ 20, 13 ] ] },
+ "icon-image": "{maki}-11",
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-padding": 1,
+ "text-offset": [ 0, 0.65 ],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(26, 25%, 32%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-parks_scalerank4",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933456003.5437" },
+ "source": "composite",
+ "source-layer": "poi_label",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ [
+ "in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ [ "==", "scalerank", 4 ]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": { "base": 1, "stops": [ [ 16, 11 ], [ 20, 13 ] ] },
+ "icon-image": "{maki}-11",
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-padding": 1,
+ "text-offset": [ 0, 0.65 ],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(100, 100%, 20%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-scalerank3",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933372896.5967" },
+ "source": "composite",
+ "source-layer": "poi_label",
+ "filter": [
+ "all",
+ [
+ "!in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ [ "==", "scalerank", 3 ]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": { "base": 1, "stops": [ [ 16, 11 ], [ 20, 13 ] ] },
+ "icon-image": "{maki}-11",
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-padding": 1,
+ "text-offset": [ 0, 0.65 ],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(26, 25%, 32%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-parks-scalerank3",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933372896.5967" },
+ "source": "composite",
+ "source-layer": "poi_label",
+ "filter": [
+ "all",
+ [
+ "in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ [ "==", "scalerank", 3 ]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": { "base": 1, "stops": [ [ 16, 11 ], [ 20, 13 ] ] },
+ "icon-image": "{maki}-11",
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-padding": 2,
+ "text-offset": [ 0, 0.65 ],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(100, 100%, 20%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "road-label-small",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933721429.3076" },
+ "source": "composite",
+ "source-layer": "road_label",
+ "minzoom": 15,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [
+ "!in",
+ "class",
+ "link",
+ "motorway",
+ "pedestrian",
+ "primary",
+ "secondary",
+ "street",
+ "street_limited",
+ "tertiary",
+ "trunk"
+ ]
+ ],
+ "layout": {
+ "text-size": { "base": 1, "stops": [ [ 15, 10 ], [ 20, 13 ] ] },
+ "text-max-angle": 30,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ],
+ "symbol-placement": "line",
+ "text-padding": 1,
+ "text-rotation-alignment": "map",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1.25,
+ "text-halo-blur": 1
+ }
+ },
+ {
+ "id": "road-label-medium",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933721429.3076" },
+ "source": "composite",
+ "source-layer": "road_label",
+ "minzoom": 11,
+ "filter": [
+ "all",
+ [ "==", "$type", "LineString" ],
+ [ "in", "class", "link", "pedestrian", "street", "street_limited" ]
+ ],
+ "layout": {
+ "text-size": { "base": 1, "stops": [ [ 11, 10 ], [ 20, 14 ] ] },
+ "text-max-angle": 30,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ],
+ "symbol-placement": "line",
+ "text-padding": 1,
+ "text-rotation-alignment": "map",
+ "text-field": ["format", ["get", "name_en"], {"text-color": "green"}],
+ "text-letter-spacing": 0.01
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "road-label-large",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933721429.3076" },
+ "source": "composite",
+ "source-layer": "road_label",
+ "filter": [ "in", "class", "motorway", "primary", "secondary", "tertiary", "trunk" ],
+ "layout": {
+ "text-size": { "base": 1, "stops": [ [ 9, 10 ], [ 20, 16 ] ] },
+ "text-max-angle": 30,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ],
+ "symbol-placement": "line",
+ "text-padding": 1,
+ "text-rotation-alignment": "map",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsla(0, 0%, 100%, 0.75)",
+ "text-halo-width": 1,
+ "text-halo-blur": 1
+ }
+ },
+ {
+ "id": "road-shields-black",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933575858.6992" },
+ "source": "composite",
+ "source-layer": "road_label",
+ "filter": [
+ "all",
+ [ "<=", "reflen", 6 ],
+ [
+ "!in",
+ "shield",
+ "at-expressway",
+ "at-motorway",
+ "at-state-b",
+ "bg-motorway",
+ "bg-national",
+ "ch-main",
+ "ch-motorway",
+ "cz-motorway",
+ "cz-road",
+ "de-motorway",
+ "e-road",
+ "fi-main",
+ "gr-motorway",
+ "gr-national",
+ "hr-motorway",
+ "hr-state",
+ "hu-main",
+ "hu-motorway",
+ "nz-state",
+ "pl-expressway",
+ "pl-motorway",
+ "pl-national",
+ "ro-county",
+ "ro-motorway",
+ "ro-national",
+ "rs-motorway",
+ "rs-state-1b",
+ "se-main",
+ "si-expressway",
+ "si-motorway",
+ "sk-highway",
+ "sk-road",
+ "us-interstate",
+ "us-interstate-business",
+ "us-interstate-duplex",
+ "us-interstate-truck",
+ "za-metropolitan",
+ "za-national",
+ "za-provincial",
+ "za-regional"
+ ]
+ ],
+ "layout": {
+ "text-size": 9,
+ "icon-image": "{shield}-{reflen}",
+ "icon-rotation-alignment": "viewport",
+ "text-max-angle": 38,
+ "symbol-spacing": { "base": 1, "stops": [ [ 11, 150 ], [ 14, 200 ] ] },
+ "text-font": [ "DIN Offc Pro Bold", "Arial Unicode MS Bold" ],
+ "symbol-placement": { "base": 1, "stops": [ [ 10, "point" ], [ 11, "line" ] ] },
+ "text-padding": 2,
+ "text-rotation-alignment": "viewport",
+ "text-field": "{ref}",
+ "text-letter-spacing": 0.05,
+ "icon-padding": 2
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 7%)",
+ "icon-halo-color": "rgba(0, 0, 0, 1)",
+ "icon-halo-width": 1,
+ "text-opacity": 1,
+ "icon-color": "white",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0
+ }
+ },
+ {
+ "id": "road-shields-white",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933575858.6992" },
+ "source": "composite",
+ "source-layer": "road_label",
+ "filter": [
+ "all",
+ [ "<=", "reflen", 6 ],
+ [
+ "in",
+ "shield",
+ "at-expressway",
+ "at-motorway",
+ "at-state-b",
+ "bg-motorway",
+ "bg-national",
+ "ch-main",
+ "ch-motorway",
+ "cz-motorway",
+ "cz-road",
+ "de-motorway",
+ "e-road",
+ "fi-main",
+ "gr-motorway",
+ "gr-national",
+ "hr-motorway",
+ "hr-state",
+ "hu-main",
+ "hu-motorway",
+ "nz-state",
+ "pl-expressway",
+ "pl-motorway",
+ "pl-national",
+ "ro-county",
+ "ro-motorway",
+ "ro-national",
+ "rs-motorway",
+ "rs-state-1b",
+ "se-main",
+ "si-expressway",
+ "si-motorway",
+ "sk-highway",
+ "sk-road",
+ "us-interstate",
+ "us-interstate-business",
+ "us-interstate-duplex",
+ "us-interstate-truck",
+ "za-metropolitan",
+ "za-national",
+ "za-provincial",
+ "za-regional"
+ ]
+ ],
+ "layout": {
+ "text-size": 9,
+ "icon-image": "{shield}-{reflen}",
+ "icon-rotation-alignment": "viewport",
+ "text-max-angle": 38,
+ "symbol-spacing": { "base": 1, "stops": [ [ 11, 150 ], [ 14, 200 ] ] },
+ "text-font": [ "DIN Offc Pro Bold", "Arial Unicode MS Bold" ],
+ "symbol-placement": { "base": 1, "stops": [ [ 10, "point" ], [ 11, "line" ] ] },
+ "text-padding": 2,
+ "text-rotation-alignment": "viewport",
+ "text-field": "{ref}",
+ "text-letter-spacing": 0.05,
+ "icon-padding": 2
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 100%)",
+ "icon-halo-color": "rgba(0, 0, 0, 1)",
+ "icon-halo-width": 1,
+ "text-opacity": 1,
+ "icon-color": "white",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0
+ }
+ },
+ {
+ "id": "motorway-junction",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933575858.6992" },
+ "source": "composite",
+ "source-layer": "motorway_junction",
+ "minzoom": 14,
+ "filter": [ "all", [ ">", "reflen", 0 ], [ "<=", "reflen", 9 ] ],
+ "layout": {
+ "text-field": "{ref}",
+ "text-size": 9,
+ "icon-image": "motorway-exit-{reflen}",
+ "text-font": [ "DIN Offc Pro Bold", "Arial Unicode MS Bold" ]
+ },
+ "paint": { "text-color": "hsl(0, 0%, 100%)", "text-translate": [ 0, 0 ] }
+ },
+ {
+ "id": "poi-scalerank2",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933358918.2366" },
+ "source": "composite",
+ "source-layer": "poi_label",
+ "filter": [
+ "all",
+ [
+ "!in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ [ "==", "scalerank", 2 ]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": { "base": 1, "stops": [ [ 14, 11 ], [ 20, 14 ] ] },
+ "icon-image": { "stops": [ [ 14, "{maki}-11" ], [ 15, "{maki}-15" ] ] },
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-padding": 2,
+ "text-offset": [ 0, 0.65 ],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(26, 25%, 32%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-parks-scalerank2",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933358918.2366" },
+ "source": "composite",
+ "source-layer": "poi_label",
+ "filter": [
+ "all",
+ [
+ "in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ [ "==", "scalerank", 2 ]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": { "base": 1, "stops": [ [ 14, 11 ], [ 20, 14 ] ] },
+ "icon-image": { "stops": [ [ 14, "{maki}-11" ], [ 15, "{maki}-15" ] ] },
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-padding": 2,
+ "text-offset": [ 0, 0.65 ],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(100, 100%, 20%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "rail-label",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "rail_station_label",
+ "minzoom": 12,
+ "filter": [ "!=", "maki", "entrance" ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": { "base": 1, "stops": [ [ 16, 11 ], [ 20, 13 ] ] },
+ "icon-image": "{network}",
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-offset": [ 0, 0.85 ],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": { "base": 1, "stops": [ [ 0, "" ], [ 13, "{name_en}" ] ] },
+ "text-letter-spacing": 0.01,
+ "icon-padding": 0,
+ "text-max-width": 7
+ },
+ "paint": {
+ "text-color": "hsl(230, 48%, 44%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "icon-halo-width": 4,
+ "icon-halo-color": "#fff",
+ "text-opacity": { "base": 1, "stops": [ [ 13.99, 0 ], [ 14, 1 ] ] },
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "water-label-sm",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933808272.805" },
+ "source": "composite",
+ "source-layer": "water_label",
+ "minzoom": 15,
+ "filter": [ "<=", "area", 10000 ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ],
+ "text-max-width": 7,
+ "text-size": { "base": 1, "stops": [ [ 16, 13 ], [ 20, 16 ] ] }
+ },
+ "paint": { "text-color": "hsl(230, 48%, 44%)" }
+ },
+ {
+ "id": "water-label",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933808272.805" },
+ "source": "composite",
+ "source-layer": "water_label",
+ "minzoom": 5,
+ "filter": [ ">", "area", 10000 ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ],
+ "text-max-width": 7,
+ "text-size": { "base": 1, "stops": [ [ 13, 13 ], [ 18, 18 ] ] }
+ },
+ "paint": { "text-color": "hsl(230, 48%, 44%)" }
+ },
+ {
+ "id": "place-residential",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "maxzoom": 18,
+ "filter": [
+ "all",
+ [ "in", "$type", "LineString", "Point", "Polygon" ],
+ [ "all", [ "<=", "localrank", 10 ], [ "==", "type", "residential" ] ]
+ ],
+ "layout": {
+ "text-line-height": 1.2,
+ "text-size": { "base": 1, "stops": [ [ 10, 11 ], [ 18, 14 ] ] },
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ],
+ "text-padding": 2,
+ "text-offset": [ 0, 0 ],
+ "text-rotation-alignment": "viewport",
+ "text-field": "{name_en}",
+ "text-max-width": 7
+ },
+ "paint": {
+ "text-color": "hsl(26, 25%, 32%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-parks-scalerank1",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933322393.2852" },
+ "source": "composite",
+ "source-layer": "poi_label",
+ "filter": [
+ "all",
+ [
+ "in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ [ "<=", "scalerank", 1 ]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": { "base": 1, "stops": [ [ 10, 11 ], [ 18, 14 ] ] },
+ "icon-image": { "stops": [ [ 13, "{maki}-11" ], [ 14, "{maki}-15" ] ] },
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-padding": 2,
+ "text-offset": [ 0, 0.65 ],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(100, 100%, 20%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "poi-scalerank1",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444933322393.2852" },
+ "source": "composite",
+ "source-layer": "poi_label",
+ "filter": [
+ "all",
+ [
+ "!in",
+ "maki",
+ "campsite",
+ "cemetery",
+ "dog-park",
+ "garden",
+ "golf",
+ "park",
+ "picnic-site",
+ "playground",
+ "zoo"
+ ],
+ [ "<=", "scalerank", 1 ]
+ ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": { "base": 1, "stops": [ [ 10, 11 ], [ 18, 14 ] ] },
+ "icon-image": { "stops": [ [ 13, "{maki}-11" ], [ 14, "{maki}-15" ] ] },
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-padding": 2,
+ "text-offset": [ 0, 0.65 ],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(26, 25%, 32%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "airport-label",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "airport_label",
+ "minzoom": 9,
+ "filter": [ "<=", "scalerank", 2 ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": { "base": 1, "stops": [ [ 10, 12 ], [ 18, 18 ] ] },
+ "icon-image": { "stops": [ [ 12, "{maki}-11" ], [ 13, "{maki}-15" ] ] },
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-padding": 2,
+ "text-offset": [ 0, 0.75 ],
+ "text-rotation-alignment": "viewport",
+ "text-anchor": "top",
+ "text-field": { "stops": [ [ 11, "{ref}" ], [ 12, "{name_en}" ] ] },
+ "text-letter-spacing": 0.01,
+ "text-max-width": 9
+ },
+ "paint": {
+ "text-color": "hsl(230, 48%, 44%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 0.5,
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "place-islet-archipelago-aboriginal",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "maxzoom": 16,
+ "filter": [ "in", "type", "aboriginal_lands", "archipelago", "islet" ],
+ "layout": {
+ "text-line-height": 1.2,
+ "text-size": { "base": 1, "stops": [ [ 10, 11 ], [ 18, 16 ] ] },
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ],
+ "text-padding": 2,
+ "text-offset": [ 0, 0 ],
+ "text-rotation-alignment": "viewport",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 8
+ },
+ "paint": {
+ "text-color": "hsl(230, 29%, 35%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "place-neighbourhood",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 10,
+ "maxzoom": 16,
+ "filter": [ "==", "type", "neighbourhood" ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-transform": "uppercase",
+ "text-letter-spacing": 0.1,
+ "text-max-width": 7,
+ "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ],
+ "text-padding": 3,
+ "text-size": { "base": 1, "stops": [ [ 12, 11 ], [ 16, 16 ] ] }
+ },
+ "paint": {
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1,
+ "text-color": "hsl(230, 29%, 35%)",
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "place-suburb",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 10,
+ "maxzoom": 16,
+ "filter": [ "==", "type", "suburb" ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-transform": "uppercase",
+ "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ],
+ "text-letter-spacing": 0.15,
+ "text-max-width": 7,
+ "text-padding": 3,
+ "text-size": { "base": 1, "stops": [ [ 11, 11 ], [ 15, 18 ] ] }
+ },
+ "paint": {
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1,
+ "text-color": "hsl(230, 29%, 35%)",
+ "text-halo-blur": 0.5
+ }
+ },
+ {
+ "id": "place-hamlet",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 10,
+ "maxzoom": 16,
+ "filter": [ "==", "type", "hamlet" ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ],
+ "text-size": { "base": 1, "stops": [ [ 12, 11.5 ], [ 15, 16 ] ] }
+ },
+ "paint": {
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1.25,
+ "text-color": "hsl(0, 0%, 0%)"
+ }
+ },
+ {
+ "id": "place-village",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 8,
+ "maxzoom": 15,
+ "filter": [ "==", "type", "village" ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ],
+ "text-max-width": 7,
+ "text-size": { "base": 1, "stops": [ [ 10, 11.5 ], [ 16, 18 ] ] }
+ },
+ "paint": {
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1.25,
+ "text-color": "hsl(0, 0%, 0%)"
+ }
+ },
+ {
+ "id": "place-town",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 6,
+ "maxzoom": 15,
+ "filter": [ "==", "type", "town" ],
+ "layout": {
+ "icon-image": "dot-9",
+ "text-font": {
+ "base": 1,
+ "stops": [
+ [ 11, [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ] ],
+ [ 12, [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ] ]
+ ]
+ },
+ "text-offset": { "base": 1, "stops": [ [ 7, [ 0, -0.15 ] ], [ 8, [ 0, 0 ] ] ] },
+ "text-anchor": { "base": 1, "stops": [ [ 7, "bottom" ], [ 8, "center" ] ] },
+ "text-field": "{name_en}",
+ "text-max-width": 7,
+ "text-size": { "base": 1, "stops": [ [ 7, 11.5 ], [ 15, 20 ] ] }
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1.25,
+ "icon-opacity": { "base": 1, "stops": [ [ 7.99, 1 ], [ 8, 0 ] ] }
+ }
+ },
+ {
+ "id": "place-island",
+ "type": "symbol",
+ "source": "composite",
+ "source-layer": "place_label",
+ "maxzoom": 16,
+ "filter": [ "==", "type", "island" ],
+ "layout": {
+ "text-line-height": 1.2,
+ "text-size": { "base": 1, "stops": [ [ 10, 11 ], [ 18, 16 ] ] },
+ "text-max-angle": 38,
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ],
+ "text-padding": 2,
+ "text-offset": [ 0, 0 ],
+ "text-rotation-alignment": "viewport",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.01,
+ "text-max-width": 7
+ },
+ "paint": {
+ "text-color": "hsl(230, 29%, 35%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "place-city-sm",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444862510685.128" },
+ "source": "composite",
+ "source-layer": "place_label",
+ "maxzoom": 14,
+ "filter": [ "all", [ "!in", "scalerank", 0, 1, 2, 3, 4, 5 ], [ "==", "type", "city" ] ],
+ "layout": {
+ "text-size": { "base": 1, "stops": [ [ 6, 12 ], [ 14, 22 ] ] },
+ "icon-image": "dot-9",
+ "text-font": {
+ "base": 1,
+ "stops": [
+ [ 7, [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ] ],
+ [ 8, [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ] ]
+ ]
+ },
+ "text-offset": { "base": 1, "stops": [ [ 7.99, [ 0, -0.2 ] ], [ 8, [ 0, 0 ] ] ] },
+ "text-anchor": { "base": 1, "stops": [ [ 7, "bottom" ], [ 8, "center" ] ] },
+ "text-field": "{name_en}",
+ "text-max-width": 7
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1.25,
+ "icon-opacity": { "base": 1, "stops": [ [ 7.99, 1 ], [ 8, 0 ] ] }
+ }
+ },
+ {
+ "id": "place-city-md-s",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444862510685.128" },
+ "source": "composite",
+ "source-layer": "place_label",
+ "maxzoom": 14,
+ "filter": [
+ "all",
+ [ "in", "ldir", "E", "S", "SE", "SW" ],
+ [ "in", "scalerank", 3, 4, 5 ],
+ [ "==", "type", "city" ]
+ ],
+ "layout": {
+ "text-field": "{name_en}",
+ "icon-image": "dot-10",
+ "text-anchor": { "base": 1, "stops": [ [ 7, "top" ], [ 8, "center" ] ] },
+ "text-offset": { "base": 1, "stops": [ [ 7.99, [ 0, 0.1 ] ], [ 8, [ 0, 0 ] ] ] },
+ "text-font": {
+ "base": 1,
+ "stops": [
+ [ 7, [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ] ],
+ [ 8, [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ] ]
+ ]
+ },
+ "text-size": { "base": 0.9, "stops": [ [ 5, 12 ], [ 12, 22 ] ] }
+ },
+ "paint": {
+ "text-halo-width": 1,
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-blur": 1,
+ "icon-opacity": { "base": 1, "stops": [ [ 7.99, 1 ], [ 8, 0 ] ] }
+ }
+ },
+ {
+ "id": "place-city-md-n",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444862510685.128" },
+ "source": "composite",
+ "source-layer": "place_label",
+ "maxzoom": 14,
+ "filter": [
+ "all",
+ [ "in", "ldir", "N", "NE", "NW", "W" ],
+ [ "in", "scalerank", 3, 4, 5 ],
+ [ "==", "type", "city" ]
+ ],
+ "layout": {
+ "icon-image": "dot-10",
+ "text-font": {
+ "base": 1,
+ "stops": [
+ [ 7, [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ] ],
+ [ 8, [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ] ]
+ ]
+ },
+ "text-offset": { "base": 1, "stops": [ [ 7.99, [ 0, -0.25 ] ], [ 8, [ 0, 0 ] ] ] },
+ "text-anchor": { "base": 1, "stops": [ [ 7, "bottom" ], [ 8, "center" ] ] },
+ "text-field": "{name_en}",
+ "text-max-width": 7,
+ "text-size": { "base": 0.9, "stops": [ [ 5, 12 ], [ 12, 22 ] ] }
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1,
+ "icon-opacity": { "base": 1, "stops": [ [ 7.99, 1 ], [ 8, 0 ] ] },
+ "text-halo-blur": 1
+ }
+ },
+ {
+ "id": "place-city-lg-s",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444862510685.128" },
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 1,
+ "maxzoom": 14,
+ "filter": [
+ "all",
+ [ "in", "ldir", "E", "S", "SE", "SW" ],
+ [ "<=", "scalerank", 2 ],
+ [ "==", "type", "city" ]
+ ],
+ "layout": {
+ "icon-image": "dot-11",
+ "text-font": {
+ "base": 1,
+ "stops": [
+ [ 7, [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ] ],
+ [ 8, [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ] ]
+ ]
+ },
+ "text-offset": { "base": 1, "stops": [ [ 7.99, [ 0, 0.15 ] ], [ 8, [ 0, 0 ] ] ] },
+ "text-anchor": { "base": 1, "stops": [ [ 7, "top" ], [ 8, "center" ] ] },
+ "text-field": "{name_en}",
+ "text-max-width": 7,
+ "text-size": { "base": 0.9, "stops": [ [ 4, 12 ], [ 10, 22 ] ] }
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1,
+ "icon-opacity": { "base": 1, "stops": [ [ 7.99, 1 ], [ 8, 0 ] ] },
+ "text-halo-blur": 1
+ }
+ },
+ {
+ "id": "place-city-lg-n",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444862510685.128" },
+ "source": "composite",
+ "source-layer": "place_label",
+ "minzoom": 1,
+ "maxzoom": 14,
+ "filter": [
+ "all",
+ [ "in", "ldir", "N", "NE", "NW", "W" ],
+ [ "<=", "scalerank", 2 ],
+ [ "==", "type", "city" ]
+ ],
+ "layout": {
+ "icon-image": "dot-11",
+ "text-font": {
+ "base": 1,
+ "stops": [
+ [ 7, [ "DIN Offc Pro Regular", "Arial Unicode MS Regular" ] ],
+ [ 8, [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ] ]
+ ]
+ },
+ "text-offset": { "base": 1, "stops": [ [ 7.99, [ 0, -0.25 ] ], [ 8, [ 0, 0 ] ] ] },
+ "text-anchor": { "base": 1, "stops": [ [ 7, "bottom" ], [ 8, "center" ] ] },
+ "text-field": "{name_en}",
+ "text-max-width": 7,
+ "text-size": { "base": 0.9, "stops": [ [ 4, 12 ], [ 10, 22 ] ] }
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-opacity": 1,
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1,
+ "icon-opacity": { "base": 1, "stops": [ [ 7.99, 1 ], [ 8, 0 ] ] },
+ "text-halo-blur": 1
+ }
+ },
+ {
+ "id": "marine-label-sm-ln",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444856087950.3635" },
+ "source": "composite",
+ "source-layer": "marine_label",
+ "minzoom": 3,
+ "maxzoom": 10,
+ "filter": [ "all", [ "==", "$type", "LineString" ], [ ">=", "labelrank", 4 ] ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": { "base": 1, "stops": [ [ 3, 12 ], [ 6, 16 ] ] },
+ "symbol-spacing": { "base": 1, "stops": [ [ 4, 100 ], [ 6, 400 ] ] },
+ "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ],
+ "symbol-placement": "line",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.1,
+ "text-max-width": 5
+ },
+ "paint": { "text-color": "hsl(205, 83%, 88%)" }
+ },
+ {
+ "id": "marine-label-sm-pt",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444856087950.3635" },
+ "source": "composite",
+ "source-layer": "marine_label",
+ "minzoom": 3,
+ "maxzoom": 10,
+ "filter": [ "all", [ "==", "$type", "Point" ], [ ">=", "labelrank", 4 ] ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-max-width": 5,
+ "text-letter-spacing": 0.1,
+ "text-line-height": 1.5,
+ "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ],
+ "text-size": { "base": 1, "stops": [ [ 3, 12 ], [ 6, 16 ] ] }
+ },
+ "paint": { "text-color": "hsl(205, 83%, 88%)" }
+ },
+ {
+ "id": "marine-label-md-ln",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444856087950.3635" },
+ "source": "composite",
+ "source-layer": "marine_label",
+ "minzoom": 2,
+ "maxzoom": 8,
+ "filter": [ "all", [ "==", "$type", "LineString" ], [ "in", "labelrank", 2, 3 ] ],
+ "layout": {
+ "text-line-height": 1.1,
+ "text-size": { "base": 1.1, "stops": [ [ 2, 12 ], [ 5, 20 ] ] },
+ "symbol-spacing": 250,
+ "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ],
+ "symbol-placement": "line",
+ "text-field": "{name_en}",
+ "text-letter-spacing": 0.15,
+ "text-max-width": 5
+ },
+ "paint": { "text-color": "hsl(205, 83%, 88%)" }
+ },
+ {
+ "id": "marine-label-md-pt",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444856087950.3635" },
+ "source": "composite",
+ "source-layer": "marine_label",
+ "minzoom": 2,
+ "maxzoom": 8,
+ "filter": [ "all", [ "==", "$type", "Point" ], [ "in", "labelrank", 2, 3 ] ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-max-width": 5,
+ "text-letter-spacing": 0.15,
+ "text-line-height": 1.5,
+ "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ],
+ "text-size": { "base": 1.1, "stops": [ [ 2, 14 ], [ 5, 20 ] ] }
+ },
+ "paint": { "text-color": "hsl(205, 83%, 88%)" }
+ },
+ {
+ "id": "marine-label-lg-ln",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444856087950.3635" },
+ "source": "composite",
+ "source-layer": "marine_label",
+ "minzoom": 1,
+ "maxzoom": 4,
+ "filter": [ "all", [ "==", "$type", "LineString" ], [ "==", "labelrank", 1 ] ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-max-width": 4,
+ "text-letter-spacing": 0.25,
+ "text-line-height": 1.1,
+ "symbol-placement": "line",
+ "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ],
+ "text-size": { "base": 1, "stops": [ [ 1, 14 ], [ 4, 30 ] ] }
+ },
+ "paint": { "text-color": "hsl(205, 83%, 88%)" }
+ },
+ {
+ "id": "marine-label-lg-pt",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444856087950.3635" },
+ "source": "composite",
+ "source-layer": "marine_label",
+ "minzoom": 1,
+ "maxzoom": 4,
+ "filter": [ "all", [ "==", "$type", "Point" ], [ "==", "labelrank", 1 ] ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-max-width": 4,
+ "text-letter-spacing": 0.25,
+ "text-line-height": 1.5,
+ "text-font": [ "DIN Offc Pro Italic", "Arial Unicode MS Regular" ],
+ "text-size": { "base": 1, "stops": [ [ 1, 14 ], [ 4, 30 ] ] }
+ },
+ "paint": { "text-color": "hsl(205, 83%, 88%)" }
+ },
+ {
+ "id": "state-label-sm",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444856151690.9143" },
+ "source": "composite",
+ "source-layer": "state_label",
+ "minzoom": 3,
+ "maxzoom": 9,
+ "filter": [ "<", "area", 20000 ],
+ "layout": {
+ "text-size": { "base": 1, "stops": [ [ 6, 10 ], [ 9, 14 ] ] },
+ "text-transform": "uppercase",
+ "text-font": [ "DIN Offc Pro Bold", "Arial Unicode MS Bold" ],
+ "text-field": { "base": 1, "stops": [ [ 0, "{abbr}" ], [ 6, "{name_en}" ] ] },
+ "text-letter-spacing": 0.15,
+ "text-max-width": 5
+ },
+ "paint": {
+ "text-opacity": 1,
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "state-label-md",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444856151690.9143" },
+ "source": "composite",
+ "source-layer": "state_label",
+ "minzoom": 3,
+ "maxzoom": 8,
+ "filter": [ "all", [ "<", "area", 80000 ], [ ">=", "area", 20000 ] ],
+ "layout": {
+ "text-size": { "base": 1, "stops": [ [ 5, 10 ], [ 8, 16 ] ] },
+ "text-transform": "uppercase",
+ "text-font": [ "DIN Offc Pro Bold", "Arial Unicode MS Bold" ],
+ "text-field": { "base": 1, "stops": [ [ 0, "{abbr}" ], [ 5, "{name_en}" ] ] },
+ "text-letter-spacing": 0.15,
+ "text-max-width": 6
+ },
+ "paint": {
+ "text-opacity": 1,
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "state-label-lg",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444856151690.9143" },
+ "source": "composite",
+ "source-layer": "state_label",
+ "minzoom": 3,
+ "maxzoom": 7,
+ "filter": [ ">=", "area", 80000 ],
+ "layout": {
+ "text-size": { "base": 1, "stops": [ [ 4, 10 ], [ 7, 18 ] ] },
+ "text-transform": "uppercase",
+ "text-font": [ "DIN Offc Pro Bold", "Arial Unicode MS Bold" ],
+ "text-padding": 1,
+ "text-field": { "base": 1, "stops": [ [ 0, "{abbr}" ], [ 4, "{name_en}" ] ] },
+ "text-letter-spacing": 0.15,
+ "text-max-width": 6
+ },
+ "paint": {
+ "text-opacity": 1,
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": "hsl(0, 0%, 100%)",
+ "text-halo-width": 1
+ }
+ },
+ {
+ "id": "country-label-sm",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444856144497.7825" },
+ "source": "composite",
+ "source-layer": "country_label",
+ "minzoom": 1,
+ "maxzoom": 10,
+ "filter": [ ">=", "scalerank", 5 ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-max-width": 6,
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-size": { "base": 0.9, "stops": [ [ 5, 14 ], [ 9, 22 ] ] }
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": { "base": 1, "stops": [ [ 2, "rgba(255,255,255,0.75)" ], [ 3, "hsl(0, 0%, 100%)" ] ] },
+ "text-halo-width": 1.25
+ }
+ },
+ {
+ "id": "country-label-md",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444856144497.7825" },
+ "source": "composite",
+ "source-layer": "country_label",
+ "minzoom": 1,
+ "maxzoom": 8,
+ "filter": [ "in", "scalerank", 3, 4 ],
+ "layout": {
+ "text-field": { "base": 1, "stops": [ [ 0, "{code}" ], [ 2, "{name_en}" ] ] },
+ "text-max-width": 6,
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-size": { "base": 1, "stops": [ [ 3, 10 ], [ 8, 24 ] ] }
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": { "base": 1, "stops": [ [ 2, "rgba(255,255,255,0.75)" ], [ 3, "hsl(0, 0%, 100%)" ] ] },
+ "text-halo-width": 1.25
+ }
+ },
+ {
+ "id": "country-label-lg",
+ "type": "symbol",
+ "metadata": { "mapbox:group": "1444856144497.7825" },
+ "source": "composite",
+ "source-layer": "country_label",
+ "minzoom": 1,
+ "maxzoom": 7,
+ "filter": [ "in", "scalerank", 1, 2 ],
+ "layout": {
+ "text-field": "{name_en}",
+ "text-max-width": { "base": 1, "stops": [ [ 0, 5 ], [ 3, 6 ] ] },
+ "text-font": [ "DIN Offc Pro Medium", "Arial Unicode MS Regular" ],
+ "text-size": { "base": 1, "stops": [ [ 1, 10 ], [ 6, 24 ] ] }
+ },
+ "paint": {
+ "text-color": "hsl(0, 0%, 0%)",
+ "text-halo-color": { "base": 1, "stops": [ [ 2, "rgba(255,255,255,0.75)" ], [ 3, "hsl(0, 0%, 100%)" ] ] },
+ "text-halo-width": 1.25
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/benchmark/parse/filter.benchmark.cpp b/benchmark/parse/filter.benchmark.cpp
index 1ae2b0f2bc..7f94d9d744 100644
--- a/benchmark/parse/filter.benchmark.cpp
+++ b/benchmark/parse/filter.benchmark.cpp
@@ -23,7 +23,7 @@ static void Parse_Filter(benchmark::State& state) {
static void Parse_EvaluateFilter(benchmark::State& state) {
const style::Filter filter = parse(R"FILTER(["==", "foo", "bar"])FILTER");
const StubGeometryTileFeature feature = { {}, FeatureType::Unknown , {}, {{ "foo", std::string("bar") }} };
- const style::expression::EvaluationContext context = { &feature };
+ const style::expression::EvaluationContext context(&feature);
while (state.KeepRunning()) {
filter(context);
diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp
index 97b143b3d9..22ae57c2be 100644
--- a/include/mbgl/style/expression/expression.hpp
+++ b/include/mbgl/style/expression/expression.hpp
@@ -25,18 +25,26 @@ public:
class EvaluationContext {
public:
- EvaluationContext(float zoom_) : zoom(zoom_), feature(nullptr) {}
- EvaluationContext(GeometryTileFeature const * feature_) : zoom(optional<float>()), feature(feature_) {}
+ EvaluationContext() = default;
+ explicit EvaluationContext(float zoom_) : zoom(zoom_) {}
+ explicit EvaluationContext(GeometryTileFeature const * feature_) : feature(feature_) {}
EvaluationContext(float zoom_, GeometryTileFeature const * feature_) :
zoom(zoom_), feature(feature_)
{}
EvaluationContext(optional<float> zoom_, GeometryTileFeature const * feature_, optional<double> colorRampParameter_) :
zoom(std::move(zoom_)), feature(feature_), colorRampParameter(std::move(colorRampParameter_))
{}
-
+
+ EvaluationContext& withFormattedSection(const Value* formattedSection_) noexcept {
+ formattedSection = formattedSection_;
+ return *this;
+ };
+
optional<float> zoom;
- GeometryTileFeature const * feature;
+ GeometryTileFeature const * feature = nullptr;
optional<double> colorRampParameter;
+ // Contains formatted section object, std::unordered_map<std::string, Value>.
+ const Value* formattedSection = nullptr;
};
template <typename T>
@@ -134,6 +142,7 @@ enum class Kind : int32_t {
All,
Comparison,
FormatExpression,
+ FormatSectionOverride
};
class Expression {
diff --git a/include/mbgl/style/expression/format_expression.hpp b/include/mbgl/style/expression/format_expression.hpp
index b00674a88e..180df0139d 100644
--- a/include/mbgl/style/expression/format_expression.hpp
+++ b/include/mbgl/style/expression/format_expression.hpp
@@ -1,11 +1,7 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/expression/formatted.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
-#include <mbgl/style/conversion.hpp>
-
-#include <memory>
namespace mbgl {
namespace style {
@@ -14,16 +10,18 @@ namespace expression {
struct FormatExpressionSection {
FormatExpressionSection(std::unique_ptr<Expression> text_,
optional<std::unique_ptr<Expression>> fontScale_,
- optional<std::unique_ptr<Expression>> textFont_);
+ optional<std::unique_ptr<Expression>> textFont_,
+ optional<std::unique_ptr<Expression>> textColor_);
std::shared_ptr<Expression> text;
optional<std::shared_ptr<Expression>> fontScale;
optional<std::shared_ptr<Expression>> textFont;
+ optional<std::shared_ptr<Expression>> textColor;
};
-class FormatExpression : public Expression {
+class FormatExpression final : public Expression {
public:
- FormatExpression(std::vector<FormatExpressionSection> sections);
+ explicit FormatExpression(std::vector<FormatExpressionSection> sections);
EvaluationResult evaluate(const EvaluationContext&) const override;
static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&);
@@ -38,13 +36,12 @@ public:
return { nullopt };
}
+ const std::vector<FormatExpressionSection>& getSections() const { return sections; }
+
mbgl::Value serialize() const override;
std::string getOperator() const override { return "format"; }
private:
std::vector<FormatExpressionSection> sections;
- std::unique_ptr<Expression> text;
- optional<std::unique_ptr<Expression>> fontScale;
- optional<std::unique_ptr<Expression>> textFont;
};
} // namespace expression
diff --git a/include/mbgl/style/expression/format_section_override.hpp b/include/mbgl/style/expression/format_section_override.hpp
new file mode 100644
index 0000000000..7dc3a8dbb4
--- /dev/null
+++ b/include/mbgl/style/expression/format_section_override.hpp
@@ -0,0 +1,82 @@
+#pragma once
+
+#include <mbgl/style/expression/expression.hpp>
+#include <mbgl/renderer/possibly_evaluated_property_value.hpp>
+
+namespace mbgl {
+namespace style {
+namespace expression {
+
+template<class T>
+class FormatSectionOverride final : public Expression {
+public:
+ FormatSectionOverride(const type::Type& type_,
+ PossiblyEvaluatedPropertyValue<T> defaultValue_,
+ std::string propertyName_) :
+ Expression(Kind::FormatSectionOverride, type_),
+ defaultValue(std::move(defaultValue_)),
+ propertyName(std::move(propertyName_))
+ {}
+
+ EvaluationResult evaluate(const EvaluationContext& context) const final {
+ using Object = std::unordered_map<std::string, expression::Value>;
+ if (context.formattedSection &&
+ context.formattedSection->is<Object>()) {
+ const auto& section = context.formattedSection->get<Object>();
+ if (section.find(propertyName) != section.end()) {
+ return section.at(propertyName);
+ }
+ }
+ return defaultValue.evaluate(*context.feature, *context.zoom, T());
+ }
+
+ void eachChild(const std::function<void(const Expression&)>& fn) const final {
+ defaultValue.match([&fn] (const style::PropertyExpression<T>& e) { fn(e.getExpression()); },
+ [] (const T&) {});
+ }
+
+ bool operator==(const Expression& e) const final {
+ if (e.getKind() == Kind::FormatSectionOverride) {
+ const auto* other = static_cast<const FormatSectionOverride*>(&e);
+
+ if (getType() != other->getType() || propertyName != other->propertyName) {
+ return false;
+ }
+
+ // Check that default values or property expressions are equal.
+ return defaultValue.match(
+ [other] (const style::PropertyExpression<T>& thisExpr) {
+ return other->defaultValue.match([&thisExpr] (const style::PropertyExpression<T>& otherExpr) {
+ return thisExpr == otherExpr;
+ },
+ [] (const T&) {
+ return false;
+ });
+ },
+ [other] (const T& thisValue) {
+ return other->defaultValue.match([&thisValue] (const T& otherValue) {
+ return thisValue == otherValue;
+ },
+ [] (const style::PropertyExpression<T>&) {
+ return false;
+ });
+ });
+ }
+
+ return false;
+ }
+
+ std::vector<optional<Value>> possibleOutputs() const final {
+ return {nullopt};
+ }
+
+ std::string getOperator() const final { return "format-section-override"; }
+
+private:
+ PossiblyEvaluatedPropertyValue<T> defaultValue;
+ std::string propertyName;
+};
+
+} // namespace expression
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/expression/formatted.hpp b/include/mbgl/style/expression/formatted.hpp
index 9e7e7308cb..f4f08e9197 100644
--- a/include/mbgl/style/expression/formatted.hpp
+++ b/include/mbgl/style/expression/formatted.hpp
@@ -1,9 +1,9 @@
#pragma once
#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/color.hpp>
#include <mbgl/util/font_stack.hpp>
#include <mbgl/util/optional.hpp>
-#include <mbgl/util/variant.hpp>
#include <vector>
#include <string>
@@ -12,15 +12,25 @@ namespace mbgl {
namespace style {
namespace expression {
+extern const char* const kFormattedSectionFontScale;
+extern const char* const kFormattedSectionTextFont;
+extern const char* const kFormattedSectionTextColor;
+
struct FormattedSection {
- FormattedSection(std::string text_, optional<double> fontScale_, optional<FontStack> fontStack_)
+ FormattedSection(std::string text_,
+ optional<double> fontScale_,
+ optional<FontStack> fontStack_,
+ optional<Color> textColor_)
: text(std::move(text_))
, fontScale(std::move(fontScale_))
, fontStack(std::move(fontStack_))
+ , textColor(std::move(textColor_))
{}
+
std::string text;
optional<double> fontScale;
optional<FontStack> fontStack;
+ optional<Color> textColor;
};
class Formatted {
@@ -28,7 +38,7 @@ public:
Formatted() = default;
Formatted(const char* plainU8String) {
- sections.emplace_back(std::string(plainU8String), nullopt, nullopt);
+ sections.emplace_back(std::string(plainU8String), nullopt, nullopt, nullopt);
}
Formatted(std::vector<FormattedSection> sections_)
diff --git a/include/mbgl/style/property_expression.hpp b/include/mbgl/style/property_expression.hpp
index b198de02b2..32983e2380 100644
--- a/include/mbgl/style/property_expression.hpp
+++ b/include/mbgl/style/property_expression.hpp
@@ -1,7 +1,6 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/expression/value.hpp>
#include <mbgl/style/expression/is_constant.hpp>
#include <mbgl/style/expression/interpolate.hpp>
#include <mbgl/style/expression/step.hpp>
@@ -11,46 +10,38 @@
namespace mbgl {
namespace style {
-template <class T>
-class PropertyExpression {
+class PropertyExpressionBase {
public:
- // Second parameter to be used only for conversions from legacy functions.
- PropertyExpression(std::unique_ptr<expression::Expression> expression_, optional<T> defaultValue_ = {})
- : expression(std::move(expression_)),
- defaultValue(std::move(defaultValue_)),
- zoomCurve(expression::findZoomCurveChecked(expression.get())) {
- }
+ explicit PropertyExpressionBase(std::unique_ptr<expression::Expression>);
- bool isZoomConstant() const { return expression::isZoomConstant(*expression); }
- bool isFeatureConstant() const { return expression::isFeatureConstant(*expression); }
+ bool isZoomConstant() const noexcept;
+ bool isFeatureConstant() const noexcept;
+ bool canEvaluateWith(const expression::EvaluationContext&) const noexcept;
+ float interpolationFactor(const Range<float>&, const float) const noexcept;
+ Range<float> getCoveringStops(const float, const float) const noexcept;
+ const expression::Expression& getExpression() const noexcept;
- T evaluate(float zoom) const {
- assert(!expression::isZoomConstant(*expression));
- assert(expression::isFeatureConstant(*expression));
- const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext(zoom, nullptr));
- if (result) {
- const optional<T> typed = expression::fromExpressionValue<T>(*result);
- return typed ? *typed : defaultValue ? *defaultValue : T();
- }
- return defaultValue ? *defaultValue : T();
- }
+ bool useIntegerZoom = false;
- template <class Feature>
- T evaluate(const Feature& feature, T finalDefaultValue) const {
- assert(expression::isZoomConstant(*expression));
- assert(!expression::isFeatureConstant(*expression));
- const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext(&feature));
- if (result) {
- const optional<T> typed = expression::fromExpressionValue<T>(*result);
- return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue;
- }
- return defaultValue ? *defaultValue : finalDefaultValue;
+protected:
+ std::shared_ptr<const expression::Expression> expression;
+ variant<std::nullptr_t, const expression::Interpolate*, const expression::Step*> zoomCurve;
+ bool isZoomConstant_;
+ bool isFeatureConstant_;
+};
+
+template <class T>
+class PropertyExpression final : public PropertyExpressionBase {
+public:
+ // Second parameter to be used only for conversions from legacy functions.
+ PropertyExpression(std::unique_ptr<expression::Expression> expression_, optional<T> defaultValue_ = nullopt)
+ : PropertyExpressionBase(std::move(expression_)),
+ defaultValue(std::move(defaultValue_)) {
}
- template <class Feature>
- T evaluate(float zoom, const Feature& feature, T finalDefaultValue) const {
- assert(!expression::isFeatureConstant(*expression));
- const expression::EvaluationResult result = expression->evaluate(expression::EvaluationContext({zoom}, &feature));
+ T evaluate(const expression::EvaluationContext& context, T finalDefaultValue = T()) const {
+ assert(canEvaluateWith(context));
+ const expression::EvaluationResult result = expression->evaluate(context);
if (result) {
const optional<T> typed = expression::fromExpressionValue<T>(*result);
return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue;
@@ -58,59 +49,29 @@ public:
return defaultValue ? *defaultValue : finalDefaultValue;
}
- float interpolationFactor(const Range<float>& inputLevels, const float inputValue) const {
- return zoomCurve.match(
- [](std::nullptr_t) {
- assert(false);
- return 0.0f;
- },
- [&](const expression::Interpolate* z) {
- return z->interpolationFactor(Range<double> { inputLevels.min, inputLevels.max }, inputValue);
- },
- [&](const expression::Step*) {
- return 0.0f;
- }
- );
+ T evaluate(float zoom) const {
+ return evaluate(expression::EvaluationContext(zoom));
}
- Range<float> getCoveringStops(const float lower, const float upper) const {
- return zoomCurve.match(
- [](std::nullptr_t) {
- assert(false);
- return Range<float>(0.0f, 0.0f);
- },
- [&](auto z) {
- return z->getCoveringStops(lower, upper);
- }
- );
+ T evaluate(const GeometryTileFeature& feature, T finalDefaultValue) const {
+ return evaluate(expression::EvaluationContext(&feature), finalDefaultValue);
}
- // Return the range obtained by evaluating the function at each of the zoom levels in zoomRange
- template <class Feature>
- Range<T> evaluate(const Range<float>& zoomRange, const Feature& feature, T finalDefaultValue) {
- return Range<T> {
- evaluate(zoomRange.min, feature, finalDefaultValue),
- evaluate(zoomRange.max, feature, finalDefaultValue)
- };
+ T evaluate(float zoom, const GeometryTileFeature& feature, T finalDefaultValue) const {
+ return evaluate(expression::EvaluationContext(zoom, &feature), finalDefaultValue);
}
std::vector<optional<T>> possibleOutputs() const {
return expression::fromExpressionValues<T>(expression->possibleOutputs());
}
- const expression::Expression& getExpression() const { return *expression; }
-
- bool useIntegerZoom = false;
-
friend bool operator==(const PropertyExpression& lhs,
const PropertyExpression& rhs) {
return *lhs.expression == *rhs.expression;
}
private:
- std::shared_ptr<const expression::Expression> expression;
optional<T> defaultValue;
- variant<std::nullptr_t, const expression::Interpolate*, const expression::Step*> zoomCurve;
};
} // namespace style
diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js
index c002718038..ae25a856a8 100755
--- a/scripts/generate-style-code.js
+++ b/scripts/generate-style-code.js
@@ -19,6 +19,29 @@ global.isLightProperty = function (property) {
return property['light-property'] === true;
};
+global.isOverridable = function (property) {
+ return ['text-color'].includes(property.name);
+};
+
+global.expressionType = function (property) {
+ switch (property.type) {
+ case 'boolean':
+ return 'BooleanType';
+ case 'number':
+ case 'enum':
+ return 'NumberType';
+ case 'string':
+ return 'StringType';
+ case 'color':
+ return `ColorType`;
+ case 'formatted':
+ return `FormattedType`;
+ case 'array':
+ return `Array<${expressionType({type: property.value})}>`;
+ default: throw new Error(`unknown type for ${property.name}`)
+ }
+};
+
global.evaluatedType = function (property) {
if (/-translate-anchor$/.test(property.name)) {
return 'TranslateAnchorType';
@@ -93,6 +116,8 @@ global.layoutPropertyType = function (property) {
global.paintPropertyType = function (property, type) {
switch (property['property-type']) {
case 'data-driven':
+ if (isOverridable(property))
+ return `DataDrivenPaintProperty<${evaluatedType(property)}, ${attributeUniformType(property, type)}, true>`;
return `DataDrivenPaintProperty<${evaluatedType(property)}, ${attributeUniformType(property, type)}>`;
case 'cross-faded-data-driven':
return `CrossFadedDataDrivenPaintProperty<${evaluatedType(property)}, ${attributeUniformType(property, type)}>`;
diff --git a/src/core-files.json b/src/core-files.json
index f745a409e5..8915ebc49d 100644
--- a/src/core-files.json
+++ b/src/core-files.json
@@ -225,6 +225,7 @@
"src/mbgl/style/light.cpp",
"src/mbgl/style/light_impl.cpp",
"src/mbgl/style/parser.cpp",
+ "src/mbgl/style/property_expression.cpp",
"src/mbgl/style/source.cpp",
"src/mbgl/style/source_impl.cpp",
"src/mbgl/style/sources/custom_geometry_source.cpp",
@@ -390,6 +391,7 @@
"mbgl/style/expression/expression.hpp": "include/mbgl/style/expression/expression.hpp",
"mbgl/style/expression/find_zoom_curve.hpp": "include/mbgl/style/expression/find_zoom_curve.hpp",
"mbgl/style/expression/format_expression.hpp": "include/mbgl/style/expression/format_expression.hpp",
+ "mbgl/style/expression/format_section_override.hpp": "include/mbgl/style/expression/format_section_override.hpp",
"mbgl/style/expression/formatted.hpp": "include/mbgl/style/expression/formatted.hpp",
"mbgl/style/expression/get_covering_stops.hpp": "include/mbgl/style/expression/get_covering_stops.hpp",
"mbgl/style/expression/interpolate.hpp": "include/mbgl/style/expression/interpolate.hpp",
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index 4041b16a65..c40a705d7f 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -1,25 +1,16 @@
-#include <mbgl/layout/layout.hpp>
#include <mbgl/layout/symbol_layout.hpp>
#include <mbgl/layout/merge_lines.hpp>
#include <mbgl/layout/clip_lines.hpp>
-#include <mbgl/renderer/buckets/symbol_bucket.hpp>
#include <mbgl/renderer/bucket_parameters.hpp>
#include <mbgl/renderer/layers/render_symbol_layer.hpp>
#include <mbgl/renderer/image_atlas.hpp>
-#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/text/get_anchors.hpp>
#include <mbgl/text/shaping.hpp>
-#include <mbgl/util/constants.hpp>
#include <mbgl/util/utf.hpp>
-#include <mbgl/util/std.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/i18n.hpp>
-#include <mbgl/math/clamp.hpp>
-#include <mbgl/math/minmax.hpp>
-#include <mbgl/math/log2.hpp>
#include <mbgl/util/platform.hpp>
-#include <mbgl/util/logging.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mapbox/polylabel.hpp>
@@ -31,11 +22,27 @@ using namespace style;
template <class Property>
static bool has(const style::SymbolLayoutProperties::PossiblyEvaluated& layout) {
return layout.get<Property>().match(
- [&] (const typename Property::Type& t) { return !t.empty(); },
- [&] (const auto&) { return true; }
+ [] (const typename Property::Type& t) { return !t.empty(); },
+ [] (const auto&) { return true; }
);
}
+namespace {
+expression::Value sectionOptionsToValue(const SectionOptions& options) {
+ std::unordered_map<std::string, expression::Value> result;
+ // TODO: Data driven properties that can be overridden on per section basis.
+ // TextOpacity
+ // TextHaloColor
+ // TextHaloWidth
+ // TextHaloBlur
+ if (options.textColor) {
+ result.emplace(expression::kFormattedSectionTextColor, *options.textColor);
+ }
+ return result;
+}
+} // namespace
+
+
SymbolLayout::SymbolLayout(const BucketParameters& parameters,
const std::vector<const RenderLayer*>& layers,
std::unique_ptr<GeometryTileLayer> sourceLayer_,
@@ -108,7 +115,6 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
auto formatted = layout.evaluate<TextField>(zoom, ft);
auto textTransform = layout.evaluate<TextTransform>(zoom, ft);
FontStack baseFontStack = layout.evaluate<TextFont>(zoom, ft);
- FontStackHash baseFontStackHash = FontStackHasher()(baseFontStack);
ft.formattedText = TaggedString();
for (std::size_t j = 0; j < formatted.sections.size(); j++) {
@@ -122,8 +128,8 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
ft.formattedText->addSection(applyArabicShaping(util::convertUTF8ToUTF16(u8string)),
section.fontScale ? *section.fontScale : 1.0,
- section.fontStack ? FontStackHasher()(*section.fontStack) : baseFontStackHash);
-
+ section.fontStack ? *section.fontStack : baseFontStack,
+ section.textColor);
}
@@ -273,6 +279,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
: layout.get<SymbolPlacement>();
const float textRepeatDistance = symbolSpacing / 2;
+ const auto evaluatedLayoutProperties = layout.evaluate(zoom, feature);
IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketLeaderID, symbolInstances.size());
auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) {
@@ -285,7 +292,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
// (1) render symbols that overlap into this tile
// (2) approximate collision detection effects from neighboring symbols
symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon,
- layout.evaluate(zoom, feature), layoutTextSize,
+ evaluatedLayoutProperties, layoutTextSize,
textBoxScale, textPadding, textPlacement, textOffset,
iconBoxScale, iconPadding, iconOffset,
glyphPositions, indexedFeature, layoutFeatureIndex, feature.index,
@@ -418,43 +425,14 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn
// Insert final placement into collision tree and add glyphs/icons to buffers
- if (hasText) {
- const Range<float> sizeData = bucket->textSizeBinder->getVertexSizeData(feature);
- bucket->text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max,
- symbolInstance.textOffset, symbolInstance.writingModes, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor));
- symbolInstance.placedTextIndex = bucket->text.placedSymbols.size() - 1;
- PlacedSymbol& horizontalSymbol = bucket->text.placedSymbols.back();
-
- bool firstHorizontal = true;
- for (const auto& symbol : symbolInstance.horizontalGlyphQuads) {
- size_t index = addSymbol(
- bucket->text, sizeData, symbol,
- symbolInstance.anchor, horizontalSymbol);
- if (firstHorizontal) {
- horizontalSymbol.vertexStartIndex = index;
- firstHorizontal = false;
- }
- }
+ if (hasText && feature.formattedText) {
+ std::size_t index = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, symbolInstance.placedTextIndex, symbolInstance.horizontalGlyphQuads);
if (symbolInstance.writingModes & WritingModeType::Vertical) {
- bucket->text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max,
- symbolInstance.textOffset, WritingModeType::Vertical, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor));
- symbolInstance.placedVerticalTextIndex = bucket->text.placedSymbols.size() - 1;
-
- PlacedSymbol& verticalSymbol = bucket->text.placedSymbols.back();
- bool firstVertical = true;
-
- for (const auto& symbol : symbolInstance.verticalGlyphQuads) {
- size_t index = addSymbol(
- bucket->text, sizeData, symbol,
- symbolInstance.anchor, verticalSymbol);
-
- if (firstVertical) {
- verticalSymbol.vertexStartIndex = index;
- firstVertical = false;
- }
- }
+ index = addSymbolGlyphQuads(*bucket, symbolInstance, feature, WritingModeType::Vertical, symbolInstance.placedVerticalTextIndex, symbolInstance.verticalGlyphQuads, index);
}
+
+ updatePaintPropertiesForSection(*bucket, feature, index);
}
if (hasIcon) {
@@ -466,12 +444,11 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn
PlacedSymbol& iconSymbol = bucket->icon.placedSymbols.back();
iconSymbol.vertexStartIndex = addSymbol(bucket->icon, sizeData, *symbolInstance.iconQuad,
symbolInstance.anchor, iconSymbol);
- }
- }
- for (auto& pair : bucket->paintProperties) {
- pair.second.iconBinders.populateVertexVectors(feature, bucket->icon.vertices.elements(), {}, {});
- pair.second.textBinders.populateVertexVectors(feature, bucket->text.vertices.elements(), {}, {});
+ for (auto& pair : bucket->paintProperties) {
+ pair.second.iconBinders.populateVertexVectors(feature, bucket->icon.vertices.elements(), {}, {});
+ }
+ }
}
}
@@ -489,12 +466,53 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn
}
-template <typename Buffer>
-size_t SymbolLayout::addSymbol(Buffer& buffer,
- const Range<float> sizeData,
- const SymbolQuad& symbol,
- const Anchor& labelAnchor,
- PlacedSymbol& placedSymbol) {
+void SymbolLayout::updatePaintPropertiesForSection(SymbolBucket& bucket,
+ const SymbolFeature& feature,
+ std::size_t sectionIndex) {
+ const auto& formattedSection = sectionOptionsToValue((*feature.formattedText).sectionAt(sectionIndex));
+ for (auto& pair : bucket.paintProperties) {
+ pair.second.textBinders.populateVertexVectors(feature, bucket.text.vertices.elements(), {}, {}, formattedSection);
+ }
+}
+
+std::size_t SymbolLayout::addSymbolGlyphQuads(SymbolBucket& bucket,
+ SymbolInstance& symbolInstance,
+ const SymbolFeature& feature,
+ WritingModeType writingMode,
+ optional<size_t>& placedIndex,
+ const SymbolQuads& glyphQuads,
+ optional<std::size_t> lastAddedSection) {
+ const Range<float> sizeData = bucket.textSizeBinder->getVertexSizeData(feature);
+ const bool hasFormatSectionOverrides = bucket.hasFormatSectionOverrides();
+
+ bucket.text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max,
+ symbolInstance.textOffset, writingMode, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor));
+ placedIndex = bucket.text.placedSymbols.size() - 1;
+ PlacedSymbol& placedSymbol = bucket.text.placedSymbols.back();
+
+ bool firstSymbol = true;
+ for (const auto& symbolQuad : glyphQuads) {
+ if (hasFormatSectionOverrides) {
+ if (lastAddedSection && *lastAddedSection != symbolQuad.sectionIndex) {
+ updatePaintPropertiesForSection(bucket, feature, *lastAddedSection);
+ }
+ lastAddedSection = symbolQuad.sectionIndex;
+ }
+ size_t index = addSymbol(bucket.text, sizeData, symbolQuad, symbolInstance.anchor, placedSymbol);
+ if (firstSymbol) {
+ placedSymbol.vertexStartIndex = index;
+ firstSymbol = false;
+ }
+ }
+
+ return lastAddedSection ? *lastAddedSection : 0u;
+}
+
+size_t SymbolLayout::addSymbol(SymbolBucket::Buffer& buffer,
+ const Range<float> sizeData,
+ const SymbolQuad& symbol,
+ const Anchor& labelAnchor,
+ PlacedSymbol& placedSymbol) {
constexpr const uint16_t vertexLength = 4;
const auto &tl = symbol.tl;
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index ab6dc049a2..53c66d31fe 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -6,18 +6,15 @@
#include <mbgl/layout/symbol_feature.hpp>
#include <mbgl/layout/symbol_instance.hpp>
#include <mbgl/text/bidi.hpp>
-#include <mbgl/style/layers/symbol_layer_impl.hpp>
-#include <mbgl/programs/symbol_program.hpp>
+#include <mbgl/renderer/buckets/symbol_bucket.hpp>
#include <memory>
#include <map>
-#include <unordered_set>
#include <vector>
namespace mbgl {
class BucketParameters;
-class SymbolBucket;
class Anchor;
class RenderLayer;
class PlacedSymbol;
@@ -26,7 +23,7 @@ namespace style {
class Filter;
} // namespace style
-class SymbolLayout : public Layout {
+class SymbolLayout final : public Layout {
public:
SymbolLayout(const BucketParameters&,
const std::vector<const RenderLayer*>&,
@@ -62,12 +59,25 @@ private:
void addToDebugBuffers(SymbolBucket&);
// Adds placed items to the buffer.
- template <typename Buffer>
- size_t addSymbol(Buffer&,
- const Range<float> sizeData,
- const SymbolQuad&,
- const Anchor& labelAnchor,
- PlacedSymbol& placedSymbol);
+ size_t addSymbol(SymbolBucket::Buffer&,
+ const Range<float> sizeData,
+ const SymbolQuad&,
+ const Anchor& labelAnchor,
+ PlacedSymbol& placedSymbol);
+
+ // Adds symbol quads to bucket and returns formatted section index of last
+ // added quad.
+ std::size_t addSymbolGlyphQuads(SymbolBucket&,
+ SymbolInstance&,
+ const SymbolFeature&,
+ WritingModeType,
+ optional<size_t>& placedIndex,
+ const SymbolQuads&,
+ optional<std::size_t> lastAddedSection = nullopt);
+
+ void updatePaintPropertiesForSection(SymbolBucket&,
+ const SymbolFeature&,
+ std::size_t sectionIndex);
// Stores the layer so that we can hold on to GeometryTileFeature instances in SymbolFeature,
// which may reference data from this object.
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp
index 3a3688a60b..9220235f1d 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.cpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp
@@ -28,13 +28,17 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo
iconSizeBinder(SymbolSizeBinder::create(zoom, iconSize, IconSize::defaultValue())) {
for (const auto& pair : paintProperties_) {
+ auto layerPaintProperties = pair.second;
+ if (hasFormatSectionOverrides()) {
+ setPaintPropertyOverrides(layerPaintProperties);
+ }
paintProperties.emplace(
std::piecewise_construct,
std::forward_as_tuple(pair.first),
std::forward_as_tuple(PaintProperties {
- pair.second,
- { RenderSymbolLayer::iconPaintProperties(pair.second), zoom },
- { RenderSymbolLayer::textPaintProperties(pair.second), zoom }
+ layerPaintProperties,
+ { RenderSymbolLayer::iconPaintProperties(layerPaintProperties), zoom },
+ { RenderSymbolLayer::textPaintProperties(layerPaintProperties), zoom }
}));
}
}
@@ -226,4 +230,23 @@ void SymbolBucket::sortFeatures(const float angle) {
}
}
+void SymbolBucket::updatePaintProperties(const std::string& layerID,
+ style::SymbolPaintProperties::PossiblyEvaluated updated) {
+ if (hasFormatSectionOverrides()) {
+ SymbolLayerPaintPropertyOverrides::updateOverrides(paintProperties.at(layerID).evaluated, updated);
+ }
+ paintProperties.at(layerID).evaluated = updated;
+}
+
+void SymbolBucket::setPaintPropertyOverrides(style::SymbolPaintProperties::PossiblyEvaluated& paint) {
+ SymbolLayerPaintPropertyOverrides::setOverrides(layout, paint);
+}
+
+bool SymbolBucket::hasFormatSectionOverrides() {
+ if (!hasFormatSectionOverrides_) {
+ hasFormatSectionOverrides_= SymbolLayerPaintPropertyOverrides::hasOverrides(layout.get<TextField>());
+ }
+ return *hasFormatSectionOverrides_;
+}
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp
index 709e48dd2e..9764d870da 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.hpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp
@@ -58,6 +58,10 @@ public:
bool hasIconData() const;
bool hasCollisionBoxData() const;
bool hasCollisionCircleData() const;
+ bool hasFormatSectionOverrides();
+ void updatePaintProperties(const std::string& layerID,
+ style::SymbolPaintProperties::PossiblyEvaluated);
+ void setPaintPropertyOverrides(style::SymbolPaintProperties::PossiblyEvaluated&);
void updateOpacity();
void sortFeatures(const float angle);
@@ -87,7 +91,7 @@ public:
std::unique_ptr<SymbolSizeBinder> textSizeBinder;
- struct TextBuffer {
+ struct Buffer {
gfx::VertexVector<SymbolLayoutVertex> vertices;
gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>> dynamicVertices;
gfx::VertexVector<gfx::Vertex<SymbolOpacityAttributes>> opacityVertices;
@@ -103,19 +107,8 @@ public:
std::unique_ptr<SymbolSizeBinder> iconSizeBinder;
- struct IconBuffer {
- gfx::VertexVector<SymbolLayoutVertex> vertices;
- gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>> dynamicVertices;
- gfx::VertexVector<gfx::Vertex<SymbolOpacityAttributes>> opacityVertices;
- gfx::IndexVector<gfx::Triangles> triangles;
- SegmentVector<SymbolIconAttributes> segments;
- std::vector<PlacedSymbol> placedSymbols;
+ struct IconBuffer : public Buffer {
PremultipliedImage atlasImage;
-
- optional<gfx::VertexBuffer<SymbolLayoutVertex>> vertexBuffer;
- optional<gfx::VertexBuffer<gfx::Vertex<SymbolDynamicLayoutAttributes>>> dynamicVertexBuffer;
- optional<gfx::VertexBuffer<gfx::Vertex<SymbolOpacityAttributes>>> opacityVertexBuffer;
- optional<gfx::IndexBuffer> indexBuffer;
} icon;
struct CollisionBuffer {
@@ -139,6 +132,7 @@ public:
uint32_t bucketInstanceId = 0;
bool justReloaded = false;
+ optional<bool> hasFormatSectionOverrides_;
std::shared_ptr<std::vector<size_t>> featureSortOrder;
};
diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp
index e523a869b2..43e3068ff0 100644
--- a/src/mbgl/renderer/layers/render_symbol_layer.cpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp
@@ -411,7 +411,7 @@ void RenderSymbolLayer::sortRenderTiles(const TransformState& state) {
void RenderSymbolLayer::updateBucketPaintProperties(Bucket* bucket) const {
assert(bucket->supportsLayer(*baseImpl));
- static_cast<SymbolBucket*>(bucket)->paintProperties.at(getID()).evaluated = evaluated;
+ static_cast<SymbolBucket*>(bucket)->updatePaintProperties(getID(), evaluated);
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp
index 34600508af..dc5ab6ae22 100644
--- a/src/mbgl/renderer/paint_property_binder.hpp
+++ b/src/mbgl/renderer/paint_property_binder.hpp
@@ -95,7 +95,10 @@ public:
virtual ~PaintPropertyBinder() = default;
- virtual void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional<PatternDependency>&) = 0;
+ virtual void populateVertexVector(const GeometryTileFeature& feature,
+ std::size_t length, const ImagePositions&,
+ const optional<PatternDependency>&,
+ const style::expression::Value&) = 0;
virtual void upload(gfx::Context& context) = 0;
virtual void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, CrossfadeParameters&) = 0;
virtual std::tuple<ExpandToType<As, optional<gl::AttributeBinding>>...> attributeBinding(const PossiblyEvaluatedType& currentValue) const = 0;
@@ -114,7 +117,7 @@ public:
: constant(std::move(constant_)) {
}
- void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional<PatternDependency>&) override {}
+ void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional<PatternDependency>&, const style::expression::Value&) override {}
void upload(gfx::Context&) override {}
void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, CrossfadeParameters&) override {};
@@ -135,13 +138,13 @@ private:
};
template <class T, class... As>
-class ConstantCrossFadedPaintPropertyBinder : public PaintPropertyBinder<T, std::array<uint16_t, 4>,PossiblyEvaluatedPropertyValue<Faded<T>>, As...> {
+class ConstantCrossFadedPaintPropertyBinder final : public PaintPropertyBinder<T, std::array<uint16_t, 4>,PossiblyEvaluatedPropertyValue<Faded<T>>, As...> {
public:
ConstantCrossFadedPaintPropertyBinder(Faded<T> constant_)
: constant(std::move(constant_)), constantPatternPositions({}) {
}
- void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional<PatternDependency>&) override {}
+ void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional<PatternDependency>&, const style::expression::Value&) override {}
void upload(gfx::Context&) override {}
void setPatternParameters(const optional<ImagePosition>& posA, const optional<ImagePosition>& posB, CrossfadeParameters&) override {
@@ -171,7 +174,7 @@ private:
};
template <class T, class A>
-class SourceFunctionPaintPropertyBinder : public PaintPropertyBinder<T, T, PossiblyEvaluatedPropertyValue<T>, A> {
+class SourceFunctionPaintPropertyBinder final : public PaintPropertyBinder<T, T, PossiblyEvaluatedPropertyValue<T>, A> {
public:
using BaseAttributeType = A;
using BaseVertex = gfx::Vertex<BaseAttributeType>;
@@ -183,8 +186,9 @@ public:
defaultValue(std::move(defaultValue_)) {
}
void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, CrossfadeParameters&) override {};
- void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional<PatternDependency>&) override {
- auto evaluated = expression.evaluate(feature, defaultValue);
+ void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional<PatternDependency>&, const style::expression::Value& formattedSection) override {
+ using style::expression::EvaluationContext;
+ auto evaluated = expression.evaluate(EvaluationContext(&feature).withFormattedSection(&formattedSection), defaultValue);
this->statistics.add(evaluated);
auto value = attributeValue(evaluated);
for (std::size_t i = vertexVector.elements(); i < length; ++i) {
@@ -227,7 +231,7 @@ private:
};
template <class T, class A>
-class CompositeFunctionPaintPropertyBinder : public PaintPropertyBinder<T, T, PossiblyEvaluatedPropertyValue<T>, A> {
+class CompositeFunctionPaintPropertyBinder final : public PaintPropertyBinder<T, T, PossiblyEvaluatedPropertyValue<T>, A> {
public:
using AttributeType = ZoomInterpolatedAttributeType<A>;
@@ -240,8 +244,12 @@ public:
zoomRange({zoom, zoom + 1}) {
}
void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, CrossfadeParameters&) override {};
- void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional<PatternDependency>&) override {
- Range<T> range = expression.evaluate(zoomRange, feature, defaultValue);
+ void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional<PatternDependency>&, const style::expression::Value& formattedSection) override {
+ using style::expression::EvaluationContext;
+ Range<T> range = {
+ expression.evaluate(EvaluationContext(zoomRange.min, &feature).withFormattedSection(&formattedSection), defaultValue),
+ expression.evaluate(EvaluationContext(zoomRange.max, &feature).withFormattedSection(&formattedSection), defaultValue),
+ };
this->statistics.add(range.min);
this->statistics.add(range.max);
AttributeValue value = zoomInterpolatedAttributeValue(
@@ -292,7 +300,7 @@ private:
};
template <class T, class A1, class A2>
-class CompositeCrossFadedPaintPropertyBinder : public PaintPropertyBinder<T, std::array<uint16_t, 4>, PossiblyEvaluatedPropertyValue<Faded<T>>, A1, A2> {
+class CompositeCrossFadedPaintPropertyBinder final : public PaintPropertyBinder<T, std::array<uint16_t, 4>, PossiblyEvaluatedPropertyValue<Faded<T>>, A1, A2> {
public:
using AttributeType = ZoomInterpolatedAttributeType<A1>;
using AttributeType2 = ZoomInterpolatedAttributeType<A2>;
@@ -313,7 +321,7 @@ public:
crossfade = crossfade_;
};
- void populateVertexVector(const GeometryTileFeature&, std::size_t length, const ImagePositions& patternPositions, const optional<PatternDependency>& patternDependencies) override {
+ void populateVertexVector(const GeometryTileFeature&, std::size_t length, const ImagePositions& patternPositions, const optional<PatternDependency>& patternDependencies, const style::expression::Value&) override {
if (patternDependencies->mid.empty()) {
// Unlike other propperties with expressions that evaluate to null, the default value for `*-pattern` properties is an empty
@@ -474,9 +482,9 @@ public:
PaintPropertyBinders(PaintPropertyBinders&&) = default;
PaintPropertyBinders(const PaintPropertyBinders&) = delete;
- void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length, const ImagePositions& patternPositions, const optional<PatternDependency>& patternDependencies) {
+ void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length, const ImagePositions& patternPositions, const optional<PatternDependency>& patternDependencies, const style::expression::Value& formattedSection = {}) {
util::ignore({
- (binders.template get<Ps>()->populateVertexVector(feature, length, patternPositions, patternDependencies), 0)...
+ (binders.template get<Ps>()->populateVertexVector(feature, length, patternPositions, patternDependencies, formattedSection), 0)...
});
}
diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp
index 5877d0eb7c..79ad2fc7d8 100644
--- a/src/mbgl/style/conversion/function.cpp
+++ b/src/mbgl/style/conversion/function.cpp
@@ -41,7 +41,7 @@ bool hasTokens(const std::string& source) {
std::unique_ptr<Expression> convertTokenStringToFormatExpression(const std::string& source) {
auto textExpression = convertTokenStringToExpression(source);
std::vector<FormatExpressionSection> sections;
- sections.emplace_back(std::move(textExpression), nullopt, nullopt);
+ sections.emplace_back(std::move(textExpression), nullopt, nullopt, nullopt);
return std::make_unique<FormatExpression>(sections);
}
diff --git a/src/mbgl/style/expression/dsl.cpp b/src/mbgl/style/expression/dsl.cpp
index f5ff83a9e7..e7d90ba07b 100644
--- a/src/mbgl/style/expression/dsl.cpp
+++ b/src/mbgl/style/expression/dsl.cpp
@@ -189,13 +189,13 @@ std::unique_ptr<Expression> concat(std::vector<std::unique_ptr<Expression>> inpu
std::unique_ptr<Expression> format(const char* value) {
return std::make_unique<Literal>(Formatted(value));
}
-
+
std::unique_ptr<Expression> format(std::unique_ptr<Expression> input) {
std::vector<FormatExpressionSection> sections;
- sections.emplace_back(std::move(input), nullopt, nullopt);
+ sections.emplace_back(std::move(input), nullopt, nullopt, nullopt);
return std::make_unique<FormatExpression>(sections);
}
-
+
} // namespace dsl
} // namespace expression
} // namespace style
diff --git a/src/mbgl/style/expression/format_expression.cpp b/src/mbgl/style/expression/format_expression.cpp
index 144df4b160..b5e4ba62c4 100644
--- a/src/mbgl/style/expression/format_expression.cpp
+++ b/src/mbgl/style/expression/format_expression.cpp
@@ -1,8 +1,6 @@
#include <mbgl/style/conversion_impl.hpp>
#include <mbgl/style/expression/format_expression.hpp>
-#include <mbgl/style/expression/literal.hpp>
-#include <mbgl/util/font_stack.hpp>
-#include <mbgl/util/string.hpp>
+#include <mbgl/style/expression/formatted.hpp>
namespace mbgl {
namespace style {
@@ -10,15 +8,21 @@ namespace expression {
FormatExpressionSection::FormatExpressionSection(std::unique_ptr<Expression> text_,
optional<std::unique_ptr<Expression>> fontScale_,
- optional<std::unique_ptr<Expression>> textFont_)
+ optional<std::unique_ptr<Expression>> textFont_,
+ optional<std::unique_ptr<Expression>> textColor_)
: text(std::move(text_))
{
if (fontScale_) {
fontScale = std::shared_ptr<Expression>(std::move(*fontScale_));
}
+
if (textFont_) {
textFont = std::shared_ptr<Expression>(std::move(*textFont_));
}
+
+ if (textColor_) {
+ textColor = std::shared_ptr<Expression>(std::move(*textColor_));
+ }
}
FormatExpression::FormatExpression(std::vector<FormatExpressionSection> sections_)
@@ -53,7 +57,7 @@ ParseResult FormatExpression::parse(const Convertible& value, ParsingContext& ct
return ParseResult();
}
- const optional<Convertible> fontScaleOption = objectMember(options, "font-scale");
+ const optional<Convertible> fontScaleOption = objectMember(options, kFormattedSectionFontScale);
ParseResult fontScale;
if (fontScaleOption) {
fontScale = ctx.parse(*fontScaleOption, 1, {type::Number});
@@ -62,7 +66,7 @@ ParseResult FormatExpression::parse(const Convertible& value, ParsingContext& ct
}
}
- const optional<Convertible> textFontOption = objectMember(options, "text-font");
+ const optional<Convertible> textFontOption = objectMember(options, kFormattedSectionTextFont);
ParseResult textFont;
if (textFontOption) {
textFont = ctx.parse(*textFontOption, 1, {type::Array(type::String)});
@@ -70,7 +74,20 @@ ParseResult FormatExpression::parse(const Convertible& value, ParsingContext& ct
return ParseResult();
}
}
- sections.emplace_back(std::move(*text), std::move(fontScale), std::move(textFont));
+
+ const optional<Convertible> textColorOption = objectMember(options, kFormattedSectionTextColor);
+ ParseResult textColor;
+ if (textColorOption) {
+ textColor = ctx.parse(*textColorOption, 1, {type::Color});
+ if (!textColor) {
+ return ParseResult();
+ }
+ }
+
+ sections.emplace_back(std::move(*text),
+ std::move(fontScale),
+ std::move(textFont),
+ std::move(textColor));
}
return ParseResult(std::make_unique<FormatExpression>(std::move(sections)));
@@ -85,6 +102,9 @@ void FormatExpression::eachChild(const std::function<void(const Expression&)>& f
if (section.textFont) {
fn(**section.textFont);
}
+ if (section.textColor) {
+ fn(**section.textColor);
+ }
}
}
@@ -108,6 +128,10 @@ bool FormatExpression::operator==(const Expression& e) const {
(!lhsSection.textFont && rhsSection.textFont)) {
return false;
}
+ if ((lhsSection.textColor && (!rhsSection.textColor || **lhsSection.textColor != **rhsSection.textColor)) ||
+ (!lhsSection.textColor && rhsSection.textColor)) {
+ return false;
+ }
}
return true;
}
@@ -115,15 +139,18 @@ bool FormatExpression::operator==(const Expression& e) const {
}
mbgl::Value FormatExpression::serialize() const {
- std::vector<mbgl::Value> serialized{{ std::string("format") }};
+ std::vector<mbgl::Value> serialized{{ getOperator() }};
for (const auto& section : sections) {
serialized.push_back(section.text->serialize());
std::unordered_map<std::string, mbgl::Value> options;
if (section.fontScale) {
- options.emplace("font-scale", (*section.fontScale)->serialize());
+ options.emplace(kFormattedSectionFontScale, (*section.fontScale)->serialize());
}
if (section.textFont) {
- options.emplace("text-font", (*section.textFont)->serialize());
+ options.emplace(kFormattedSectionTextFont, (*section.textFont)->serialize());
+ }
+ if (section.textColor) {
+ options.emplace(kFormattedSectionTextColor, (*section.textColor)->serialize());
}
serialized.push_back(options);
}
@@ -164,7 +191,20 @@ EvaluationResult FormatExpression::evaluate(const EvaluationContext& params) con
}
evaluatedTextFont = *textFontValue;
}
- evaluatedSections.emplace_back(*evaluatedText, evaluatedFontScale, evaluatedTextFont);
+
+ optional<Color> evaluatedTextColor;
+ if (section.textColor) {
+ auto textColorResult = (*section.textColor)->evaluate(params);
+ if (!textColorResult) {
+ return textColorResult.error();
+ }
+
+ evaluatedTextColor = fromExpressionValue<Color>(*textColorResult);
+ if (!evaluatedTextColor) {
+ return EvaluationError { "Format text-color option must evaluate to Color" };
+ }
+ }
+ evaluatedSections.emplace_back(*evaluatedText, evaluatedFontScale, evaluatedTextFont, evaluatedTextColor);
}
return Formatted(evaluatedSections);
}
diff --git a/src/mbgl/style/expression/formatted.cpp b/src/mbgl/style/expression/formatted.cpp
index 8232d0c698..3fa39b2cdc 100644
--- a/src/mbgl/style/expression/formatted.cpp
+++ b/src/mbgl/style/expression/formatted.cpp
@@ -1,18 +1,15 @@
#include <mbgl/style/expression/formatted.hpp>
#include <mbgl/style/conversion_impl.hpp>
-#include <mbgl/style/expression/is_constant.hpp>
-#include <mbgl/style/expression/is_expression.hpp>
-#include <mbgl/style/expression/literal.hpp>
-#include <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/expression/type.hpp>
-#include <mbgl/style/expression/compound_expression.hpp>
-#include <mbgl/style/expression/boolean_operator.hpp>
+#include <mbgl/style/conversion/constant.hpp>
namespace mbgl {
namespace style {
-
namespace expression {
+const char* const kFormattedSectionFontScale = "font-scale";
+const char* const kFormattedSectionTextFont = "text-font";
+const char* const kFormattedSectionTextColor = "text-color";
+
bool Formatted::operator==(const Formatted& other) const {
if (other.sections.size() != sections.size()) {
return false;
@@ -22,14 +19,14 @@ bool Formatted::operator==(const Formatted& other) const {
const auto& otherSection = other.sections.at(i);
if (thisSection.text != otherSection.text ||
thisSection.fontScale != otherSection.fontScale ||
- thisSection.fontStack != otherSection.fontStack) {
+ thisSection.fontStack != otherSection.fontStack ||
+ thisSection.textColor != otherSection.textColor) {
return false;
}
}
return true;
}
-
-
+
std::string Formatted::toString() const {
std::string result;
for (const auto& section : sections) {
@@ -37,7 +34,7 @@ std::string Formatted::toString() const {
}
return result;
}
-
+
} // namespace expression
namespace conversion {
@@ -65,6 +62,7 @@ optional<Formatted> Converter<Formatted>::operator()(const Convertible& value, E
optional<double> fontScale;
optional<FontStack> textFont;
+ optional<Color> textColor;
if (sectionLength > 1) {
Convertible sectionParams = arrayMember(section, 1);
if (!isObject(sectionParams)) {
@@ -72,12 +70,12 @@ optional<Formatted> Converter<Formatted>::operator()(const Convertible& value, E
return nullopt;
}
- optional<Convertible> fontScaleMember = objectMember(sectionParams, "font-scale");
+ optional<Convertible> fontScaleMember = objectMember(sectionParams, kFormattedSectionFontScale);
if (fontScaleMember) {
fontScale = toDouble(*fontScaleMember);
}
- optional<Convertible> textFontMember = objectMember(sectionParams, "text-font");
+ optional<Convertible> textFontMember = objectMember(sectionParams, kFormattedSectionTextFont);
if (textFontMember) {
if (isArray(*textFontMember)) {
std::vector<std::string> fontsVector;
@@ -96,9 +94,17 @@ optional<Formatted> Converter<Formatted>::operator()(const Convertible& value, E
return nullopt;
}
}
+
+ optional<Convertible> textColorMember = objectMember(sectionParams, kFormattedSectionTextColor);
+ if (textColorMember) {
+ textColor = convert<Color>(*textColorMember, error);
+ if (!textColor) {
+ return nullopt;
+ }
+ }
}
- sections.push_back(FormattedSection(*sectionText, fontScale, textFont));
+ sections.push_back(FormattedSection(*sectionText, fontScale, textFont, textColor));
}
return Formatted(sections);
} else if (optional<std::string> result = toString(value)) {
diff --git a/src/mbgl/style/expression/is_constant.cpp b/src/mbgl/style/expression/is_constant.cpp
index 3b20f49a86..9704168a41 100644
--- a/src/mbgl/style/expression/is_constant.cpp
+++ b/src/mbgl/style/expression/is_constant.cpp
@@ -17,18 +17,22 @@ bool isFeatureConstant(const Expression& expression) {
return false;
} else if (name == "has" && parameterCount && *parameterCount == 1) {
return false;
- } else if (0 == name.rfind(filter, 0)) {
- // Legacy filters begin with "filter-" and are never constant.
- return false;
} else if (
name == "properties" ||
name == "geometry-type" ||
name == "id"
) {
return false;
+ } else if (0u == name.rfind(filter, 0u)) {
+ // Legacy filters begin with "filter-" and are never constant.
+ return false;
}
}
+ if (expression.getKind() == Kind::FormatSectionOverride) {
+ return false;
+ }
+
if (expression.getKind() == Kind::CollatorExpression) {
// Although the results of a Collator expression with fixed arguments
// generally shouldn't change between executions, we can't serialize them
diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs
index 792f858862..89dffdcd42 100644
--- a/src/mbgl/style/layers/layer_properties.hpp.ejs
+++ b/src/mbgl/style/layers/layer_properties.hpp.ejs
@@ -31,6 +31,11 @@ struct <%- camelize(property.name) %> : ColorRampProperty {
<% } else { -%>
struct <%- camelize(property.name) %> : <%- paintPropertyType(property, type) %> {
static <%- evaluatedType(property) %> defaultValue() { return <%- defaultValue(property) %>; }
+<% if (isOverridable(property)) { -%>
+ static constexpr const char *name() { return "<%- property.name %>"; }
+ static constexpr auto expressionType() { return expression::type::<%- expressionType(property) %>{}; };
+ template<typename T> static bool hasOverride(const T& t) { return !!t.<%- camelizeWithLeadingLowercase(property.name) %>; };
+<% } -%>
};
<% } -%>
diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp
index 3dd1da1136..e35e7b0b9f 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.cpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.cpp
@@ -1,17 +1,24 @@
#include <mbgl/style/layers/symbol_layer_impl.hpp>
-
#include <mbgl/util/logging.hpp>
namespace mbgl {
namespace style {
+bool SymbolLayer::Impl::hasFormatSectionOverrides() const {
+ if (!hasFormatSectionOverrides_) {
+ hasFormatSectionOverrides_ = SymbolLayerPaintPropertyOverrides::hasOverrides(layout.get<TextField>());
+ }
+ return *hasFormatSectionOverrides_;
+}
+
bool SymbolLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const {
assert(other.getTypeInfo() == getTypeInfo());
const auto& impl = static_cast<const style::SymbolLayer::Impl&>(other);
return filter != impl.filter ||
visibility != impl.visibility ||
layout != impl.layout ||
- paint.hasDataDrivenPropertyDifference(impl.paint);
+ paint.hasDataDrivenPropertyDifference(impl.paint) ||
+ (hasFormatSectionOverrides() && SymbolLayerPaintPropertyOverrides::hasPaintPropertyDifference(paint, impl.paint));
}
void SymbolLayer::Impl::populateFontStack(std::set<FontStack>& fontStack) const {
@@ -20,10 +27,10 @@ void SymbolLayer::Impl::populateFontStack(std::set<FontStack>& fontStack) const
}
layout.get<TextFont>().match(
- [&] (Undefined) {
+ [&fontStack] (Undefined) {
fontStack.insert({"Open Sans Regular", "Arial Unicode MS Regular"});
},
- [&] (const FontStack& constant) {
+ [&fontStack] (const FontStack& constant) {
fontStack.insert(constant);
},
[&] (const auto& function) {
diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp
index a5b0332f6c..f937fccaa8 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.hpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.hpp
@@ -3,10 +3,104 @@
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
+#include <mbgl/style/expression/format_expression.hpp>
+#include <mbgl/style/expression/formatted.hpp>
+#include <mbgl/style/expression/format_section_override.hpp>
namespace mbgl {
namespace style {
+template<typename PaintProperty>
+struct FormatSectionOverrides;
+
+template<typename... PaintProperty>
+struct FormatSectionOverrides<TypeList<PaintProperty...>> {
+ template<typename Property, typename T, typename U>
+ static void setOverride(const T& overrides, U& overridable) {
+ if (hasOverride<Property>(overrides.template get<TextField>())) {
+ auto override =
+ std::make_unique<expression::FormatSectionOverride<typename Property::Type>>(Property::expressionType(),
+ std::move(overridable.template get<Property>()),
+ Property::name());
+ PropertyExpression<typename Property::Type> expr(std::move(override));
+ overridable.template get<Property>() = PossiblyEvaluatedPropertyValue<typename Property::Type>(std::move(expr));
+ }
+ }
+
+ template<typename T, typename U>
+ static void setOverrides(const T& overrides, U& overridable) {
+ util::ignore({(setOverride<PaintProperty>(overrides, overridable), 0)...});
+ }
+
+ template<typename Property, typename T, typename U>
+ static void updateOverride(T& evaluated, U& updated) {
+ auto property = evaluated.template get<Property>();
+ if (!property.isConstant()) {
+ const bool hasFormatSectionOverride = property.match(
+ [] (const style::PropertyExpression<typename Property::Type>& e) {
+ return e.getExpression().getKind() == expression::Kind::FormatSectionOverride;
+ },
+ [] (const auto&) {
+ return false;
+ });
+ if (hasFormatSectionOverride) {
+ updated.template get<Property>() = std::move(property);
+ }
+ }
+ }
+
+ template<typename T, typename U>
+ static void updateOverrides(T& evaluated, U& updated) {
+ util::ignore({(updateOverride<PaintProperty>(evaluated, updated), 0)...});
+ }
+
+ template<typename Property, typename FormattedProperty>
+ static bool hasOverride(const FormattedProperty& formatted) {
+ return formatted.match(
+ [] (const TextField::Type& t) {
+ for (const auto& section : t.sections) {
+ if (Property::hasOverride(section)) {
+ return true;
+ }
+ }
+ return false;
+ },
+ [] (const PropertyExpression<TextField::Type>& t) {
+ if (t.getExpression().getKind() == expression::Kind::FormatExpression) {
+ const auto* e = static_cast<const expression::FormatExpression*>(&t.getExpression());
+ for (const auto& section : e->getSections()) {
+ if (Property::hasOverride(section)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ },
+ [] (const auto&) {
+ return false;
+ }
+ );
+ }
+
+ template <typename FormattedProperty>
+ static bool hasOverrides(const FormattedProperty& formatted) {
+ bool result = false;
+ util::ignore({ (result |= hasOverride<PaintProperty>(formatted))... });
+ return result;
+ }
+
+ template <typename PaintProperties>
+ static bool hasPaintPropertyDifference(const PaintProperties& lhs, const PaintProperties& rhs) {
+ bool result = false;
+ util::ignore({ (result |= lhs.template get<PaintProperty>().value.isConstant() &&
+ rhs.template get<PaintProperty>().value.isConstant() &&
+ (lhs.template get<PaintProperty>().value.asConstant() != rhs.template get<PaintProperty>().value.asConstant()))... });
+ return result;
+ }
+};
+
+using SymbolLayerPaintPropertyOverrides = FormatSectionOverrides<SymbolPaintProperties::OverridableProperties>;
+
class SymbolLayer::Impl : public Layer::Impl {
public:
using Layer::Impl::Impl;
@@ -19,6 +113,10 @@ public:
SymbolPaintProperties::Transitionable paint;
DECLARE_LAYER_TYPE_INFO;
+
+private:
+ bool hasFormatSectionOverrides() const;
+ mutable optional<bool> hasFormatSectionOverrides_;
};
} // namespace style
diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp
index d5bdce1f5d..c352ab8e77 100644
--- a/src/mbgl/style/layers/symbol_layer_properties.hpp
+++ b/src/mbgl/style/layers/symbol_layer_properties.hpp
@@ -229,8 +229,11 @@ struct TextOpacity : DataDrivenPaintProperty<float, attributes::a_opacity, unifo
static float defaultValue() { return 1; }
};
-struct TextColor : DataDrivenPaintProperty<Color, attributes::a_fill_color, uniforms::u_fill_color> {
+struct TextColor : DataDrivenPaintProperty<Color, attributes::a_fill_color, uniforms::u_fill_color, true> {
static Color defaultValue() { return Color::black(); }
+ static constexpr const char *name() { return "text-color"; }
+ static constexpr auto expressionType() { return expression::type::ColorType{}; };
+ template<typename T> static bool hasOverride(const T& t) { return !!t.textColor; };
};
struct TextHaloColor : DataDrivenPaintProperty<Color, attributes::a_halo_color, uniforms::u_halo_color> {
diff --git a/src/mbgl/style/layout_property.hpp b/src/mbgl/style/layout_property.hpp
index 0fcad30cc4..d98a1cbf31 100644
--- a/src/mbgl/style/layout_property.hpp
+++ b/src/mbgl/style/layout_property.hpp
@@ -16,6 +16,7 @@ public:
using PossiblyEvaluatedType = T;
using Type = T;
static constexpr bool IsDataDriven = false;
+ static constexpr bool IsOverridable = false;
};
template <class T>
@@ -27,6 +28,7 @@ public:
using PossiblyEvaluatedType = PossiblyEvaluatedPropertyValue<T>;
using Type = T;
static constexpr bool IsDataDriven = true;
+ static constexpr bool IsOverridable = false;
};
} // namespace style
diff --git a/src/mbgl/style/light_impl.hpp b/src/mbgl/style/light_impl.hpp
index f094c9d462..33db64ae3f 100644
--- a/src/mbgl/style/light_impl.hpp
+++ b/src/mbgl/style/light_impl.hpp
@@ -21,6 +21,7 @@ public:
using PossiblyEvaluatedType = T;
using Type = T;
static constexpr bool IsDataDriven = false;
+ static constexpr bool IsOverridable = false;
};
struct LightAnchor : LightProperty<LightAnchorType> {
diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp
index 343e689a32..7d398748f2 100644
--- a/src/mbgl/style/paint_property.hpp
+++ b/src/mbgl/style/paint_property.hpp
@@ -21,9 +21,10 @@ public:
using PossiblyEvaluatedType = T;
using Type = T;
static constexpr bool IsDataDriven = false;
+ static constexpr bool IsOverridable = false;
};
-template <class T, class A, class U>
+template <class T, class A, class U, bool isOverridable = false>
class DataDrivenPaintProperty {
public:
using TransitionableType = Transitionable<PropertyValue<T>>;
@@ -32,6 +33,7 @@ public:
using PossiblyEvaluatedType = PossiblyEvaluatedPropertyValue<T>;
using Type = T;
static constexpr bool IsDataDriven = true;
+ static constexpr bool IsOverridable = isOverridable;
using Attribute = A;
using AttributeList = TypeList<A>;
@@ -48,6 +50,7 @@ public:
using PossiblyEvaluatedType = PossiblyEvaluatedPropertyValue<Faded<T>>;
using Type = T;
static constexpr bool IsDataDriven = true;
+ static constexpr bool IsOverridable = false;
using Attribute = A1;
using AttributeList = TypeList<A1, A2>;
@@ -64,6 +67,7 @@ public:
using PossiblyEvaluatedType = Faded<T>;
using Type = T;
static constexpr bool IsDataDriven = false;
+ static constexpr bool IsOverridable = false;
};
/*
@@ -84,6 +88,7 @@ public:
using PossiblyEvaluatedType = Color;
using Type = Color;
static constexpr bool IsDataDriven = false;
+ static constexpr bool IsOverridable = false;
static Color defaultValue() { return {}; }
};
diff --git a/src/mbgl/style/properties.hpp b/src/mbgl/style/properties.hpp
index d836735c65..7f58ff223d 100644
--- a/src/mbgl/style/properties.hpp
+++ b/src/mbgl/style/properties.hpp
@@ -99,6 +99,9 @@ public:
template <class P>
struct IsDataDriven : std::integral_constant<bool, P::IsDataDriven> {};
+template <class P>
+struct IsOverridable : std::integral_constant<bool, P::IsOverridable> {};
+
template <class... Ps>
class Properties {
public:
@@ -122,6 +125,7 @@ public:
using EvaluatedTypes = TypeList<typename Ps::Type...>;
using DataDrivenProperties = FilteredTypeList<PropertyTypes, IsDataDriven>;
+ using OverridableProperties = FilteredTypeList<PropertyTypes, IsOverridable>;
template <class TypeList>
using Tuple = IndexedTuple<PropertyTypes, TypeList>;
diff --git a/src/mbgl/style/property_expression.cpp b/src/mbgl/style/property_expression.cpp
new file mode 100644
index 0000000000..9ebecc4b40
--- /dev/null
+++ b/src/mbgl/style/property_expression.cpp
@@ -0,0 +1,68 @@
+#include <mbgl/style/property_expression.hpp>
+
+namespace mbgl {
+namespace style {
+
+PropertyExpressionBase::PropertyExpressionBase(std::unique_ptr<expression::Expression> expression_)
+ : expression(std::move(expression_)),
+ zoomCurve(expression::findZoomCurveChecked(expression.get())) {
+ isZoomConstant_ = expression::isZoomConstant(*expression);
+ isFeatureConstant_ = expression::isFeatureConstant(*expression);
+}
+
+bool PropertyExpressionBase::isZoomConstant() const noexcept {
+ return isZoomConstant_;
+}
+
+bool PropertyExpressionBase::isFeatureConstant() const noexcept {
+ return isFeatureConstant_;
+}
+
+bool PropertyExpressionBase::canEvaluateWith(const expression::EvaluationContext& context) const noexcept {
+ if (context.zoom) {
+ if (context.feature != nullptr) {
+ return !isFeatureConstant();
+ }
+ return !isZoomConstant() && isFeatureConstant();
+ }
+
+ if (context.feature != nullptr) {
+ return isZoomConstant() && !isFeatureConstant();
+ }
+
+ return true;
+}
+
+float PropertyExpressionBase::interpolationFactor(const Range<float>& inputLevels, const float inputValue) const noexcept {
+ return zoomCurve.match(
+ [](std::nullptr_t) {
+ assert(false);
+ return 0.0f;
+ },
+ [&](const expression::Interpolate* z) {
+ return z->interpolationFactor(Range<double> { inputLevels.min, inputLevels.max }, inputValue);
+ },
+ [](const expression::Step*) {
+ return 0.0f;
+ }
+ );
+}
+
+Range<float> PropertyExpressionBase::getCoveringStops(const float lower, const float upper) const noexcept {
+ return zoomCurve.match(
+ [](std::nullptr_t) {
+ assert(false);
+ return Range<float>(0.0f, 0.0f);
+ },
+ [&](auto z) {
+ return z->getCoveringStops(lower, upper);
+ }
+ );
+}
+
+const expression::Expression& PropertyExpressionBase::getExpression() const noexcept {
+ return *expression;
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp
index 034784dc24..c97b242c10 100644
--- a/src/mbgl/text/glyph.hpp
+++ b/src/mbgl/text/glyph.hpp
@@ -19,7 +19,7 @@ namespace mbgl {
using GlyphID = char16_t;
using GlyphIDs = std::set<GlyphID>;
-
+
// Note: this only works for the BMP
GlyphRange getGlyphRange(GlyphID glyph);
@@ -59,8 +59,8 @@ using GlyphMap = std::map<FontStackHash, Glyphs>;
class PositionedGlyph {
public:
- explicit PositionedGlyph(GlyphID glyph_, float x_, float y_, bool vertical_, FontStackHash font_, float scale_)
- : glyph(glyph_), x(x_), y(y_), vertical(vertical_), font(font_), scale(scale_)
+ explicit PositionedGlyph(GlyphID glyph_, float x_, float y_, bool vertical_, FontStackHash font_, float scale_, std::size_t sectionIndex_ = 0)
+ : glyph(glyph_), x(x_), y(y_), vertical(vertical_), font(font_), scale(scale_), sectionIndex(sectionIndex_)
{}
GlyphID glyph = 0;
@@ -70,6 +70,8 @@ public:
FontStackHash font = 0;
float scale = 0.0;
+ // Maps positioned glyph to TaggedString section
+ std::size_t sectionIndex;
};
enum class WritingModeType : uint8_t;
diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp
index 9d582f14d6..ec0045caad 100644
--- a/src/mbgl/text/quads.cpp
+++ b/src/mbgl/text/quads.cpp
@@ -172,7 +172,7 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText,
br = util::matrixMultiply(matrix, br);
}
- quads.emplace_back(tl, tr, bl, br, rect, shapedText.writingMode, glyphOffset);
+ quads.emplace_back(tl, tr, bl, br, rect, shapedText.writingMode, glyphOffset, positionedGlyph.sectionIndex);
}
return quads;
diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp
index 44a35a5014..f41a4fec66 100644
--- a/src/mbgl/text/quads.hpp
+++ b/src/mbgl/text/quads.hpp
@@ -20,14 +20,16 @@ public:
Point<float> br_,
Rect<uint16_t> tex_,
WritingModeType writingMode_,
- Point<float> glyphOffset_)
+ Point<float> glyphOffset_,
+ size_t sectionIndex_ = 0)
: tl(std::move(tl_)),
tr(std::move(tr_)),
bl(std::move(bl_)),
br(std::move(br_)),
tex(std::move(tex_)),
writingMode(writingMode_),
- glyphOffset(glyphOffset_) {}
+ glyphOffset(glyphOffset_),
+ sectionIndex(sectionIndex_){}
Point<float> tl;
Point<float> tr;
@@ -36,6 +38,7 @@ public:
Rect<uint16_t> tex;
WritingModeType writingMode;
Point<float> glyphOffset;
+ size_t sectionIndex;
};
using SymbolQuads = std::vector<SymbolQuad>;
diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp
index 3a6335955b..02dbf146e1 100644
--- a/src/mbgl/text/shaping.cpp
+++ b/src/mbgl/text/shaping.cpp
@@ -299,7 +299,8 @@ void shapeLines(Shaping& shaping,
std::size_t lineStartIndex = shaping.positionedGlyphs.size();
for (std::size_t i = 0; i < line.length(); i++) {
- const SectionOptions& section = line.getSection(i);
+ const std::size_t sectionIndex = line.getSectionIndex(i);
+ const SectionOptions& section = line.sectionAt(sectionIndex);
char16_t codePoint = line.getCharCodeAt(i);
auto glyphs = glyphMap.find(section.fontStackHash);
if (glyphs == glyphMap.end()) {
@@ -318,10 +319,10 @@ void shapeLines(Shaping& shaping,
const Glyph& glyph = **it->second;
if (writingMode == WritingModeType::Horizontal || !util::i18n::hasUprightVerticalOrientation(codePoint)) {
- shaping.positionedGlyphs.emplace_back(codePoint, x, y + baselineOffset, false, section.fontStackHash, section.scale);
+ shaping.positionedGlyphs.emplace_back(codePoint, x, y + baselineOffset, false, section.fontStackHash, section.scale, sectionIndex);
x += glyph.metrics.advance * section.scale + spacing;
} else {
- shaping.positionedGlyphs.emplace_back(codePoint, x, baselineOffset, true, section.fontStackHash, section.scale);
+ shaping.positionedGlyphs.emplace_back(codePoint, x, baselineOffset, true, section.fontStackHash, section.scale, sectionIndex);
x += verticalHeight * section.scale + spacing;
}
}
diff --git a/src/mbgl/text/tagged_string.cpp b/src/mbgl/text/tagged_string.cpp
index 851e011c4f..8c4e3b02e8 100644
--- a/src/mbgl/text/tagged_string.cpp
+++ b/src/mbgl/text/tagged_string.cpp
@@ -1,11 +1,12 @@
#include <mbgl/text/tagged_string.hpp>
+#include <mbgl/math/minmax.hpp>
#include <mbgl/util/i18n.hpp>
namespace mbgl {
-void TaggedString::addSection(const std::u16string& sectionText, double scale, FontStackHash fontStack) {
+void TaggedString::addSection(const std::u16string& sectionText, double scale, FontStack fontStack, optional<Color> textColor) {
styledText.first += sectionText;
- sections.emplace_back(scale, fontStack);
+ sections.emplace_back(scale, fontStack, std::move(textColor));
styledText.second.resize(styledText.first.size(), sections.size() - 1);
}
@@ -26,7 +27,7 @@ void TaggedString::trim() {
double TaggedString::getMaxScale() const {
double maxScale = 0.0;
for (std::size_t i = 0; i < styledText.first.length(); i++) {
- maxScale = std::max(maxScale, getSection(i).scale);
+ maxScale = util::max(maxScale, getSection(i).scale);
}
return maxScale;
}
diff --git a/src/mbgl/text/tagged_string.hpp b/src/mbgl/text/tagged_string.hpp
index 476c2225f0..2607e10889 100644
--- a/src/mbgl/text/tagged_string.hpp
+++ b/src/mbgl/text/tagged_string.hpp
@@ -1,17 +1,23 @@
#pragma once
-#include <mbgl/text/glyph.hpp>
#include <mbgl/text/bidi.hpp>
+#include <mbgl/style/expression/formatted.hpp>
+#include <mbgl/util/font_stack.hpp>
namespace mbgl {
struct SectionOptions {
- SectionOptions(double scale_, FontStackHash fontStackHash_)
- : scale(scale_), fontStackHash(fontStackHash_)
+ SectionOptions(double scale_, FontStack fontStack_, optional<Color> textColor_ = nullopt)
+ : scale(scale_),
+ fontStackHash(FontStackHasher()(fontStack_)),
+ fontStack(std::move(fontStack_)),
+ textColor(std::move(textColor_))
{}
double scale;
FontStackHash fontStackHash;
+ FontStack fontStack;
+ optional<Color> textColor;
};
/**
@@ -71,7 +77,11 @@ struct TaggedString {
return styledText;
}
- void addSection(const std::u16string& text, double scale, FontStackHash fontStack);
+ void addSection(const std::u16string& text,
+ double scale,
+ FontStack fontStack,
+ optional<Color> textColor_ = nullopt);
+
const SectionOptions& sectionAt(std::size_t index) const {
return sections.at(index);
}
@@ -88,7 +98,7 @@ struct TaggedString {
void trim();
void verticalizePunctuation();
-
+
private:
StyledText styledText;
std::vector<SectionOptions> sections;
diff --git a/test/style/property_expression.test.cpp b/test/style/property_expression.test.cpp
index e4ee5f115f..75c8c59490 100644
--- a/test/style/property_expression.test.cpp
+++ b/test/style/property_expression.test.cpp
@@ -5,9 +5,11 @@
#include <mbgl/renderer/property_evaluator.hpp>
#include <mbgl/renderer/property_evaluation_parameters.hpp>
#include <mbgl/style/expression/dsl.hpp>
+#include <mbgl/style/expression/format_section_override.hpp>
using namespace mbgl;
using namespace mbgl::style;
+using namespace mbgl::style::expression;
using namespace mbgl::style::expression::dsl;
using namespace std::string_literals;
@@ -24,10 +26,23 @@ static StubGeometryTileFeature oneString {
PropertyMap {{ "property", "1"s }}
};
+static StubGeometryTileFeature oneColor {
+ PropertyMap {{ "color", "red"s }}
+};
+
float evaluate(PropertyValue<float> value, float zoom) {
return value.evaluate(PropertyEvaluator<float>(PropertyEvaluationParameters(zoom), 0));
}
+template<typename T>
+auto createOverride(expression::type::Type exprType,
+ PossiblyEvaluatedPropertyValue<T> propValue,
+ std::string propName) {
+ return std::make_unique<FormatSectionOverride<T>>(std::move(exprType),
+ std::move(propValue),
+ std::move(propName));
+}
+
TEST(PropertyExpression, Constant) {
EXPECT_EQ(2.0f, evaluate(PropertyValue<float>(2.0), 0));
EXPECT_EQ(3.8f, evaluate(PropertyValue<float>(3.8), 0));
@@ -121,3 +136,38 @@ TEST(PropertyExpression, Issue8460) {
EXPECT_NEAR(600.0f, fn2.evaluate(18.0f, oneInteger, -1.0f), 0.00);
EXPECT_NEAR(600.0f, fn2.evaluate(19.0f, oneInteger, -1.0f), 0.00);
}
+
+TEST(PropertyExpression, FormatSectionOverride) {
+ using Value = expression::Value;
+ Value formattedSection =
+ std::unordered_map<std::string, Value>{ {"text-color", Value{Color::blue()}} };
+ auto ctx = expression::EvaluationContext(&oneDouble).withFormattedSection(&formattedSection);
+ PossiblyEvaluatedPropertyValue<Color> constantValueRed(Color::red());
+ PossiblyEvaluatedPropertyValue<Color> constantValueGreen(Color::green());
+ PossiblyEvaluatedPropertyValue<Color> ddsValueRed(toColor(string(get("color"))));
+
+ // Evaluation test
+ {
+ auto override1 = createOverride(expression::type::Color, constantValueGreen, "text-color");
+ PropertyExpression<Color> propExpr(std::move(override1));
+ EXPECT_EQ(Color::green(), propExpr.evaluate(15.0f, oneDouble, Color()));
+ EXPECT_EQ(Color::green(), propExpr.evaluate(oneDouble, Color()));
+ EXPECT_EQ(Color::blue(), propExpr.evaluate(ctx));
+
+ auto override2 = createOverride(expression::type::Color, ddsValueRed, "text-color");
+ PropertyExpression<Color> propExprDDS(std::move(override2));
+ EXPECT_EQ(Color::red(), propExprDDS.evaluate(oneColor, Color()));
+ EXPECT_EQ(Color::blue(), propExprDDS.evaluate(ctx));
+ }
+
+ // Equality test
+ {
+ auto override1 = createOverride(expression::type::Color, constantValueRed, "text-color");
+ auto override2 = createOverride(expression::type::Color, constantValueGreen, "text-color");
+ auto override3 = createOverride(expression::type::Color, constantValueGreen, "text-halo-color");
+ auto override4 = createOverride(expression::type::Color, ddsValueRed, "text-color");
+ EXPECT_TRUE(*override1 != *override2);
+ EXPECT_TRUE(*override2 != *override3);
+ EXPECT_TRUE(*override1 != *override4);
+ }
+}
diff --git a/test/style/style_layer.test.cpp b/test/style/style_layer.test.cpp
index 50aa643b50..e58a5fe5d0 100644
--- a/test/style/style_layer.test.cpp
+++ b/test/style/style_layer.test.cpp
@@ -1,6 +1,5 @@
-#include <mbgl/test/util.hpp>
-#include <mbgl/test/stub_layer_observer.hpp>
-#include <mbgl/test/stub_file_source.hpp>
+#include <mbgl/style/expression/dsl.hpp>
+#include <mbgl/style/expression/format_expression.hpp>
#include <mbgl/style/style_impl.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/background_layer_impl.hpp>
@@ -16,6 +15,9 @@
#include <mbgl/style/layers/raster_layer_impl.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
+#include <mbgl/test/util.hpp>
+#include <mbgl/test/stub_layer_observer.hpp>
+#include <mbgl/test/stub_file_source.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/default_thread_pool.hpp>
@@ -25,6 +27,9 @@
using namespace mbgl;
using namespace mbgl::style;
+using namespace expression;
+using namespace expression::dsl;
+using namespace std::literals::string_literals;
namespace {
@@ -50,6 +55,10 @@ const auto saturation = 1.0f;
const auto contrast = 1.0f;
const auto duration = 1.0f;
+class MockLayoutProperties : public Properties<TextField> {};
+class MockPaintProperties : public Properties<TextColor> {};
+using MockOverrides = FormatSectionOverrides<MockPaintProperties::OverridableProperties>;
+
} // namespace
TEST(Layer, BackgroundProperties) {
@@ -291,3 +300,75 @@ TEST(Layer, DuplicateLayer) {
}
}
+namespace {
+
+template<template<typename> class PropertyValueType, typename LayoutType>
+void testHasOverrides(LayoutType& layout) {
+ // Undefined
+ layout.template get<TextField>() = PropertyValueType<Formatted>();
+ EXPECT_FALSE(MockOverrides::hasOverrides(layout.template get<TextField>()));
+
+ // Constant, no overrides.
+ layout.template get<TextField>() = PropertyValueType<Formatted>(Formatted(""));
+ EXPECT_FALSE(MockOverrides::hasOverrides(layout.template get<TextField>()));
+
+ // Constant, overridden text-color.
+ auto formatted = Formatted("");
+ formatted.sections.emplace_back("section text"s, nullopt, nullopt, Color::green());
+ layout.template get<TextField>() = PropertyValueType<Formatted>(std::move(formatted));
+ EXPECT_TRUE(MockOverrides::hasOverrides(layout.template get<TextField>()));
+
+ // Expression, no overrides.
+ auto formatExpr = std::make_unique<FormatExpression>(std::vector<FormatExpressionSection>{});
+ PropertyExpression<Formatted> propExpr(std::move(formatExpr));
+ layout.template get<TextField>() = PropertyValueType<Formatted>(std::move(propExpr));
+ EXPECT_FALSE(MockOverrides::hasOverrides(layout.template get<TextField>()));
+
+ // Expression, overridden text-color.
+ FormatExpressionSection section(literal(""), nullopt, nullopt, toColor(literal("red")));
+ auto formatExprOverride = std::make_unique<FormatExpression>(std::vector<FormatExpressionSection>{section});
+ PropertyExpression<Formatted> propExprOverride(std::move(formatExprOverride));
+ layout.template get<TextField>() = PropertyValueType<Formatted>(std::move(propExprOverride));
+ EXPECT_TRUE(MockOverrides::hasOverrides(layout.template get<TextField>()));
+}
+
+} // namespace
+
+TEST(Layer, SymbolLayerOverrides) {
+
+ // Unevaluated / transitionable.
+ {
+ MockLayoutProperties::Unevaluated layout;
+ testHasOverrides<PropertyValue>(layout);
+
+ MockPaintProperties::Transitionable current;
+ MockPaintProperties::Transitionable updated;
+ current.get<TextColor>() = Transitionable<PropertyValue<Color>>{{Color::green()}, {}};
+ updated.get<TextColor>() = Transitionable<PropertyValue<Color>>{{Color::green()}, {}};
+ EXPECT_FALSE(MockOverrides::hasPaintPropertyDifference(current, updated));
+
+ current.get<TextColor>() = Transitionable<PropertyValue<Color>>{{Color::red()}, {}};
+ EXPECT_TRUE(MockOverrides::hasPaintPropertyDifference(current, updated));
+ }
+
+ // Possibly evaluated.
+ {
+ MockLayoutProperties::PossiblyEvaluated layout;
+ MockPaintProperties::PossiblyEvaluated paint;
+ testHasOverrides<PossiblyEvaluatedPropertyValue>(layout);
+
+ // Constant, overridden text-color.
+ auto formatted = Formatted("");
+ formatted.sections.emplace_back("section text"s, nullopt, nullopt, Color::green());
+ layout.get<TextField>() = PossiblyEvaluatedPropertyValue<Formatted>(std::move(formatted));
+ paint.get<TextColor>() = PossiblyEvaluatedPropertyValue<Color>{Color::red()};
+ EXPECT_TRUE(paint.get<TextColor>().isConstant());
+ MockOverrides::setOverrides(layout, paint);
+ EXPECT_FALSE(paint.get<TextColor>().isConstant());
+
+ MockPaintProperties::PossiblyEvaluated updated;
+ updated.get<TextColor>() = PossiblyEvaluatedPropertyValue<Color>{Color::red()};
+ MockOverrides::updateOverrides(paint, updated);
+ EXPECT_FALSE(updated.get<TextColor>().isConstant());
+ }
+}
diff --git a/test/text/tagged_string.test.cpp b/test/text/tagged_string.test.cpp
index 3c58ccd94b..da1141f00b 100644
--- a/test/text/tagged_string.test.cpp
+++ b/test/text/tagged_string.test.cpp
@@ -6,22 +6,22 @@
using namespace mbgl;
TEST(TaggedString, Trim) {
- TaggedString basic(u" \t\ntrim that and not this \n\t", SectionOptions(1.0f, 0));
+ TaggedString basic(u" \t\ntrim that and not this \n\t", SectionOptions(1.0f, {}));
basic.trim();
EXPECT_EQ(basic.rawText(), u"trim that and not this");
TaggedString twoSections;
- twoSections.addSection(u" \t\ntrim that", 1.5f, 1);
- twoSections.addSection(u" and not this \n\t", 0.5f, 2);
+ twoSections.addSection(u" \t\ntrim that", 1.5f, {});
+ twoSections.addSection(u" and not this \n\t", 0.5f, {});
twoSections.trim();
EXPECT_EQ(twoSections.rawText(), u"trim that and not this");
- TaggedString empty(u"\n\t\v \r \t\n", SectionOptions(1.0f, 0));
+ TaggedString empty(u"\n\t\v \r \t\n", SectionOptions(1.0f, {}));
empty.trim();
EXPECT_EQ(empty.rawText(), u"");
- TaggedString noTrim(u"no trim!", SectionOptions(1.0f, 0));
+ TaggedString noTrim(u"no trim!", SectionOptions(1.0f, {}));
noTrim.trim();
EXPECT_EQ(noTrim.rawText(), u"no trim!");
}
diff --git a/test/util/merge_lines.test.cpp b/test/util/merge_lines.test.cpp
index f76a1ea72a..1d4b0d230e 100644
--- a/test/util/merge_lines.test.cpp
+++ b/test/util/merge_lines.test.cpp
@@ -25,7 +25,7 @@ public:
SymbolFeature(std::make_unique<StubGeometryTileFeature>(std::move(id_), type_, std::move(geometry_), std::move(properties_)))
{
if (text_) {
- formattedText = TaggedString(*text_, SectionOptions(1.0, 0));
+ formattedText = TaggedString(*text_, SectionOptions(1.0, {}));
}
icon = std::move(icon_);
index = index_;