summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml6
-rw-r--r--Makefile4
-rw-r--r--README.md7
-rwxr-xr-xbin/build-style.js12
-rwxr-xr-xbin/default.style.json2244
-rw-r--r--common.gypi2
-rw-r--r--common/glfw_view.cpp10
-rw-r--r--common/settings_json.cpp6
-rw-r--r--common/settings_json.hpp2
-rw-r--r--common/settings_nsuserdefaults.hpp2
-rw-r--r--common/settings_nsuserdefaults.mm8
-rw-r--r--include/mbgl/geometry/icon_buffer.hpp10
-rw-r--r--include/mbgl/geometry/interpolate.hpp2
-rw-r--r--include/mbgl/geometry/sprite_atlas.hpp17
-rw-r--r--include/mbgl/map/map.hpp61
-rw-r--r--include/mbgl/map/raster_tile_data.hpp10
-rw-r--r--include/mbgl/map/source.hpp29
-rw-r--r--include/mbgl/map/sprite.hpp51
-rw-r--r--include/mbgl/map/tile.hpp8
-rw-r--r--include/mbgl/map/tile_data.hpp23
-rw-r--r--include/mbgl/map/tile_parser.hpp39
-rw-r--r--include/mbgl/map/transform.hpp17
-rw-r--r--include/mbgl/map/transform_state.hpp8
-rw-r--r--include/mbgl/map/vector_tile.hpp18
-rw-r--r--include/mbgl/map/vector_tile_data.hpp22
-rw-r--r--include/mbgl/platform/event.hpp1
-rw-r--r--include/mbgl/renderer/icon_bucket.hpp53
-rw-r--r--include/mbgl/renderer/painter.hpp14
-rw-r--r--include/mbgl/renderer/symbol_bucket.hpp109
-rw-r--r--include/mbgl/renderer/text_bucket.hpp61
-rw-r--r--include/mbgl/shader/icon_shader.hpp57
-rw-r--r--include/mbgl/shader/line_shader.hpp4
-rw-r--r--include/mbgl/style/property_key.hpp14
-rw-r--r--include/mbgl/style/style.hpp6
-rw-r--r--include/mbgl/style/style_bucket.hpp90
-rw-r--r--include/mbgl/style/style_parser.hpp4
-rw-r--r--include/mbgl/style/style_properties.hpp57
-rw-r--r--include/mbgl/style/style_source.hpp18
-rw-r--r--include/mbgl/style/types.hpp210
-rw-r--r--include/mbgl/text/collision.hpp25
-rw-r--r--include/mbgl/text/glyph.hpp13
-rw-r--r--include/mbgl/text/glyph_store.hpp27
-rw-r--r--include/mbgl/text/placement.hpp34
-rw-r--r--include/mbgl/text/types.hpp41
-rw-r--r--include/mbgl/util/filesource.hpp45
-rw-r--r--include/mbgl/util/rect.hpp5
-rw-r--r--include/mbgl/util/token.hpp2
-rw-r--r--include/mbgl/util/uv.hpp27
m---------ios/mapbox-gl-cocoa0
-rw-r--r--linux/main.cpp16
-rw-r--r--linux/mapboxgl-app.gyp2
-rw-r--r--macosx/Info.plist11
-rw-r--r--macosx/main.mm81
-rw-r--r--macosx/mapboxgl-app.gyp4
-rw-r--r--mapboxgl.gyp41
-rwxr-xr-xscripts/compare_images.js117
-rwxr-xr-xscripts/deploy_results.sh8
-rw-r--r--src/geometry/icon_buffer.cpp33
-rw-r--r--src/geometry/interpolate.cpp27
-rw-r--r--src/geometry/sprite_atlas.cpp65
-rw-r--r--src/map/map.cpp129
-rw-r--r--src/map/raster_tile_data.cpp6
-rw-r--r--src/map/source.cpp52
-rw-r--r--src/map/sprite.cpp119
-rw-r--r--src/map/tile_data.cpp18
-rw-r--r--src/map/tile_parser.cpp129
-rw-r--r--src/map/transform.cpp12
-rw-r--r--src/map/vector_tile_data.cpp12
-rw-r--r--src/renderer/debug_bucket.cpp2
-rw-r--r--src/renderer/icon_bucket.cpp79
-rw-r--r--src/renderer/line_bucket.cpp2
-rw-r--r--src/renderer/painter.cpp19
-rw-r--r--src/renderer/painter_fill.cpp5
-rw-r--r--src/renderer/painter_framebuffers.cpp1
-rw-r--r--src/renderer/painter_icon.cpp45
-rw-r--r--src/renderer/painter_line.cpp7
-rw-r--r--src/renderer/painter_prerender.cpp2
-rw-r--r--src/renderer/painter_raster.cpp4
-rw-r--r--src/renderer/painter_symbol.cpp217
-rw-r--r--src/renderer/painter_text.cpp155
-rw-r--r--src/renderer/symbol_bucket.cpp394
-rw-r--r--src/renderer/text_bucket.cpp146
-rw-r--r--src/shader/icon.fragment.glsl11
-rw-r--r--src/shader/icon.vertex.glsl69
-rw-r--r--src/shader/icon_shader.cpp138
-rw-r--r--src/shader/line.fragment.glsl5
-rw-r--r--src/shader/line_shader.cpp8
-rw-r--r--src/shader/text_shader.cpp1
-rw-r--r--src/style/property_fallback.cpp92
-rw-r--r--src/style/style.cpp7
-rw-r--r--src/style/style_bucket.cpp3
-rw-r--r--src/style/style_layer.cpp45
-rw-r--r--src/style/style_parser.cpp168
-rw-r--r--src/style/style_properties.cpp3
-rw-r--r--src/text/collision.cpp250
-rw-r--r--src/text/glyph_store.cpp133
-rw-r--r--src/text/placement.cpp333
-rw-r--r--src/text/rotation_range.cpp6
-rw-r--r--src/util/filesource.cpp58
-rw-r--r--styles/bright/img/sprite.json2818
-rw-r--r--styles/bright/img/sprite.pngbin0 -> 118946 bytes
-rw-r--r--styles/bright/img/sprite@2x.json2818
-rw-r--r--styles/bright/img/sprite@2x.pngbin0 -> 272040 bytes
-rw-r--r--styles/bright/style.json1336
-rw-r--r--test/enums.cpp9
-rw-r--r--test/fixtures/glyphs/Open Sans Semibold, Arial Unicode MS Bold/0-255.pbfbin84942 -> 0 bytes
-rw-r--r--test/fixtures/sprites/outdoors.json1
-rw-r--r--test/fixtures/sprites/outdoors.pngbin40912 -> 0 bytes
-rw-r--r--test/fixtures/styles/icons.info.json18
-rw-r--r--test/fixtures/styles/icons.style.json33
-rw-r--r--test/fixtures/styles/icons/default.expected.pngbin6538 -> 0 bytes
-rw-r--r--test/fixtures/styles/line-color.info.json27
-rw-r--r--test/fixtures/styles/line-color.style.json33
-rw-r--r--test/fixtures/styles/line-color/colored.expected.pngbin64163 -> 0 bytes
-rw-r--r--test/fixtures/styles/line-color/default.expected.pngbin80000 -> 0 bytes
-rw-r--r--test/fixtures/styles/road-width.info.json45
-rw-r--r--test/fixtures/styles/road-width.style.json31
-rw-r--r--test/fixtures/styles/road-width/z13.9.expected.pngbin1142 -> 0 bytes
-rw-r--r--test/fixtures/styles/road-width/z14.0.expected.pngbin51801 -> 0 bytes
-rw-r--r--test/fixtures/styles/road-width/z14.1.expected.pngbin35033 -> 0 bytes
-rw-r--r--test/fixtures/styles/road-width/z14.2.expected.pngbin23417 -> 0 bytes
-rw-r--r--test/fixtures/styles/world-aa.info.json9
-rw-r--r--test/fixtures/styles/world-aa.style.json29
-rw-r--r--test/fixtures/styles/world-aa/plain.expected.pngbin31356 -> 0 bytes
-rw-r--r--test/fixtures/styles/world-no-aa.info.json10
-rw-r--r--test/fixtures/styles/world-no-aa.style.json30
-rw-r--r--test/fixtures/styles/world-no-aa/plain.expected.pngbin9451 -> 0 bytes
-rw-r--r--test/fixtures/tiles/0-0-0.vector.pbfbin79244 -> 0 bytes
-rw-r--r--test/fixtures/tiles/13-4401-2687.vector.pbfbin97260 -> 0 bytes
-rw-r--r--test/fixtures/tiles/14-8802-5374.vector.pbfbin399937 -> 0 bytes
-rw-r--r--test/fixtures/tiles/14-8802-5375.vector.pbfbin325249 -> 0 bytes
-rw-r--r--test/fixtures/tiles/14-8803-5374.vector.pbfbin347363 -> 0 bytes
-rw-r--r--test/fixtures/tiles/14-8803-5375.vector.pbfbin448599 -> 0 bytes
-rw-r--r--test/fixtures/tiles/2-1-1.vector.pbfbin74471 -> 0 bytes
-rw-r--r--test/fixtures/tiles/2-1-2.vector.pbfbin41406 -> 0 bytes
-rw-r--r--test/fixtures/tiles/2-2-1.vector.pbfbin272036 -> 0 bytes
-rw-r--r--test/fixtures/tiles/2-2-2.vector.pbfbin29521 -> 0 bytes
-rw-r--r--test/headless.cpp104
-rw-r--r--test/test.gyp2
139 files changed, 9591 insertions, 4587 deletions
diff --git a/.travis.yml b/.travis.yml
index ec877eb68b..eb4e700b1e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -22,6 +22,7 @@ before_install:
install:
- make setup
+- npm install git+https://github.com/mapbox/mapbox-gl-test-suite.git
before_script:
- rm -rf mapnik-packaging/out/packages
@@ -30,10 +31,7 @@ script:
- make linux -j4 BUILDTYPE=${BUILDTYPE}
- make test -j4 BUILDTYPE=${BUILDTYPE}
- ./scripts/run_tests.sh
-- ./scripts/compare_images.js
-
-after_script:
-- ./scripts/deploy_results.sh
+- (cd ./node_modules/mapbox-gl-test-suite/ && (./bin/compare_images.js; ./bin/deploy_results.sh))
notifications:
hipchat:
diff --git a/Makefile b/Makefile
index bfb550affc..fb1c5b3ec7 100644
--- a/Makefile
+++ b/Makefile
@@ -78,8 +78,10 @@ xproj: config.gypi macosx/mapboxgl-app.gyp clear_xcode_cache node
open ./build/macosx/mapboxgl-app.xcodeproj
# build iOS project for Xcode
-iproj: config.gypi ios/mapbox-gl-cocoa/app/mapboxgl-app.gyp clear_xcode_cache node
+iproj-cli: config.gypi ios/mapbox-gl-cocoa/app/mapboxgl-app.gyp clear_xcode_cache node
deps/run_gyp ios/mapbox-gl-cocoa/app/mapboxgl-app.gyp --depth=. --generator-output=./build -f xcode
+
+iproj: iproj-cli
open ./build/ios/mapbox-gl-cocoa/app/mapboxgl-app.xcodeproj
# build Linux project for Xcode (Runs on Mac OS X too, but without platform-specific code)
diff --git a/README.md b/README.md
index b69166aedc..9a67c51b59 100644
--- a/README.md
+++ b/README.md
@@ -5,14 +5,15 @@ implemented in C++11, currently targeting iOS, OS X, and Ubuntu Linux.
# Depends
- - Modern C++ compiler that supports `-std=c++11` (On OSX clang++, on Linux g++-4.8 or g++-4.9)
+ - Modern C++ compiler that supports `-std=c++11` (On OS X clang++, on Linux g++-4.8 or g++-4.9)
- Boost headers
- `libpng`
- `libuv`
- `glfw3`
- `libcurl` (depends on OpenSSL; Linux only)
- `libboost_regex` (Linux only)
- - Homebrew (for build on OS X)
+ - Apple Command Line Tools (for build on OS X; available at [Apple Developer](https://developer.apple.com/downloads))
+ - [Homebrew](http://brew.sh) (for build on OS X)
- Python 2.x (for build only)
- Node.js (for build only)
@@ -33,6 +34,8 @@ The demo applications use Mapbox vector tiles, which **require a Mapbox account
For iOS and OS X use of the demo apps in Xcode, setup the access token by editing the scheme for the application target, then adding an environment variable with the name `MAPBOX_ACCESS_TOKEN`.
+![edit scheme](https://cloud.githubusercontent.com/assets/98601/3647749/30f74f26-1102-11e4-84af-f1be853b4e38.png)
+
![setting access token in Xcode scheme](https://cloud.githubusercontent.com/assets/52399/3543326/9e7cfbb8-0860-11e4-8def-3684a9028b61.png)
## OS X
diff --git a/bin/build-style.js b/bin/build-style.js
deleted file mode 100755
index 06d4cc0808..0000000000
--- a/bin/build-style.js
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env node
-'use strict';
-
-var mkdirp = require('mkdirp');
-var path = require('path');
-var fs = require('fs');
-
-var data = JSON.stringify(require(path.join(process.cwd(), process.argv[2])));
-var out = path.join(process.argv[3], 'style.min.js');
-
-mkdirp.sync(path.dirname(out));
-fs.writeFileSync(out, data);
diff --git a/bin/default.style.json b/bin/default.style.json
deleted file mode 100755
index aea2a1a3ac..0000000000
--- a/bin/default.style.json
+++ /dev/null
@@ -1,2244 +0,0 @@
-{
- "version": 3,
- "sprite": "https://www.mapbox.com/mapbox-gl-styles/sprites/outdoors",
- "glyphs": "https://mapbox.s3.amazonaws.com/gl-glyphs-256/{fontstack}/{range}.pbf",
- "sources": {
- "mapbox": {
- "type": "vector",
- "url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5",
- "maxZoom": 14
- }
- },
- "constants": {
- "@land": "rgb(244,239,225)",
- "@water": "#cdd",
- "@water_dark": "#185869",
- "@crop": "#eeeed4",
- "@grass": "#e6e6cc",
- "@scrub": "#dfe5c8",
- "@wood": "#cee2bd",
- "@snow": "#f4f8ff",
- "@rock": "#ddd",
- "@sand": "#ffd",
- "@cemetery": "#edf4ed",
- "@pitch": "#fff",
- "@park": "#d4e4bc",
- "@piste": "blue",
- "@school": "#e8dfe0",
- "@hospital": "#f8eee0",
- "@builtup": "#f6faff",
- "@case": "#fff",
- "@motorway": "#cda0a0",
- "@main": "#ddc0b9",
- "@street": "#fff",
- "@text": "#666",
- "@text_stroke": "rgba(255,255,255,0.8)",
- "@country_text": "#222",
- "@marine_text": "#a0bdc0",
- "@water_text": "#185869",
- "@land_night": "#017293",
- "@water_night": "#103",
- "@water_dark_night": "#003366",
- "@crop_night": "#178d96",
- "@grass_night": "#23948a",
- "@scrub_night": "#31a186",
- "@wood_night": "#45b581",
- "@park_night": "#51bd8b",
- "@snow_night": "#5ad9fe",
- "@rock_night": "#999",
- "@sand_night": "#437162",
- "@cemetery_night": "#218c96",
- "@pitch_night": "rgba(255,255,255,0.2)",
- "@school_night": "#01536a",
- "@hospital_night": "#015e7a",
- "@builtup_night": "#014b60",
- "@admin_night": "#ffb680",
- "@text_night": "#fff",
- "@text_water_night": "#2a5b8a",
- "@text_stroke_night": "#103",
- "@text2_stroke_night": "rgba(1,69,89,0.8)",
- "@case_night": "#015e7a",
- "@street_case_night": "#015b76",
- "@motorway_night": "#bbdde7",
- "@main_night": "#64b2c9",
- "@street_night": "#0186ac",
- "@contour_night": "#ffff80",
- "@river_canal_width": {
- "stops": [[10, 0.5], [11, 1], [13, 2], [15, 3]]
- },
- "@stream_width": {
- "stops": [[12, 0.25], [13, 0.5], [15, 1.5], [17, 2]]
- },
- "@motorway_width": {
- "stops": [[4, 0], [5, 0.5], [7, 0.8], [9, 1], [10, 1.2], [11, 2], [12, 3], [13, 4], [14, 6], [15, 9], [16, 12], [17, 14]]
- },
- "@motorway_casing_width": {
- "stops": [[6.5, 0.6], [7, 0.8], [9, 2.8], [10, 3], [11, 4], [12, 5], [13, 6.5], [14, 9], [15, 12], [16, 15], [17, 17]]
- },
- "@motorway_link_width": {
- "stops": [[11, 1.2], [13, 2], [15, 3], [17, 4]]
- },
- "@motorway_link_casing_width": {
- "stops": [[11, 2.8], [13, 3.5], [15, 5], [17, 6]]
- },
- "@main_width": {
- "stops": [[4, 1], [11, 1], [12, 1.5], [13, 2], [14, 3], [15, 6], [16, 10], [17, 12]]
- },
- "@main_casing_width": {
- "stops": [[8, 2.9], [11, 2.9], [12, 3.5], [13, 4], [14, 5.5], [15, 9], [16, 12], [17, 14]]
- },
- "@street_width": {
- "stops": [[13.5, 0], [14, 1.5], [15, 3], [16, 8]]
- },
- "@street_casing_width": {
- "stops": [[12, 0.4], [13, 1], [14, 2.5], [15, 4], [16, 10]]
- },
- "@street_casing_opacity": {
- "stops": [[13, 0], [13.5, 1]]
- },
- "@service_casing_width": {
- "stops": [[13, 0.5], [14, 3], [15, 3.5], [16, 4], [17, 5], [18, 6]]
- },
- "@runway_width": {
- "stops": [[9, 1], [10, 2], [11, 3], [12, 5], [13, 7], [14, 11], [15, 15], [16, 19], [17, 23]]
- },
- "@taxiway_width": {
- "stops": [[9, 0.2], [11, 0.2], [12, 1], [13, 1.5], [14, 2], [15, 3], [16, 4], [17, 5]]
- },
- "@aerialway_width": {
- "stops": [[12.5, 0.8], [13, 1.4], [14, 1.6], [15, 2], [16, 2.4], [17, 3]]
- },
- "@aerialway_casing_width": {
- "stops": [[12.5, 2], [13, 2.5], [14, 3], [15, 3.5], [16, 4], [21, 5]]
- },
- "@path_width": {
- "stops": [[13, 1.2], [14, 1.5], [15, 1.8]]
- },
- "@admin_l2_width": {
- "stops": [[1, 0.5], [2, 0.7], [3, 0.7], [4, 0.8], [5, 1], [7, 2], [9, 3]]
- },
- "@admin_l3_width": {
- "stops": [[5, 0.6], [7, 1], [11, 2]]
- },
- "@road_label_1_size": {
- "stops": [[12, 11], [13, 12], [14, 13], [15, 14], [16, 16], [17, 18]]
- },
- "@road_label_2_size": {
- "stops": [[12, 11], [13, 12], [15, 14], [17, 16]]
- },
- "@road_label_3_size": {
- "stops": [[14, 10], [15, 12], [17, 14]]
- },
- "@fence_width": {
- "stops": [[16, 0.6], [18, 1]]
- },
- "@hedge_width": {
- "stops": [[15, 0.6], [16, 1.2], [18, 1.6]]
- },
- "@barrier_line_land_width": {
- "stops": [[13, 0.4], [14, 0.75], [15, 1.5], [16, 3], [17, 6], [18, 12], [19, 24], [20, 48]]
- },
- "@country_label_size": {
- "stops": [[0, 14], [11, 24]]
- },
- "@poi_label_1-2_size": {
- "stops": [[14, 10], [15, 11], [16, 12]]
- },
- "@poi_label_3_size": {
- "stops": [[15, 10], [16, 11]]
- },
- "@hillshade_rasterize": {
- "enabled": {
- "stops": [[10, false], [11, true]]
- },
- "size": {
- "stops": [[10, 1024], [11, 512], [12, 256]]
- },
- "blur": 1
- }
- },
- "layers": [{
- "id": "background",
- "type": "background",
- "style": {
- "background-color": "@land"
- },
- "style.night": {
- "background-color": "@land_night"
- }
- }, {
- "id": "landcover_snow",
- "source": "mapbox",
- "source-layer": "landcover",
- "filter": { "class": "snow" },
- "type": "fill",
- "style": {
- "fill-color": "@snow"
- },
- "style.night": {
- "fill-color": "@snow_night"
- }
- }, {
- "id": "landcover_crop",
- "source": "mapbox",
- "source-layer": "landcover",
- "filter": { "class": "crop" },
- "type": "fill",
- "style": {
- "fill-color": "@crop"
- },
- "style.night": {
- "fill-color": "@crop_night"
- }
- }, {
- "id": "landcover_grass",
- "source": "mapbox",
- "source-layer": "landcover",
- "filter": { "class": "grass" },
- "type": "fill",
- "style": {
- "fill-color": "@grass",
- "fill-opacity": {
- "stops": [[12, 1], [13, 0.8], [16, 0.2]]
- }
- },
- "style.night": {
- "fill-color": "@grass_night",
- "fill-opacity": {
- "stops": [[12, 1], [13, 0.8], [16, 0.2]]
- }
- }
- }, {
- "id": "landcover_scrub",
- "source": "mapbox",
- "source-layer": "landcover",
- "filter": { "class": "scrub" },
- "type": "fill",
- "style": {
- "fill-color": "@scrub",
- "fill-opacity": {
- "stops": [[12, 1], [13, 0.8], [16, 0.2]]
- }
- },
- "style.night": {
- "fill-color": "@scrub_night",
- "fill-opacity": {
- "stops": [[12, 1], [13, 0.8], [16, 0.2]]
- }
- }
- }, {
- "id": "landcover_wood",
- "source": "mapbox",
- "source-layer": "landcover",
- "filter": { "class": "wood" },
- "type": "fill",
- "style": {
- "fill-color": "@wood",
- "fill-opacity": {
- "stops": [[12, 1], [13, 0.8], [16, 0.2]]
- }
- },
- "style.night": {
- "fill-color": "@wood_night",
- "fill-opacity": {
- "stops": [[12, 1], [13, 0.8], [16, 0.2]]
- }
- }
- }, {
- "id": "landuse_wood",
- "source": "mapbox",
- "source-layer": "landuse",
- "filter": { "class": "wood" },
- "type": "fill",
- "style": {
- "fill-color": "@wood"
- },
- "style.night": {
- "fill-color": "@wood_night",
- "fill-opacity": 0.8
- }
- }, {
- "id": "landuse_school",
- "source": "mapbox",
- "source-layer": "landuse",
- "filter": { "class": "school" },
- "type": "fill",
- "style": {
- "fill-color": "@school"
- },
- "style.night": {
- "fill-color": "@school_night"
- }
- }, {
- "id": "landuse_sand",
- "source": "mapbox",
- "source-layer": "landuse",
- "filter": { "class": "sand" },
- "type": "fill",
- "style": {
- "fill-color": "@sand"
- },
- "style.night": {
- "fill-color": "@sand_night",
- "fill-opacity": 0.8
- }
- }, {
- "id": "landuse_pitch",
- "source": "mapbox",
- "source-layer": "landuse",
- "filter": { "class": "pitch" },
- "type": "fill",
- "style": {
- "fill-color": "rgba(255,255,255,0.5)",
- "fill-outline-color": "@pitch"
- },
- "style.night": {
- "fill-color": "@pitch_night",
- "fill-outline-color": "@pitch"
- }
- }, {
- "id": "landuse_park",
- "source": "mapbox",
- "source-layer": "landuse",
- "filter": { "class": "park" },
- "type": "fill",
- "style": {
- "fill-color": "@park"
- },
- "style.night": {
- "fill-color": "@park_night"
- }
- }, {
- "id": "landuse_industrial",
- "source": "mapbox",
- "source-layer": "landuse",
- "filter": { "class": "industrial" },
- "type": "fill",
- "style": {
- "fill-color": "rgba(246,250,255,0.5)"
- },
- "style.night": {
- "fill-color": "@builtup_night"
- }
- }, {
- "id": "landuse_scrub",
- "source": "mapbox",
- "source-layer": "landuse",
- "filter": { "class": "scrub" },
- "type": "fill",
- "style": {
- "fill-color": "@scrub"
- },
- "style.night": {
- "fill-color": "@scrub_night",
- "fill-opacity": 0.8
- }
- }, {
- "id": "landuse_grass",
- "source": "mapbox",
- "source-layer": "landuse",
- "filter": { "class": "grass" },
- "type": "fill",
- "style": {
- "fill-color": "@grass"
- },
- "style.night": {
- "fill-color": "@grass_night",
- "fill-opacity": 0.8
- }
- }, {
- "id": "landuse_crop",
- "source": "mapbox",
- "source-layer": "landuse",
- "filter": { "class": "crop" },
- "type": "fill",
- "style": {
- "fill-color": "@crop"
- },
- "style.night": {
- "fill-color": "@crop_night",
- "fill-opacity": 0.8
- }
- }, {
- "id": "landuse_rock",
- "source": "mapbox",
- "source-layer": "landuse",
- "filter": { "class": "rock" },
- "type": "fill",
- "style": {
- "fill-color": "@rock"
- },
- "style.night": {
- "fill-color": "@rock_night",
- "fill-opacity": 0.8
- }
- }, {
- "id": "landuse_snow",
- "source": "mapbox",
- "source-layer": "landuse",
- "filter": { "class": "snow" },
- "type": "fill",
- "style": {
- "fill-color": "@snow"
- },
- "style.night": {
- "fill-color": "@snow_night",
- "fill-opacity": 0.8
- }
- }, {
- "id": "landuse_hospital",
- "source": "mapbox",
- "source-layer": "landuse",
- "filter": { "class": "hospital" },
- "type": "fill",
- "style": {
- "fill-color": "@hospital"
- },
- "style.night": {
- "fill-color": "@hospital_night"
- }
- }, {
- "id": "landuse_cemetery",
- "source": "mapbox",
- "source-layer": "landuse",
- "filter": { "class": "cemetery" },
- "type": "fill",
- "style": {
- "fill-color": "@cemetery"
- },
- "style.night": {
- "fill-color": "@cemetery_night"
- }
- }, {
- "id": "overlay_wetland",
- "source": "mapbox",
- "source-layer": "landuse_overlay",
- "filter": { "class": ["wetland", "wetland_noveg"] },
- "type": "fill",
- "style": {
- "fill-color": "rgba(210,225,225,0.2)",
- "fill-image": "wetland_noveg_64"
- },
- "style.night": {
- "fill-color": "rgba(210,225,225,0.2)",
- "fill-image": "wetland_noveg_64"
- }
- }, {
- "id": "overlay_breakwater_pier",
- "source": "mapbox",
- "source-layer": "landuse_overlay",
- "filter": { "class": ["breakwater", "pier"] },
- "type": "fill",
- "style": {
- "fill-color": "@land"
- },
- "style.night": {
- "fill-color": "@land_night"
- }
- }, {
- "id": "waterway_river_canal",
- "source": "mapbox",
- "source-layer": "waterway",
- "filter": { "type": ["river", "canal"] },
- "type": "line",
- "render": {
- "line-cap": "round"
- },
- "style": {
- "line-color": "#87abaf",
- "line-width": "@river_canal_width"
- },
- "style.night": {
- "line-color": "rgb(10,20,71)",
- "line-width": "@river_canal_width"
- }
- }, {
- "id": "waterway_stream",
- "source": "mapbox",
- "source-layer": "waterway",
- "filter": { "type": "stream" },
- "type": "line",
- "render": {
- "line-cap": "round"
- },
- "style": {
- "line-color": "#87abaf",
- "line-width": "@stream_width"
- },
- "style.night": {
- "line-color": "rgb(10,20,71)",
- "line-width": "@stream_width"
- }
- }, {
- "id": "building_shadow",
- "source": "mapbox",
- "source-layer": "building",
- "type": "fill",
- "style": {
- "fill-color": "#d5d1c6",
- "fill-translate": [1, 1],
- "fill-opacity": {
- "stops": [[15.5, 0], [16, 1]]
- },
- "fill-outline-color": "#d5d1c6"
- },
- "style.night": {
- "fill-color": "#026688",
- "fill-translate": [1, 1],
- "fill-opacity": {
- "stops": [[15.5, 0], [16, 1]]
- },
- "fill-outline-color": "#026688"
- }
- }, {
- "id": "building",
- "ref": "building_shadow",
- "style": {
- "fill-color": "#ebe7db"
- },
- "style.night": {
- "fill-color": "#027797"
- }
- }, {
- "id": "building_wall",
- "ref": "building_shadow",
- "style": {
- "fill-color": "#ebe7db",
- "fill-opacity": {
- "stops": [[15.5, 0], [16, 0.7]]
- },
- "fill-outline-color": "#d5d1c6"
- },
- "style.night": {
- "fill-color": "#027797",
- "fill-opacity": {
- "stops": [[15.5, 0], [16, 0.7]]
- },
- "fill-outline-color": "#026688"
- }
- }, {
- "id": "hillshade_full_highlight",
- "source": "mapbox",
- "source-layer": "hillshade",
- "filter": { "class": "full_highlight" },
- "type": "fill",
- "rasterize": "@hillshade_rasterize",
- "style": {
- "fill-color": "#fffff3",
- "fill-antialias": false,
- "fill-opacity": {
- "stops": [[14, 0.3], [15, 0.3], [16, 0.2], [17, 0.2], [18, 0.1]]
- }
- },
- "style.night": {
- "fill-color": "#fdfdad",
- "fill-antialias": false,
- "fill-opacity": {
- "stops": [[13, 0.4], [14, 0.3], [16, 0.2], [17, 0.1], [18, 0.05]]
- }
- }
- }, {
- "id": "hillshade_medium_highlight",
- "source": "mapbox",
- "source-layer": "hillshade",
- "filter": { "class": "medium_highlight" },
- "type": "fill",
- "rasterize": "@hillshade_rasterize",
- "style": {
- "fill-color": "#ffd",
- "fill-antialias": false,
- "fill-opacity": {
- "stops": [[14, 0.3], [15, 0.3], [16, 0.2], [17, 0.2], [18, 0.1]]
- }
- },
- "style.night": {
- "fill-color": "#ffe1b7",
- "fill-antialias": false,
- "fill-opacity": {
- "stops": [[14, 0.3], [16, 0.2], [17, 0.15], [18, 0.05]]
- }
- }
- }, {
- "id": "hillshade_medium_shadow",
- "source": "mapbox",
- "source-layer": "hillshade",
- "filter": { "class": "medium_shadow" },
- "type": "fill",
- "rasterize": "@hillshade_rasterize",
- "style": {
- "fill-color": "#206",
- "fill-antialias": false,
- "fill-opacity": {
- "stops": [[14, 0.08], [15, 0.075], [16, 0.05], [17, 0.05], [18, 0.025]]
- }
- },
- "style.night": {
- "fill-color": "#206",
- "fill-antialias": false,
- "fill-opacity": {
- "stops": [[15, 0.3], [16, 0.2], [17, 0.1], [18, 0.05]]
- }
- }
- }, {
- "id": "hillshade_full_shadow",
- "source": "mapbox",
- "source-layer": "hillshade",
- "filter": { "class": "full_shadow" },
- "type": "fill",
- "rasterize": "@hillshade_rasterize",
- "style": {
- "fill-color": "#103",
- "fill-antialias": false,
- "fill-opacity": {
- "stops": [[14, 0.08], [15, 0.075], [16, 0.05], [17, 0.05], [18, 0.025]]
- }
- },
- "style.night": {
- "fill-color": "#103",
- "fill-antialias": false,
- "fill-opacity": {
- "stops": [[15, 0.3], [16, 0.2], [17, 0.1], [18, 0.05]]
- }
- }
- }, {
- "id": "contour_line_loud",
- "source": "mapbox",
- "source-layer": "contour",
- "filter": { "index": 5 },
- "type": "line",
- "render": {
- "line-join": "round"
- },
- "style": {
- "line-color": "#008",
- "line-width": 0.9,
- "line-opacity": {
- "stops": [[11, 0.05], [12, 0.11]]
- }
- },
- "style.night": {
- "line-color": "@contour_night",
- "line-width": 0.9,
- "line-opacity": {
- "stops": [[11, 0.1], [12, 0.2]]
- }
- }
- }, {
- "id": "contour_line_regular",
- "source": "mapbox",
- "source-layer": "contour",
- "type": "line",
- "render": {
- "line-join": "round"
- },
- "style": {
- "line-color": "#008",
- "line-width": 0.5,
- "line-opacity": {
- "stops": [[11, 0.05], [12, 0.11]]
- }
- },
- "style.night": {
- "line-color": "@contour_night",
- "line-width": 0.5,
- "line-opacity": {
- "stops": [[11, 0.1], [12, 0.4]]
- }
- }
- }, {
- "id": "barrier_line_gate",
- "source": "mapbox",
- "source-layer": "barrier_line",
- "filter": { "class": "gate" },
- "type": "line",
- "style": {
- "line-width": 2.5,
- "line-color": "#aab"
- },
- "style.night": {
- "line-width": 2.5,
- "line-color": "#59596f"
- }
- }, {
- "id": "barrier_line_fence",
- "source": "mapbox",
- "source-layer": "barrier_line",
- "filter": { "class": "fence" },
- "type": "line",
- "style": {
- "line-color": "#aeada3",
- "line-width": "@fence_width"
- },
- "style.night": {
- "line-color": "#014b61",
- "line-width": "@fence_width"
- }
- }, {
- "id": "barrier_line_hedge",
- "source": "mapbox",
- "source-layer": "barrier_line",
- "filter": { "class": "hedge" },
- "type": "line",
- "style": {
- "line-color": "#8de99b",
- "line-width": "@hedge_width"
- },
- "style.night": {
- "line-color": "#2e7a57",
- "line-width": "@hedge_width"
- }
- }, {
- "id": "barrier_line_land",
- "source": "mapbox",
- "source-layer": "barrier_line",
- "filter": { "class": "land" },
- "type": "line",
- "style": {
- "line-color": "@land",
- "line-width": "@barrier_line_land_width"
- },
- "style.night": {
- "line-color": "@land_night",
- "line-width": "@barrier_line_land_width"
- }
- }, {
- "id": "barrier_line_land_fill",
- "source": "mapbox",
- "source-layer": "barrier_line",
- "filter": { "class": "land" },
- "type": "fill",
- "style": {
- "fill-color": "@land"
- },
- "style.night": {
- "fill-color": "@land_night"
- }
- }, {
- "id": "barrier_line_cliff",
- "source": "mapbox",
- "source-layer": "barrier_line",
- "filter": { "class": "cliff" },
- "type": "line",
- "style": {
- "line-color": "#987",
- "line-width": 4
- },
- "style.night": {
- "line-color": "#63574b",
- "line-width": 4
- }
- }, {
- "id": "water",
- "source": "mapbox",
- "source-layer": "water",
- "type": "fill",
- "style": {
- "fill-color": "@water",
- "fill-outline-color": "#a2bdc0"
- },
- "style.night": {
- "fill-color": "@water_night",
- "fill-outline-color": "@water_dark_night"
- }
- }, {
- "id": "aeroway_fill",
- "source": "mapbox",
- "source-layer": "aeroway",
- "type": "fill",
- "style": {
- "fill-color": "#ddd"
- },
- "style.night": {
- "fill-color": "#367"
- }
- }, {
- "id": "aeroway_runway",
- "source": "mapbox",
- "source-layer": "aeroway",
- "filter": { "type": "runway" },
- "type": "line",
- "style": {
- "line-color": "#ddd",
- "line-width": "@runway_width"
- },
- "style.night": {
- "line-color": "#367",
- "line-width": "@runway_width"
- }
- }, {
- "id": "aeroway_taxiway",
- "source": "mapbox",
- "source-layer": "aeroway",
- "filter": { "type": "taxiway" },
- "type": "line",
- "style": {
- "line-color": "#ddd",
- "line-width": "@taxiway_width"
- },
- "style.night": {
- "line-color": "#367",
- "line-width": "@taxiway_width"
- }
- }, {
- "id": "tunnel_motorway_link_casing",
- "source": "mapbox",
- "source-layer": "tunnel",
- "filter": { "class": "motorway_link" },
- "type": "line",
- "style": {
- "line-color": "@case",
- "line-dasharray": [6, 6],
- "line-width": "@motorway_link_casing_width"
- },
- "style.night": {
- "line-color": "@case_night",
- "line-dasharray": [6, 6],
- "line-width": "@motorway_link_casing_width"
- }
- }, {
- "id": "tunnel_service_casing",
- "source": "mapbox",
- "source-layer": "tunnel",
- "filter": { "class": "service" },
- "type": "line",
- "style": {
- "line-color": "#000",
- "line-opacity": 0.04,
- "line-dasharray": [6, 6],
- "line-width": "@service_casing_width"
- },
- "style.night": {
- "line-color": "#000",
- "line-opacity": 0.04,
- "line-dasharray": [6, 6],
- "line-width": "@service_casing_width"
- }
- }, {
- "id": "tunnel_main_casing",
- "source": "mapbox",
- "source-layer": "tunnel",
- "filter": { "class": "main" },
- "type": "line",
- "style": {
- "line-color": "@case",
- "line-dasharray": [6, 6],
- "line-width": "@main_casing_width",
- "line-opacity": {
- "stops": [[8, 0], [9, 1]]
- }
- },
- "style.night": {
- "line-color": "@case_night",
- "line-dasharray": [6, 6],
- "line-width": "@main_casing_width",
- "line-opacity": {
- "stops": [[8, 0], [9, 1]]
- }
- }
- }, {
- "id": "tunnel_street_casing",
- "source": "mapbox",
- "source-layer": "tunnel",
- "filter": { "class": ["street", "street_limited"] },
- "type": "line",
- "style": {
- "line-color": "#d9d5c6",
- "line-width": "@street_casing_width",
- "line-opacity": "@street_casing_opacity"
- },
- "style.night": {
- "line-color": "@street_case_night",
- "line-width": "@street_casing_width",
- "line-opacity": "@street_casing_opacity"
- }
- }, {
- "id": "tunnel_motorway_link",
- "ref": "tunnel_motorway_link_casing",
- "style": {
- "line-color": "#e6cec7",
- "line-width": "@motorway_link_width"
- },
- "style.night": {
- "line-color": "#78b0c1",
- "line-width": "@motorway_link_width"
- }
- }, {
- "id": "tunnel_service",
- "ref": "tunnel_service_casing",
- "style": {
- "line-color": "#e6cec7",
- "line-width": 2
- },
- "style.night": {
- "line-color": "#017ca0",
- "line-width": 2
- }
- }, {
- "id": "tunnel_street",
- "ref": "tunnel_street_casing",
- "style": {
- "line-color": "#d9d5c6",
- "line-width": "@street_width"
- },
- "style.night": {
- "line-color": "@street_night",
- "line-width": "@street_width"
- }
- }, {
- "id": "tunnel_main",
- "ref": "tunnel_main_casing",
- "style": {
- "line-color": "#e6cec7",
- "line-width": "@main_width",
- "line-opacity": {
- "stops": [[5.5, 0], [6, 1]]
- }
- },
- "style.night": {
- "line-color": "#78b0c1",
- "line-width": "@main_width",
- "line-opacity": {
- "stops": [[5.5, 0], [6, 1]]
- }
- }
- }, {
- "id": "tunnel_motorway_casing",
- "source": "mapbox",
- "source-layer": "tunnel",
- "filter": { "class": "motorway" },
- "type": "line",
- "style": {
- "line-color": "@case",
- "line-dasharray": [6, 6],
- "line-width": "@motorway_casing_width",
- "line-opacity": {
- "stops": [[8.5, 0], [9, 1]]
- }
- },
- "style.night": {
- "line-color": "@case_night",
- "line-dasharray": [6, 6],
- "line-width": "@motorway_casing_width",
- "line-opacity": {
- "stops": [[8.5, 0], [9, 1]]
- }
- }
- }, {
- "id": "tunnel_motorway",
- "ref": "tunnel_motorway_casing",
- "style": {
- "line-color": "#e6cec7",
- "line-width": "@motorway_width",
- "line-opacity": {
- "stops": [[5.5, 0], [6, 1]]
- }
- },
- "style.night": {
- "line-color": "#78b0c1",
- "line-width": "@motorway_width",
- "line-opacity": {
- "stops": [[5.5, 0], [6, 1]]
- }
- }
- }, {
- "id": "road_path_case",
- "source": "mapbox",
- "source-layer": "road",
- "filter": { "class": "path" },
- "type": "line",
- "style": {
- "line-color": "#ffd",
- "line-opacity": 0.4,
- "line-width": {
- "stops": [[14, 3], [15, 4]]
- }
- },
- "style.night": {
- "line-color": "@land_night",
- "line-opacity": 0.2
- }
- }, {
- "id": "road_path_footway",
- "source": "mapbox",
- "source-layer": "bridge",
- "filter": { "type": "footway" },
- "type": "line",
- "style": {
- "line-color": "#bba",
- "line-dasharray": [10, 4],
- "line-width": "@path_width"
- },
- "style.night": {
- "line-color": "#fff",
- "line-dasharray": [10, 4],
- "line-width": "@path_width"
- }
- }, {
- "id": "road_path_path",
- "source": "mapbox",
- "source-layer": "bridge",
- "filter": { "type": "path" },
- "type": "line",
- "style": {
- "line-color": "#987",
- "line-dasharray": [10, 4],
- "line-opacity": 0.8,
- "line-width": {
- "stops": [[13, 0.8], [14, 0.9], [15, 1.2]]
- }
- },
- "style.night": {
- "line-color": "#fff",
- "line-dasharray": [10, 4],
- "line-opacity": 0.8,
- "line-width": {
- "stops": [[13, 0.8], [14, 0.9], [15, 1.2]]
- }
- }
- }, {
- "id": "road_path_cycleway",
- "source": "mapbox",
- "source-layer": "bridge",
- "filter": { "type": "cycleway" },
- "type": "line",
- "style": {
- "line-color": "#488",
- "line-dasharray": [10, 4],
- "line-width": "@path_width"
- },
- "style.night": {
- "line-color": "#94e6ff",
- "line-dasharray": [10, 4],
- "line-width": "@path_width"
- }
- }, {
- "id": "road_path_mtb",
- "source": "mapbox",
- "source-layer": "bridge",
- "filter": { "type": "mtb" },
- "type": "line",
- "style": {
- "line-color": "#488",
- "line-dasharray": [12, 4],
- "line-width": "@path_width"
- },
- "style.night": {
- "line-color": "#94e6ff",
- "line-dasharray": [12, 4],
- "line-width": "@path_width"
- }
- }, {
- "id": "road_path_piste",
- "source": "mapbox",
- "source-layer": "bridge",
- "filter": { "type": "piste" },
- "type": "line",
- "style": {
- "line-color": "#87b",
- "line-dasharray": [8, 4],
- "line-width": "@path_width"
- },
- "style.night": {
- "line-color": "#715dae",
- "line-dasharray": [8, 4],
- "line-width": "@path_width"
- }
- }, {
- "id": "road_path_steps",
- "source": "mapbox",
- "source-layer": "bridge",
- "filter": { "type": "steps" },
- "type": "line",
- "style": {
- "line-color": "#bba",
- "line-dasharray": [10, 4],
- "line-width": 4
- },
- "style.night": {
- "line-color": "#016684",
- "line-dasharray": [10, 4],
- "line-opacity": 0.3,
- "line-width": 6
- }
- }, {
- "id": "road_major_rail",
- "source": "mapbox",
- "source-layer": "bridge",
- "filter": { "class": "major_rail" },
- "type": "line",
- "style": {
- "line-color": "#c8c4c0",
- "line-width": 0.8
- },
- "style.night": {
- "line-color": "#c8c4c0",
- "line-width": 0.8
- }
- }, {
- "id": "road_motorway_link_casing",
- "source": "mapbox",
- "source-layer": "road",
- "filter": { "class": "motorway_link" },
- "type": "line",
- "render": {
- "line-join": "round",
- "line-cap": "round"
- },
- "style": {
- "line-color": "@case",
- "line-width": "@motorway_link_casing_width"
- },
- "style.night": {
- "line-color": "@case_night",
- "line-width": "@motorway_link_casing_width"
- }
- }, {
- "id": "road_service_casing",
- "source": "mapbox",
- "source-layer": "road",
- "filter": { "class": "service" },
- "type": "line",
- "render": {
- "line-join": "round",
- "line-cap": "round"
- },
- "style": {
- "line-color": "#000",
- "line-opacity": 0.04,
- "line-width": "@service_casing_width"
- },
- "style.night": {
- "line-color": "#000",
- "line-opacity": 0.04,
- "line-width": "@service_casing_width"
- }
- }, {
- "id": "road_main_casing",
- "source": "mapbox",
- "source-layer": "road",
- "filter": { "class": "main" },
- "type": "line",
- "render": {
- "line-join": "round",
- "line-cap": "round"
- },
- "style": {
- "line-color": "@case",
- "line-width": "@main_casing_width",
- "line-opacity": {
- "stops": [[8, 0], [9, 1]]
- }
- },
- "style.night": {
- "line-color": "@case_night",
- "line-width": "@main_casing_width",
- "line-opacity": {
- "stops": [[8, 0], [9, 1]]
- }
- }
- }, {
- "id": "road_street_casing",
- "source": "mapbox",
- "source-layer": "road",
- "filter": { "class": ["street", "street_limited"] },
- "type": "line",
- "render": {
- "line-join": "round",
- "line-cap": "round"
- },
- "style": {
- "line-color": "#d9d5c6",
- "line-width": "@street_casing_width",
- "line-opacity": "@street_casing_opacity"
- },
- "style.night": {
- "line-color": "@street_case_night",
- "line-width": "@street_casing_width",
- "line-opacity": "@street_casing_opacity"
- }
- }, {
- "id": "road_motorway_link",
- "ref": "road_motorway_link_casing",
- "style": {
- "line-color": "@motorway",
- "line-width": "@motorway_link_width"
- },
- "style.night": {
- "line-color": "@motorway_night",
- "line-width": "@motorway_link_width"
- }
- }, {
- "id": "road_service",
- "ref": "road_service_casing",
- "style": {
- "line-color": "@street",
- "line-width": 2
- },
- "style.night": {
- "line-color": "@street_night",
- "line-width": 2
- }
- }, {
- "id": "road_street",
- "ref": "road_street_casing",
- "style": {
- "line-color": "@street",
- "line-width": "@street_width"
- },
- "style.night": {
- "line-color": "@street_night",
- "line-width": "@street_width"
- }
- }, {
- "id": "road_main",
- "ref": "road_main_casing",
- "style": {
- "line-color": "@main",
- "line-width": "@main_width",
- "line-opacity": {
- "stops": [[5.5, 0], [6, 1]]
- }
- },
- "style.night": {
- "line-color": "@main_night",
- "line-width": "@main_width",
- "line-opacity": {
- "stops": [[5.5, 0], [6, 1]]
- }
- }
- }, {
- "id": "road_motorway_casing",
- "source": "mapbox",
- "source-layer": "road",
- "filter": { "class": "motorway" },
- "type": "line",
- "render": {
- "line-join": "round",
- "line-cap": "round"
- },
- "style": {
- "line-color": "@case",
- "line-width": "@motorway_casing_width",
- "line-opacity": {
- "stops": [[8.5, 0], [9, 1]]
- }
- },
- "style.night": {
- "line-color": "@case_night",
- "line-width": "@motorway_casing_width",
- "line-opacity": {
- "stops": [[8.5, 0], [9, 1]]
- }
- }
- }, {
- "id": "road_motorway",
- "ref": "road_motorway_casing",
- "style": {
- "line-color": "@motorway",
- "line-width": "@motorway_width",
- "line-opacity": {
- "stops": [[5.5, 0], [6, 1]]
- }
- },
- "style.night": {
- "line-color": "@motorway_night",
- "line-width": "@motorway_width",
- "line-opacity": {
- "stops": [[5.5, 0], [6, 1]]
- }
- }
- }, {
- "id": "road_major_rail_hatching",
- "ref": "road_major_rail",
- "style": {
- "line-color": "#c8c4c0",
- "line-dasharray": [2, 31],
- "line-width": 5
- },
- "style.night": {
- "line-color": "#c8c4c0",
- "line-dasharray": [2, 31],
- "line-width": 5
- }
- }, {
- "id": "bridge_motorway_link_casing",
- "source": "mapbox",
- "source-layer": "bridge",
- "filter": { "class": "motorway_link" },
- "type": "line",
- "style": {
- "line-color": "@case",
- "line-width": "@motorway_link_casing_width"
- },
- "style.night": {
- "line-color": "@case_night",
- "line-width": "@motorway_link_casing_width"
- }
- }, {
- "id": "bridge_service_casing",
- "source": "mapbox",
- "source-layer": "bridge",
- "filter": { "class": "service" },
- "type": "line",
- "style": {
- "line-color": "#000",
- "line-opacity": 0.04,
- "line-width": "@service_casing_width"
- },
- "style.night": {
- "line-color": "#000",
- "line-opacity": 0.04,
- "line-width": "@service_casing_width"
- }
- }, {
- "id": "bridge_main_casing",
- "source": "mapbox",
- "source-layer": "bridge",
- "filter": { "class": "main" },
- "type": "line",
- "style": {
- "line-color": "@case",
- "line-width": "@main_casing_width",
- "line-opacity": {
- "stops": [[8, 0], [9, 1]]
- }
- },
- "style.night": {
- "line-color": "@case_night",
- "line-width": "@main_casing_width",
- "line-opacity": {
- "stops": [[8, 0], [9, 1]]
- }
- }
- }, {
- "id": "bridge_street_casing",
- "source": "mapbox",
- "source-layer": "bridge",
- "filter": { "class": ["street", "street_limited"] },
- "type": "line",
- "style": {
- "line-color": "#d9d5c6",
- "line-width": "@street_casing_width",
- "line-opacity": "@street_casing_opacity"
- },
- "style.night": {
- "line-color": "@street_case_night",
- "line-width": "@street_casing_width",
- "line-opacity": "@street_casing_opacity"
- }
- }, {
- "id": "bridge_motorway_link",
- "ref": "bridge_motorway_link_casing",
- "style": {
- "line-color": "@motorway",
- "line-width": "@motorway_link_width"
- },
- "style.night": {
- "line-color": "@motorway_night",
- "line-width": "@motorway_link_width"
- }
- }, {
- "id": "bridge_service",
- "ref": "bridge_service_casing",
- "style": {
- "line-color": "@street",
- "line-width": 2
- },
- "style.night": {
- "line-color": "@street_night",
- "line-width": 2
- }
- }, {
- "id": "bridge_street",
- "ref": "bridge_street_casing",
- "style": {
- "line-color": "@street",
- "line-width": "@street_width"
- },
- "style.night": {
- "line-color": "@street_night",
- "line-width": "@street_width"
- }
- }, {
- "id": "bridge_main",
- "ref": "bridge_main_casing",
- "style": {
- "line-color": "@main",
- "line-width": "@main_width",
- "line-opacity": {
- "stops": [[5.5, 0], [6, 1]]
- }
- },
- "style.night": {
- "line-color": "@main_night",
- "line-width": "@main_width",
- "line-opacity": {
- "stops": [[5.5, 0], [6, 1]]
- }
- }
- }, {
- "id": "bridge_motorway_casing",
- "source": "mapbox",
- "source-layer": "bridge",
- "filter": { "class": "motorway" },
- "type": "line",
- "style": {
- "line-color": "@case",
- "line-width": "@motorway_casing_width",
- "line-opacity": {
- "stops": [[8.5, 0], [9, 1]]
- }
- },
- "style.night": {
- "line-color": "@case_night",
- "line-width": "@motorway_casing_width",
- "line-opacity": {
- "stops": [[8.5, 0], [9, 1]]
- }
- }
- }, {
- "id": "bridge_motorway",
- "ref": "bridge_motorway_casing",
- "style": {
- "line-color": "@motorway",
- "line-width": "@motorway_width",
- "line-opacity": {
- "stops": [[5.5, 0], [6, 1]]
- }
- },
- "style.night": {
- "line-color": "@motorway_night",
- "line-width": "@motorway_width",
- "line-opacity": {
- "stops": [[5.5, 0], [6, 1]]
- }
- }
- }, {
- "id": "bridge_aerialway_casing",
- "source": "mapbox",
- "source-layer": "bridge",
- "filter": { "class": "aerialway" },
- "type": "line",
- "style": {
- "line-color": "white",
- "line-opacity": 0.5,
- "line-width": "@aerialway_casing_width"
- },
- "style.night": {
- "line-color": "white",
- "line-opacity": 0.5,
- "line-width": "@aerialway_casing_width"
- }
- }, {
- "id": "bridge_aerialway",
- "ref": "bridge_aerialway_casing",
- "style": {
- "line-color": "#876",
- "line-opacity": 0.5,
- "line-width": "@aerialway_width"
- },
- "style.night": {
- "line-color": "#876",
- "line-opacity": 0.5,
- "line-width": "@aerialway_width"
- }
- }, {
- "id": "admin_l3",
- "source": "mapbox",
- "source-layer": "admin",
- "filter": { "admin_level": [3, 4, 5] },
- "type": "line",
- "render": {
- "line-join": "round"
- },
- "style": {
- "line-color": "#88a",
- "line-dasharray": [60, 20],
- "line-opacity": {
- "stops": [[3, 0], [5, 1]]
- },
- "line-width": "@admin_l3_width"
- },
- "style.night": {
- "line-color": "@admin_night",
- "line-dasharray": [60, 20],
- "line-opacity": {
- "stops": [[3, 0], [5, 1]]
- },
- "line-width": "@admin_l3_width"
- }
- }, {
- "id": "admin_l2",
- "source": "mapbox",
- "source-layer": "admin",
- "filter": { "admin_level": 2 },
- "type": "line",
- "render": {
- "line-join": "round",
- "line-cap": "round"
- },
- "style": {
- "line-color": "#88a",
- "line-width": "@admin_l2_width"
- },
- "style.night": {
- "line-color": "@admin_night",
- "line-width": "@admin_l2_width"
- }
- }, {
- "id": "admin_maritime_cover",
- "source": "mapbox",
- "source-layer": "admin",
- "filter": { "maritime": 1 },
- "type": "line",
- "render": {
- "line-join": "round",
- "line-cap": "round"
- },
- "style": {
- "line-color": "@water",
- "line-width": 5
- },
- "style.night": {
- "line-color": "@water_night",
- "line-width": 5
- }
- }, {
- "id": "admin_maritime",
- "ref": "admin_maritime_cover",
- "style": {
- "line-color": "#c0d6d6",
- "line-width": {
- "stops": [[5, 1], [7, 2], [11, 3]]
- }
- },
- "style.night": {
- "line-color": "#0a1347",
- "line-width": {
- "stops": [[5, 1], [7, 2], [11, 3]]
- }
- }
- }, {
- "id": "country_label_line",
- "source": "mapbox",
- "source-layer": "country_label_line",
- "type": "line",
- "render": {
- "text-max-width": 5
- },
- "style": {
- "line-color": "@country_text",
- "line-width": 0.5,
- "line-opacity": 0.5
- },
- "style.night": {
- "line-color": "@text_night",
- "line-width": 0.5,
- "line-opacity": 0.5
- }
- }, {
- "id": "country_label",
- "source": "mapbox",
- "source-layer": "country_label",
- "filter": { "$type": "Point" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-font": "Open Sans Semibold, Arial Unicode MS Bold",
- "text-max-size": 24,
- "text-max-width": 5
- },
- "style": {
- "text-color": "@country_text",
- "text-halo-color": "rgba(255,255,255,0.5)",
- "text-halo-width": 0.5,
- "text-size": "@country_label_size"
- },
- "style.night": {
- "text-color": "@text_night",
- "text-halo-color": "@text2_stroke_night",
- "text-halo-width": 0.4,
- "text-size": "@country_label_size"
- }
- }, {
- "id": "marine_label_line_1",
- "source": "mapbox",
- "source-layer": "marine_label",
- "filter": { "$type": "LineString", "labelrank": 1 },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "curve",
- "text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
- "text-max-size": 30,
- "text-max-angle": 0.5,
- "text-letter-spacing": 0.4
- },
- "style": {
- "text-color": "@marine_text",
- "text-size": {
- "stops": [[2, 20], [3, 25], [4, 30], [21, 30]]
- },
- "text-halo-color": "@water"
- },
- "style.night": {
- "text-color": "@water_dark_night",
- "text-size": {
- "stops": [[2, 20], [3, 25], [4, 30], [21, 30]]
- },
- "text-halo-color": "@water_night"
- }
- }, {
- "id": "marine_label_line_2",
- "source": "mapbox",
- "source-layer": "marine_label",
- "filter": { "$type": "LineString", "labelrank": 2 },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "curve",
- "text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
- "text-max-size": 24,
- "text-max-angle": 0.5
- },
- "style": {
- "text-color": "@marine_text",
- "text-size": {
- "stops": [[2, 13], [3, 14], [4, 20], [5, 24], [21, 24]]
- },
- "text-halo-color": "@water"
- },
- "style.night": {
- "text-color": "@water_dark_night",
- "text-size": {
- "stops": [[2, 13], [3, 14], [4, 20], [5, 24], [21, 24]]
- },
- "text-halo-color": "@water_night"
- }
- }, {
- "id": "marine_label_line_3",
- "source": "mapbox",
- "source-layer": "marine_label",
- "filter": { "$type": "LineString", "labelrank": 3 },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "curve",
- "text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
- "text-max-size": 18,
- "text-max-angle": 0.5
- },
- "style": {
- "text-color": "@marine_text",
- "text-size": {
- "stops": [[2, 12], [3, 13], [4, 15], [5, 18], [21, 18]]
- },
- "text-halo-color": "@water"
- },
- "style.night": {
- "text-color": "@water_dark_night",
- "text-size": {
- "stops": [[2, 12], [3, 13], [4, 15], [5, 18], [21, 18]]
- },
- "text-halo-color": "@water_night"
- }
- }, {
- "id": "marine_label_line_other",
- "source": "mapbox",
- "source-layer": "marine_label",
- "filter": { "$type": "LineString", "labelrank": [4, 5, 6] },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "curve",
- "text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
- "text-max-size": 16,
- "text-max-angle": 0.5
- },
- "style": {
- "text-color": "@marine_text",
- "text-size": {
- "stops": [[3, 12], [4, 14], [5, 16], [21, 16]]
- },
- "text-halo-color": "@water"
- },
- "style.night": {
- "text-color": "@water_dark_night",
- "text-size": {
- "stops": [[3, 12], [4, 14], [5, 16], [21, 16]]
- },
- "text-halo-color": "@water_night"
- }
- }, {
- "id": "marine_label_point_1",
- "source": "mapbox",
- "source-layer": "marine_label",
- "filter": { "$type": "Point", "labelrank": 1 },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
- "text-max-size": 30,
- "text-max-width": 8,
- "text-letter-spacing": 0.4,
- "text-line-height": 2
- },
- "style": {
- "text-color": "@marine_text",
- "text-size": {
- "stops": [[2, 20], [3, 25], [4, 30], [21, 30]]
- },
- "text-halo-color": "@water"
- },
- "style.night": {
- "text-color": "@water_dark_night",
- "text-size": {
- "stops": [[2, 20], [3, 25], [4, 30], [21, 30]]
- },
- "text-halo-color": "@water_night"
- }
- }, {
- "id": "marine_label_point_2",
- "source": "mapbox",
- "source-layer": "marine_label",
- "filter": { "$type": "Point", "labelrank": 2 },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
- "text-max-size": 24,
- "text-max-width": 8,
- "text-letter-spacing": 0.2,
- "text-line-height": 1.5
- },
- "style": {
- "text-color": "@marine_text",
- "text-size": {
- "stops": [[2, 13], [3, 14], [4, 20], [5, 24], [21, 24]]
- },
- "text-halo-color": "@water"
- },
- "style.night": {
- "text-color": "@water_dark_night",
- "text-size": {
- "stops": [[2, 13], [3, 14], [4, 20], [5, 24], [21, 24]]
- },
- "text-halo-color": "@water_night"
- }
- }, {
- "id": "marine_label_point_3",
- "source": "mapbox",
- "source-layer": "marine_label",
- "filter": { "$type": "Point", "labelrank": 3 },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
- "text-max-size": 18,
- "text-max-width": 8,
- "text-letter-spacing": 0.1,
- "text-line-height": 1.3
- },
- "style": {
- "text-color": "@marine_text",
- "text-size": {
- "stops": [[2, 12], [3, 13], [4, 15], [5, 18], [21, 18]]
- },
- "text-halo-color": "@water"
- },
- "style.night": {
- "text-color": "@water_dark_night",
- "text-size": {
- "stops": [[2, 12], [3, 13], [4, 15], [5, 18], [21, 18]]
- },
- "text-halo-color": "@water_night"
- }
- }, {
- "id": "marine_label_point_other",
- "source": "mapbox",
- "source-layer": "marine_label",
- "filter": { "$type": "Point", "labelrank": [4, 5, 6] },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
- "text-max-size": 16,
- "text-max-width": 8,
- "text-letter-spacing": 0.1,
- "text-line-height": 1.2
- },
- "style": {
- "text-color": "@marine_text",
- "text-size": {
- "stops": [[3, 12], [4, 14], [5, 16], [21, 16]]
- },
- "text-halo-color": "@water"
- },
- "style.night": {
- "text-color": "@water_dark_night",
- "text-size": {
- "stops": [[3, 12], [4, 14], [5, 16], [21, 16]]
- },
- "text-halo-color": "@water_night"
- }
- }, {
- "id": "state_label",
- "source": "mapbox",
- "source-layer": "state_label",
- "filter": { "$type": "Point" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-font": "Open Sans Regular, Arial Unicode MS Regular",
- "text-max-size": 16,
- "text-max-width": 8
- },
- "style": {
- "text-color": "#333",
- "text-halo-width": 0.4,
- "text-halo-color": "rgba(244,239,225,0.8)",
- "text-size": {
- "stops": [[2.99, 0], [3, 10], [8.99, 16], [9, 0]]
- }
- },
- "style.night": {
- "text-color": "#fff",
- "text-halo-width": 0.4,
- "text-halo-color": "@land_night",
- "text-size": {
- "stops": [[2.99, 0], [3, 10], [8.99, 16], [9, 0]]
- }
- }
- }, {
- "id": "place_label_city",
- "source": "mapbox",
- "source-layer": "place_label",
- "filter": { "type": "city", "$type": "Point" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-font": "Open Sans Semibold, Arial Unicode MS Bold",
- "text-max-size": 20,
- "text-max-width": 8
- },
- "style": {
- "text-color": "#444",
- "text-halo-width": 0.4,
- "text-halo-color": "@text_stroke",
- "text-size": {
- "stops": [[2.99, 0], [3, 10], [6, 14], [13.99, 20], [14, 0]]
- }
- },
- "style.night": {
- "text-color": "#fff",
- "text-halo-width": 0.4,
- "text-halo-color": "@text2_stroke_night",
- "text-size": {
- "stops": [[2.99, 0], [3, 10], [6, 14], [13.99, 20], [14, 0]]
- }
- }
- }, {
- "id": "place_label_town",
- "source": "mapbox",
- "source-layer": "place_label",
- "filter": { "type": "town", "$type": "Point" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-font": "Open Sans Semibold, Arial Unicode MS Bold",
- "text-max-size": 24,
- "text-max-width": 8
- },
- "style": {
- "text-color": "#716656",
- "text-halo-width": 0.3,
- "text-halo-color": "@text_stroke",
- "text-size": {
- "stops": [[8, 10], [11, 13], [13, 17], [15, 22]]
- }
- },
- "style.night": {
- "text-color": "@text_night",
- "text-halo-width": 0.3,
- "text-halo-color": "@text2_stroke_night",
- "text-size": {
- "stops": [[8, 10], [11, 13], [13, 17], [15, 22]]
- }
- }
- }, {
- "id": "place_label_village",
- "source": "mapbox",
- "source-layer": "place_label",
- "filter": { "type": "village", "$type": "Point" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-font": "Open Sans Semibold, Arial Unicode MS Bold",
- "text-max-size": 22,
- "text-max-width": 8
- },
- "style": {
- "text-color": "#635644",
- "text-halo-width": 0.3,
- "text-halo-color": "@text_stroke",
- "text-size": {
- "stops": [[8, 8], [11, 10], [13, 14], [15, 16], [16, 20]]
- }
- },
- "style.night": {
- "text-color": "@text_night",
- "text-halo-width": 0.3,
- "text-halo-color": "@text2_stroke_night",
- "text-size": {
- "stops": [[8, 8], [11, 10], [13, 14], [15, 16], [16, 20]]
- }
- }
- }, {
- "id": "place_label_other",
- "source": "mapbox",
- "source-layer": "place_label",
- "filter": { "type": ["hamlet", "suburb", "neighbourhood"], "$type": "Point" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-font": "Open Sans Semibold, Arial Unicode MS Bold",
- "text-max-size": 18,
- "text-max-width": 6
- },
- "style": {
- "text-color": "#7d6c55",
- "text-halo-color": "@text_stroke",
- "text-size": {
- "stops": [[12, 11], [13, 12], [15, 14], [17, 18]]
- }
- },
- "style.night": {
- "text-color": "@text_night",
- "text-halo-color": "@text2_stroke_night",
- "text-halo-width": 0.3,
- "text-size": {
- "stops": [[12, 11], [13, 12], [15, 14], [17, 18]]
- }
- }
- }, {
- "id": "road_label_1",
- "source": "mapbox",
- "source-layer": "road_label",
- "filter": { "class": ["motorway", "main"], "$type": "LineString" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "curve",
- "text-padding": 2,
- "text-font": "Open Sans Regular, Arial Unicode MS Regular",
- "text-max-size": 18,
- "text-max-angle": 0.5
- },
- "style": {
- "text-color": "#585042",
- "text-halo-color": "@land",
- "text-halo-width": 0.6,
- "text-size": "@road_label_1_size"
- },
- "style.night": {
- "text-color": "@text_night",
- "text-halo-color": "@text2_stroke_night",
- "text-halo-width": 0.5,
- "text-size": "@road_label_1_size"
- }
- }, {
- "id": "road_label_2",
- "source": "mapbox",
- "source-layer": "road_label",
- "filter": { "class": ["street", "street_limited"], "$type": "LineString" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "curve",
- "text-padding": 2,
- "text-font": "Open Sans Regular, Arial Unicode MS Regular",
- "text-max-size": 16,
- "text-max-angle": 0.5
- },
- "style": {
- "text-color": "#585042",
- "text-halo-color": "@land",
- "text-halo-width": 0.6,
- "text-size": "@road_label_2_size"
- },
- "style.night": {
- "text-color": "@text_night",
- "text-halo-color": "@text2_stroke_night",
- "text-halo-width": 0.5,
- "text-size": "@road_label_2_size"
- }
- }, {
- "id": "road_label_3",
- "source": "mapbox",
- "source-layer": "road_label",
- "filter": { "class": ["service", "driveway", "path"], "$type": "LineString" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "curve",
- "text-padding": 2,
- "text-font": "Open Sans Regular, Arial Unicode MS Regular",
- "text-max-size": 14,
- "text-max-angle": 0.5
- },
- "style": {
- "text-color": "#585042",
- "text-halo-color": "@land",
- "text-halo-width": 0.6,
- "text-size": "@road_label_3_size"
- },
- "style.night": {
- "text-color": "@text_night",
- "text-halo-color": "@text2_stroke_night",
- "text-halo-width": 0.5,
- "text-size": "@road_label_3_size"
- }
- }, {
- "id": "contour_label",
- "source": "mapbox",
- "source-layer": "contour",
- "filter": { "index": [5, 10], "$type": "LineString" },
- "type": "text",
- "render": {
- "text-path": "curve",
- "text-field": "{ele} m",
- "text-font": "Open Sans Regular, Arial Unicode MS Regular",
- "text-max-size": 10,
- "text-max-angle": 0.5
- },
- "style": {
- "text-color": "@text",
- "text-halo-color": "@land",
- "text-halo-width": 0.3,
- "text-size": 10
- },
- "style.night": {
- "text-color": "@contour_night",
- "text-halo-color": "@land_night",
- "text-halo-width": 0.3,
- "text-size": 10
- }
- }, {
- "id": "water_label",
- "source": "mapbox",
- "source-layer": "water_label",
- "filter": { "$type": "Point" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
- "text-max-size": 12,
- "text-max-width": 8
- },
- "style": {
- "text-color": "@water_dark",
- "text-halo-color": "rgba(255,255,255,0.75)"
- },
- "style.night": {
- "text-color": "@text_water_night",
- "text-halo-color": "@water_night"
- }
- }, {
- "id": "waterway_label",
- "source": "mapbox",
- "source-layer": "waterway_label",
- "filter": { "$type": "LineString" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "curve",
- "text-font": "Open Sans Semibold Italic, Arial Unicode MS Bold",
- "text-max-size": 12,
- "text-max-angle": 0.5
- },
- "style": {
- "text-color": "@water_dark",
- "text-halo-width": 0.4,
- "text-halo-color": "@text_stroke"
- },
- "style.night": {
- "text-color": "@text_water_night",
- "text-halo-color": "@water_night"
- }
- }, {
- "id": "poi",
- "source": "mapbox",
- "source-layer": "poi_label",
- "filter": { "scalerank": [1, 2] },
- "type": "icon",
- "render": {
- "icon-image": "{maki}-12",
- "icon-size": 12
- },
- "style.night": {}
- }, {
- "id": "poi_label_1-2",
- "source": "mapbox",
- "source-layer": "poi_label",
- "filter": { "scalerank": [1, 2], "$type": "Point" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-padding": 2,
- "text-font": "Open Sans Semibold, Arial Unicode MS Bold",
- "text-max-size": 12,
- "text-max-width": 10,
- "text-alignment": "center"
- },
- "style": {
- "text-color": "#444",
- "text-size": "@poi_label_1-2_size",
- "text-halo-color": "@land",
- "text-halo-width": 0.3
- },
- "style.night": {
- "text-color": "#fff",
- "text-size": "@poi_label_1-2_size",
- "text-halo-color": "@text2_stroke_night",
- "text-halo-width": 0.3
- }
- }, {
- "id": "poi_3",
- "source": "mapbox",
- "source-layer": "poi_label",
- "filter": { "scalerank": 3 },
- "type": "icon",
- "render": {
- "icon-image": "{maki}-12",
- "icon-size": 12
- },
- "style": {
- "icon-opacity": {
- "stops": [[15.5, 0], [15.75, 1]]
- }
- },
- "style.night": {
- "icon-opacity": {
- "stops": [[15.5, 0], [15.75, 1]]
- }
- }
- }, {
- "id": "poi_label_3",
- "source": "mapbox",
- "source-layer": "poi_label",
- "filter": { "scalerank": 3, "$type": "Point" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-padding": 2,
- "text-font": "Open Sans Semibold, Arial Unicode MS Bold",
- "text-max-size": 11,
- "text-max-width": 10,
- "text-alignment": "center"
- },
- "style": {
- "text-color": "#444",
- "text-size": "@poi_label_3_size",
- "text-halo-color": "@land",
- "text-halo-width": 0.3,
- "text-opacity": {
- "stops": [[15.5, 0], [15.75, 1]]
- }
- },
- "style.night": {
- "text-color": "#fff",
- "text-size": "@poi_label_3_size",
- "text-halo-color": "@text2_stroke_night",
- "text-halo-width": 0.3,
- "text-opacity": {
- "stops": [[15.5, 0], [15.75, 1]]
- }
- }
- }, {
- "id": "poi_4",
- "source": "mapbox",
- "source-layer": "poi_label",
- "filter": { "scalerank": 4 },
- "type": "icon",
- "render": {
- "icon-image": "{maki}-12",
- "icon-size": 12
- },
- "style": {
- "icon-opacity": {
- "stops": [[17.5, 0], [17.75, 1]]
- }
- },
- "style.night": {
- "icon-opacity": {
- "stops": [[17.5, 0], [17.75, 1]]
- }
- }
- }, {
- "id": "poi_label_4",
- "source": "mapbox",
- "source-layer": "poi_label",
- "filter": { "scalerank": 4, "$type": "Point" },
- "type": "text",
- "render": {
- "text-field": "{name_en}",
- "text-path": "horizontal",
- "text-padding": 2,
- "text-font": "Open Sans Semibold, Arial Unicode MS Bold",
- "text-max-size": 10,
- "text-max-width": 10,
- "text-alignment": "center"
- },
- "style": {
- "text-color": "#444",
- "text-size": 10,
- "text-opacity": {
- "stops": [[17.5, 0], [17.75, 1]]
- },
- "text-halo-color": "@land",
- "text-halo-width": 0.3
- },
- "style.night": {
- "text-color": "#fff",
- "text-size": 10,
- "text-opacity": {
- "stops": [[17.5, 0], [17.75, 1]]
- },
- "text-halo-color": "@text2_stroke_night",
- "text-halo-width": 0.3
- }
- }, {
- "id": "poi_aerodrome",
- "source": "mapbox",
- "source-layer": "poi_label",
- "filter": { "maki": "airport" },
- "type": "icon",
- "render": {
- "icon-image": "{maki}-12",
- "icon-size": 12
- },
- "style": {
- "icon-opacity": {
- "stops": [[12, 0], [12.25, 1]]
- }
- },
- "style.night": {
- "icon-opacity": {
- "stops": [[12, 0], [12.25, 1]]
- }
- }
- }]
-}
diff --git a/common.gypi b/common.gypi
index a38a279ef1..513d8688f0 100644
--- a/common.gypi
+++ b/common.gypi
@@ -7,7 +7,7 @@
'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
'GCC_ENABLE_CPP_RTTI':'YES',
- 'OTHER_CPLUSPLUSFLAGS': [ '-Wall', '-Wextra' ],
+ 'OTHER_CPLUSPLUSFLAGS': [ '-Wall', '-Wextra', '-Wno-variadic-macros' ],
'GCC_WARN_PEDANTIC': 'YES',
'GCC_WARN_UNINITIALIZED_AUTOS': 'YES_AGGRESSIVE'
},
diff --git a/common/glfw_view.cpp b/common/glfw_view.cpp
index 60d95c8b81..f53090a000 100644
--- a/common/glfw_view.cpp
+++ b/common/glfw_view.cpp
@@ -1,5 +1,7 @@
#include "glfw_view.hpp"
+#include <mbgl/util/string.hpp>
+
GLFWView::GLFWView(bool fullscreen) : fullscreen(fullscreen) {
#ifdef NVIDIA
glDiscardFramebufferEXT = (PFNGLDISCARDFRAMEBUFFEREXTPROC)glfwGetProcAddress("glDiscardFramebufferEXT");
@@ -192,9 +194,15 @@ void GLFWView::make_active() {
void GLFWView::swap() {
glfwPostEmptyEvent();
+
+ double lon, lat, zoom;
+ map->getLonLatZoom(lon, lat, zoom);
+ const double bearing = map->getBearing();
+ const std::string title = mbgl::util::sprintf<128>("Mapbox GL – %.2f/%.6f/%.6f/%.1f", zoom, lat, lon, bearing);
+ glfwSetWindowTitle(window, title.c_str());
}
-void GLFWView::notify_map_change(mbgl::MapChange change, mbgl::timestamp delay) {
+void GLFWView::notify_map_change(mbgl::MapChange /*change*/, mbgl::timestamp /*delay*/) {
// no-op
}
diff --git a/common/settings_json.cpp b/common/settings_json.cpp
index bceab50da6..f2f1248aa6 100644
--- a/common/settings_json.cpp
+++ b/common/settings_json.cpp
@@ -18,7 +18,7 @@ void Settings_JSON::load() {
longitude = document[rapidjson::SizeType(0)].GetDouble();
latitude = document[1].GetDouble();
zoom = document[2].GetDouble();
- angle = document[3].GetDouble();
+ bearing = document[3].GetDouble();
debug = document[4].GetBool();
}
}
@@ -32,7 +32,7 @@ void Settings_JSON::save() {
writer.Double(longitude);
writer.Double(latitude);
writer.Double(zoom);
- writer.Double(angle);
+ writer.Double(bearing);
writer.Bool(debug);
writer.EndArray();
}
@@ -41,6 +41,6 @@ void Settings_JSON::clear() {
longitude = 0;
latitude = 0;
zoom = 0;
- angle = 0;
+ bearing = 0;
debug = false;
}
diff --git a/common/settings_json.hpp b/common/settings_json.hpp
index 09f7841c91..25c2179ba0 100644
--- a/common/settings_json.hpp
+++ b/common/settings_json.hpp
@@ -14,7 +14,7 @@ public:
double longitude = 0;
double latitude = 0;
double zoom = 0;
- double angle = 0;
+ double bearing = 0;
bool debug = false;
};
diff --git a/common/settings_nsuserdefaults.hpp b/common/settings_nsuserdefaults.hpp
index dcc6ab46b9..3533e3da35 100644
--- a/common/settings_nsuserdefaults.hpp
+++ b/common/settings_nsuserdefaults.hpp
@@ -14,7 +14,7 @@ public:
double longitude = 0;
double latitude = 0;
double zoom = 0;
- double angle = 0;
+ double bearing = 0;
bool debug = false;
};
diff --git a/common/settings_nsuserdefaults.mm b/common/settings_nsuserdefaults.mm
index 24571677f4..dfc601bddb 100644
--- a/common/settings_nsuserdefaults.mm
+++ b/common/settings_nsuserdefaults.mm
@@ -9,7 +9,7 @@ Settings_NSUserDefaults::Settings_NSUserDefaults()
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"longitude" : @(longitude),
@"latitude" : @(latitude),
@"zoom" : @(zoom),
- @"angle" : @(angle),
+ @"bearing" : @(bearing),
@"debug" : @(debug) }];
load();
}
@@ -21,7 +21,7 @@ void Settings_NSUserDefaults::load()
longitude = [settings[@"longitude"] doubleValue];
latitude = [settings[@"latitude"] doubleValue];
zoom = [settings[@"zoom"] doubleValue];
- angle = [settings[@"angle"] doubleValue];
+ bearing = [settings[@"bearing"] doubleValue];
debug = [settings[@"debug"] boolValue];
}
@@ -29,8 +29,8 @@ void Settings_NSUserDefaults::save()
{
[[NSUserDefaults standardUserDefaults] setValuesForKeysWithDictionary:@{ @"longitude" : @(longitude),
@"latitude" : @(latitude),
- @"zoom" : @(zoom),
- @"angle" : @(angle),
+ @"zoom" : @(zoom),
+ @"bearing" : @(bearing),
@"debug" : @(debug) }];
[[NSUserDefaults standardUserDefaults] synchronize];
}
diff --git a/include/mbgl/geometry/icon_buffer.hpp b/include/mbgl/geometry/icon_buffer.hpp
index 346b3b5f06..e7e5f40355 100644
--- a/include/mbgl/geometry/icon_buffer.hpp
+++ b/include/mbgl/geometry/icon_buffer.hpp
@@ -3,16 +3,18 @@
#include "buffer.hpp"
+#include <array>
+
namespace mbgl {
class IconVertexBuffer : public Buffer<
- 4 + // int16 x/y coordinates per vertex (== 4 bytes)
- 4 // uint16 x/y coordinates of icon in sprite (== 4 bytes)
+ 20
> {
public:
- typedef int16_t vertex_type;
+ static const double angleFactor;
+
+ size_t add(int16_t x, int16_t y, float ox, float oy, int16_t tx, int16_t ty, float angle, float minzoom, std::array<float, 2> range, float maxzoom, float labelminzoom);
- void add(vertex_type x, vertex_type y, uint16_t tx, uint16_t ty);
};
}
diff --git a/include/mbgl/geometry/interpolate.hpp b/include/mbgl/geometry/interpolate.hpp
index cebbcc7028..998cba31cd 100644
--- a/include/mbgl/geometry/interpolate.hpp
+++ b/include/mbgl/geometry/interpolate.hpp
@@ -7,7 +7,7 @@
namespace mbgl {
Anchors interpolate(const std::vector<Coordinate> &vertices, float spacing,
- float minScale = 0.0f, int start = 0);
+ float minScale, float maxScale, float tilePixelRatio, int start = 0);
}
#endif
diff --git a/include/mbgl/geometry/sprite_atlas.hpp b/include/mbgl/geometry/sprite_atlas.hpp
index 4b55540cc8..dc2378c2fb 100644
--- a/include/mbgl/geometry/sprite_atlas.hpp
+++ b/include/mbgl/geometry/sprite_atlas.hpp
@@ -26,18 +26,21 @@ public:
// Changes the pixel ratio.
bool resize(float newRatio);
- // Update uninitialized sprites in this atlas from the given sprite.
+ // Update uninitialized (= outdated) sprites in this atlas from the given sprite.
void update(const Sprite &sprite);
- // Returns the coordinates of a square icon. The getter also *creates* new square icons in the
- // atlas if they don't exist, but they'll be default-initialized with a a black circle.
- Rect<dimension> getIcon(int size, const std::string &name);
-
// Returns the coordinates of an image that is sourced from the sprite image.
- // This getter does not create images, as the dimension of the texture us unknown if the
- // sprite is not yet loaded. Instead, it returns a 0/0/0/0 rect.
+ // This getter attempts to read the image from the sprite if it is already loaded.
+ // In that case, it copies it into the sprite atlas and returns the dimensions.
+ // Otherwise, it returns a 0/0/0/0 rect.
Rect<dimension> getImage(const std::string &name, const Sprite &sprite);
+ // Returns the coordinates of an image that is sourced from the sprite image.
+ // This getter waits until the sprite image was loaded, copies it into the sprite
+ // image and returns the dimensions.
+ // NEVER CALL THIS FUNCTION FROM THE RENDER THREAD! it is blocking.
+ Rect<dimension> waitForImage(const std::string &name, const Sprite &sprite);
+
// Binds the image buffer of this sprite atlas to the GPU, and uploads data if it is out
// of date.
void bind(bool linear = false);
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
index 774e5e1292..be01b456cc 100644
--- a/include/mbgl/map/map.hpp
+++ b/include/mbgl/map/map.hpp
@@ -1,26 +1,34 @@
-
#ifndef MBGL_MAP_MAP
#define MBGL_MAP_MAP
-#include <uv.h>
-
-#include <mbgl/map/view.hpp>
#include <mbgl/map/transform.hpp>
-#include <mbgl/style/style.hpp>
-#include <mbgl/geometry/glyph_atlas.hpp>
-#include <mbgl/text/glyph_store.hpp>
#include <mbgl/renderer/painter.hpp>
+
#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/texturepool.hpp>
+#include <mbgl/util/time.hpp>
+#include <mbgl/util/uv.hpp>
#include <cstdint>
-#include <string>
-#include <map>
+#include <atomic>
+#include <iosfwd>
+#include <memory>
+#include <set>
+#include <vector>
namespace mbgl {
-class Source;
+class GlyphAtlas;
+class GlyphStore;
+class LayerDescription;
class SpriteAtlas;
+class Sprite;
+class Style;
+class StyleLayer;
+class StyleLayerGroup;
+class StyleSource;
+class Texturepool;
+class FileSource;
+class View;
class Map : private util::noncopyable {
public:
@@ -57,7 +65,8 @@ public:
void toggleClass(const std::string &name);
const std::vector<std::string> &getAppliedClasses() const;
void setDefaultTransitionDuration(uint64_t duration_milliseconds = 0);
- void setStyleJSON(std::string newStyleJSON);
+ void setStyleURL(const std::string &url);
+ void setStyleJSON(std::string newStyleJSON, const std::string &base = "");
std::string getStyleJSON() const;
void setAccessToken(std::string access_token);
std::string getAccessToken() const;
@@ -89,9 +98,9 @@ public:
// Rotation
void rotateBy(double sx, double sy, double ex, double ey, double duration = 0);
- void setAngle(double angle, double duration = 0);
- void setAngle(double angle, double cx, double cy);
- double getAngle() const;
+ void setBearing(double degrees, double duration = 0);
+ void setBearing(double degrees, double cx, double cy);
+ double getBearing() const;
void resetNorth();
void startRotating();
void stopRotating();
@@ -104,10 +113,12 @@ public:
public:
inline const TransformState &getState() const { return state; }
- inline std::shared_ptr<const Style> getStyle() const { return style; }
+ inline std::shared_ptr<FileSource> getFileSource() const { return fileSource; }
+ inline std::shared_ptr<Style> getStyle() const { return style; }
inline std::shared_ptr<GlyphAtlas> getGlyphAtlas() { return glyphAtlas; }
inline std::shared_ptr<GlyphStore> getGlyphStore() { return glyphStore; }
inline std::shared_ptr<SpriteAtlas> getSpriteAtlas() { return spriteAtlas; }
+ std::shared_ptr<Sprite> getSprite();
inline std::shared_ptr<Texturepool> getTexturepool() { return texturepool; }
inline std::shared_ptr<uv::loop> getLoop() { return loop; }
inline timestamp getAnimationTime() const { return animationTime; }
@@ -143,6 +154,14 @@ private:
void renderLayer(std::shared_ptr<StyleLayer> layer_desc, RenderPass pass);
private:
+ bool async = false;
+ std::shared_ptr<uv::loop> loop;
+ uv_thread_t thread;
+ uv_async_t *async_terminate = nullptr;
+ uv_async_t *async_render = nullptr;
+ uv_async_t *async_cleanup = nullptr;
+
+private:
// If cleared, the next time the render thread attempts to render the map, it will *actually*
// render the map.
std::atomic_flag is_clean = ATOMIC_FLAG_INIT;
@@ -162,10 +181,13 @@ private:
Transform transform;
TransformState state;
+ std::shared_ptr<FileSource> fileSource;
+
std::shared_ptr<Style> style;
std::shared_ptr<GlyphAtlas> glyphAtlas;
std::shared_ptr<GlyphStore> glyphStore;
std::shared_ptr<SpriteAtlas> spriteAtlas;
+ std::shared_ptr<Sprite> sprite;
std::shared_ptr<Texturepool> texturepool;
Painter painter;
@@ -180,13 +202,6 @@ private:
std::set<std::shared_ptr<StyleSource>> activeSources;
-private:
- bool async = false;
- std::shared_ptr<uv::loop> loop;
- uv_thread_t thread;
- uv_async_t *async_terminate = nullptr;
- uv_async_t *async_render = nullptr;
- uv_async_t *async_cleanup = nullptr;
};
}
diff --git a/include/mbgl/map/raster_tile_data.hpp b/include/mbgl/map/raster_tile_data.hpp
index 976faa91bc..bf8691454f 100644
--- a/include/mbgl/map/raster_tile_data.hpp
+++ b/include/mbgl/map/raster_tile_data.hpp
@@ -1,18 +1,24 @@
#ifndef MBGL_MAP_RASTER_TILE_DATA
#define MBGL_MAP_RASTER_TILE_DATA
+#include <mbgl/map/tile.hpp>
#include <mbgl/map/tile_data.hpp>
-
#include <mbgl/renderer/raster_bucket.hpp>
+#include <memory>
namespace mbgl {
+class Map;
+class Painter;
+class SourceInfo;
+class StyleLayer;
+
class RasterTileData : public TileData {
friend class TileParser;
public:
- RasterTileData(Tile::ID id, Map &map, const std::string url);
+ RasterTileData(Tile::ID id, Map &map, const SourceInfo &source);
~RasterTileData();
virtual void parse();
diff --git a/include/mbgl/map/source.hpp b/include/mbgl/map/source.hpp
index be5fad3af8..c3f2d4fe8b 100644
--- a/include/mbgl/map/source.hpp
+++ b/include/mbgl/map/source.hpp
@@ -3,30 +3,29 @@
#include <mbgl/map/tile.hpp>
#include <mbgl/map/tile_data.hpp>
+#include <mbgl/style/style_source.hpp>
+
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/time.hpp>
-#include <mbgl/style/style_source.hpp>
-#include <mbgl/style/types.hpp>
+#include <mbgl/util/mat4.hpp>
-#include <list>
+#include <cstdint>
#include <forward_list>
-#include <memory>
-#include <vector>
-#include <string>
+#include <iosfwd>
#include <map>
-#include <set>
+#include <memory>
namespace mbgl {
+class Map;
+class Painter;
+class StyleLayer;
class TransformState;
-class Texturepool;
+struct box;
class Source : public std::enable_shared_from_this<Source>, private util::noncopyable {
public:
- Source(StyleSource style_source, const std::string &access_token = "");
- Source(SourceType type = SourceType::Vector, const std::string &url = "",
- uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 22,
- const std::string &access_token = "");
+ Source(SourceInfo info, const std::string &access_token = "");
bool update(Map &map);
void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
@@ -41,11 +40,7 @@ public:
static std::string normalizeSourceURL(const std::string &url, const std::string &access_token);
public:
- const SourceType type;
- const std::string url;
- const uint32_t tile_size;
- const int32_t min_zoom;
- const int32_t max_zoom;
+ const SourceInfo info;
private:
bool findLoadedChildren(const Tile::ID& id, int32_t maxCoveringZoom, std::forward_list<Tile::ID>& retain);
diff --git a/include/mbgl/map/sprite.hpp b/include/mbgl/map/sprite.hpp
index 22126eb6a1..967f1d6614 100644
--- a/include/mbgl/map/sprite.hpp
+++ b/include/mbgl/map/sprite.hpp
@@ -1,18 +1,20 @@
#ifndef MBGL_STYLE_SPRITE
#define MBGL_STYLE_SPRITE
-#include <mbgl/util/raster.hpp>
-#include <mbgl/util/vec.hpp>
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/noncopyable.hpp>
-#include <string>
-#include <mutex>
-#include <memory>
+#include <cstdint>
#include <atomic>
+#include <iosfwd>
+#include <memory>
+#include <string>
#include <unordered_map>
+#include <future>
namespace mbgl {
-class Map;
+class FileSource;
class SpritePosition {
public:
@@ -28,36 +30,47 @@ public:
uint8_t pixelRatio = 1;
};
-class Sprite : public std::enable_shared_from_this<Sprite> {
-public:
- Sprite(Map &map, float pixelRatio = 1);
+class Sprite : public std::enable_shared_from_this<Sprite>, private util::noncopyable {
+private:
+ struct Key {};
+ void load(const std::shared_ptr<FileSource> &fileSource);
- void load(const std::string& base_url);
+public:
+ Sprite(const Key &, const std::string& base_url, float pixelRatio);
+ static std::shared_ptr<Sprite> Create(const std::string& base_url, float pixelRatio, const std::shared_ptr<FileSource> &fileSource);
const SpritePosition &getSpritePosition(const std::string& name) const;
+ void waitUntilLoaded() const;
bool isLoaded() const;
+ operator bool() const;
+
+private:
+ const bool valid;
+
public:
const float pixelRatio;
+ const std::string spriteURL;
+ const std::string jsonURL;
std::unique_ptr<util::Image> raster;
private:
- void asyncParseJSON();
- void asyncParseImage();
-
- static void parseJSON(std::shared_ptr<Sprite> &sprite);
- static void parseImage(std::shared_ptr<Sprite> &sprite);
- static void complete(std::shared_ptr<Sprite> &sprite);
+ void parseJSON();
+ void parseImage();
+ void complete();
private:
- Map &map;
- std::string url;
std::string body;
std::string image;
- std::atomic<bool> loaded;
+ std::atomic<bool> loadedImage;
+ std::atomic<bool> loadedJSON;
std::unordered_map<std::string, SpritePosition> pos;
const SpritePosition empty;
+
+ std::promise<void> promise;
+ std::future<void> future;
+
};
}
diff --git a/include/mbgl/map/tile.hpp b/include/mbgl/map/tile.hpp
index 7e868afad9..9cf5ff5341 100644
--- a/include/mbgl/map/tile.hpp
+++ b/include/mbgl/map/tile.hpp
@@ -1,15 +1,17 @@
#ifndef MBGL_MAP_TILE
#define MBGL_MAP_TILE
-#include <mbgl/util/vec.hpp>
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <cstdint>
-#include <forward_list>
-#include <string>
#include <bitset>
+#include <cmath>
+#include <cstdint>
+#include <forward_list>
+#include <iosfwd>
#include <memory>
+#include <string>
namespace mbgl {
diff --git a/include/mbgl/map/tile_data.hpp b/include/mbgl/map/tile_data.hpp
index a4b73c339f..c349ea2bae 100644
--- a/include/mbgl/map/tile_data.hpp
+++ b/include/mbgl/map/tile_data.hpp
@@ -2,22 +2,26 @@
#define MBGL_MAP_TILE_DATA
#include <mbgl/map/tile.hpp>
-#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/platform/platform.hpp>
-#include <mbgl/geometry/vao.hpp>
#include <mbgl/renderer/debug_bucket.hpp>
+#include <mbgl/geometry/debug_font_buffer.hpp>
+
+#include <mbgl/util/noncopyable.hpp>
-#include <cstdint>
-#include <string>
-#include <memory>
#include <atomic>
+#include <exception>
+#include <iosfwd>
+#include <memory>
+#include <string>
namespace mbgl {
class Map;
class Painter;
+class SourceInfo;
class StyleLayer;
+namespace platform { class Request; }
+
class TileData : public std::enable_shared_from_this<TileData>,
private util::noncopyable {
public:
@@ -37,7 +41,7 @@ public:
};
public:
- TileData(Tile::ID id, Map &map, const std::string url);
+ TileData(Tile::ID id, Map &map, const SourceInfo &source);
~TileData();
void request();
@@ -60,8 +64,13 @@ public:
protected:
Map &map;
+public:
+ const SourceInfo &source;
+
// Request-related information.
const std::string url;
+
+protected:
std::weak_ptr<platform::Request> req;
std::string data;
diff --git a/include/mbgl/map/tile_parser.hpp b/include/mbgl/map/tile_parser.hpp
index 14e00946b8..9aa0f4dc66 100644
--- a/include/mbgl/map/tile_parser.hpp
+++ b/include/mbgl/map/tile_parser.hpp
@@ -2,27 +2,30 @@
#define MBGL_MAP_TILE_PARSER
#include <mbgl/map/vector_tile.hpp>
-#include <mbgl/text/placement.hpp>
-#include <mbgl/text/glyph_store.hpp>
-#include <mbgl/text/glyph.hpp>
-#include <mbgl/util/utf.hpp>
#include <mbgl/style/filter_expression.hpp>
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/text/collision.hpp>
+
+#include <cstdint>
+#include <iosfwd>
+#include <memory>
+#include <string>
namespace mbgl {
-class Style;
+class Bucket;
+class FontStack;
class GlyphAtlas;
class GlyphStore;
class SpriteAtlas;
-class VectorTileData;
-class StyleLayer;
-class StyleLayerGroup;
+class Sprite;
+class Style;
class StyleBucket;
class StyleBucketFill;
class StyleBucketLine;
-class StyleBucketIcon;
-
-class Bucket;
+class StyleBucketSymbol;
+class StyleLayerGroup;
+class VectorTileData;
class TileParser {
public:
@@ -30,25 +33,22 @@ public:
const std::shared_ptr<const Style> &style,
const std::shared_ptr<GlyphAtlas> &glyphAtlas,
const std::shared_ptr<GlyphStore> &glyphStore,
- const std::shared_ptr<SpriteAtlas> &spriteAtlas);
+ const std::shared_ptr<SpriteAtlas> &spriteAtlas,
+ const std::shared_ptr<Sprite> &sprite);
public:
void parse();
private:
bool obsolete() const;
- void parseGlyphs();
void parseStyleLayers(std::shared_ptr<StyleLayerGroup> group);
- void addGlyph(uint64_t tileid, const std::string stackname, const std::u32string &string, const FontStack &fontStack, GlyphAtlas &glyphAtlas, GlyphPositions &face);
std::unique_ptr<Bucket> createBucket(std::shared_ptr<StyleBucket> bucket_desc);
std::unique_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill);
std::unique_ptr<Bucket> createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line);
- std::unique_ptr<Bucket> createIconBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketIcon &icon);
- std::unique_ptr<Bucket> createTextBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketText &text);
+ std::unique_ptr<Bucket> createSymbolBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketSymbol &symbol);
- template <class Bucket> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter);
- template <class Bucket, typename ...Args> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter, Args&& ...args);
+ template <class Bucket> void addBucketGeometries(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter);
private:
const VectorTile vector_data;
@@ -59,8 +59,9 @@ private:
std::shared_ptr<GlyphAtlas> glyphAtlas;
std::shared_ptr<GlyphStore> glyphStore;
std::shared_ptr<SpriteAtlas> spriteAtlas;
+ std::shared_ptr<Sprite> sprite;
- Placement placement;
+ Collision collision;
};
}
diff --git a/include/mbgl/map/transform.hpp b/include/mbgl/map/transform.hpp
index 61bef76563..df7839ea96 100644
--- a/include/mbgl/map/transform.hpp
+++ b/include/mbgl/map/transform.hpp
@@ -1,20 +1,23 @@
#ifndef MBGL_MAP_TRANSFORM
#define MBGL_MAP_TRANSFORM
-#include <mbgl/util/transition.hpp>
+#include <mbgl/util/time.hpp>
+#include <mbgl/map/transform_state.hpp>
+
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/uv.hpp>
-#include "view.hpp"
-#include "transform_state.hpp"
-
+#include <cstdint>
+#include <cmath>
#include <forward_list>
+#include <memory>
namespace mbgl {
-struct box;
+class View;
+namespace util { class transition; }
- class Transform : private util::noncopyable {
+class Transform : private util::noncopyable {
public:
Transform(View &view);
@@ -93,7 +96,7 @@ private:
const double max_scale = std::pow(2, 18);
// cache values for spherical mercator math
- double zc, Bc, Cc;
+ double Bc, Cc;
std::forward_list<std::shared_ptr<util::transition>> transitions;
std::shared_ptr<util::transition> scale_timeout;
diff --git a/include/mbgl/map/transform_state.hpp b/include/mbgl/map/transform_state.hpp
index 85dd2eb87d..5b3b7d3755 100644
--- a/include/mbgl/map/transform_state.hpp
+++ b/include/mbgl/map/transform_state.hpp
@@ -1,15 +1,17 @@
#ifndef MBGL_MAP_TRANSFORM_STATE
#define MBGL_MAP_TRANSFORM_STATE
-#include <mbgl/util/mat4.hpp>
#include <mbgl/map/tile.hpp>
+#include <mbgl/util/mat4.hpp>
+#include <mbgl/util/vec.hpp>
+
#include <cstdint>
+#include <array>
+#include <limits>
namespace mbgl {
-class Transform;
-
class TransformState {
friend class Transform;
diff --git a/include/mbgl/map/vector_tile.hpp b/include/mbgl/map/vector_tile.hpp
index 77e379865f..1bbe645307 100644
--- a/include/mbgl/map/vector_tile.hpp
+++ b/include/mbgl/map/vector_tile.hpp
@@ -1,24 +1,22 @@
#ifndef MBGL_MAP_VECTOR_TILE
#define MBGL_MAP_VECTOR_TILE
-#include <mbgl/util/pbf.hpp>
-#include <mbgl/util/vec.hpp>
+#include <mbgl/style/filter_expression.hpp>
#include <mbgl/style/value.hpp>
#include <mbgl/text/glyph.hpp>
-#include <mbgl/style/filter_expression.hpp>
-#include <vector>
+#include <mbgl/util/pbf.hpp>
+
+#include <cstdint>
+#include <iosfwd>
#include <map>
+#include <string>
#include <unordered_map>
-#include <set>
-#include <limits>
+#include <vector>
namespace mbgl {
-class BucketDescription;
class VectorTileLayer;
-struct pbf;
-
enum class FeatureType {
Unknown = 0,
Point = 1,
@@ -88,7 +86,7 @@ private:
const FilterExpression& filterExpression;
};
-std::ostream& operator<<(std::ostream&, const GlyphPlacement& placement);
+std::ostream& operator<<(std::ostream&, const PositionedGlyph& placement);
class VectorTileLayer {
public:
diff --git a/include/mbgl/map/vector_tile_data.hpp b/include/mbgl/map/vector_tile_data.hpp
index dd55e8dae1..edad228999 100644
--- a/include/mbgl/map/vector_tile_data.hpp
+++ b/include/mbgl/map/vector_tile_data.hpp
@@ -1,29 +1,32 @@
#ifndef MBGL_MAP_VECTOR_TILE_DATA
#define MBGL_MAP_VECTOR_TILE_DATA
+#include <mbgl/map/tile.hpp>
#include <mbgl/map/tile_data.hpp>
-
-
-#include <mbgl/renderer/bucket.hpp>
-
-#include <mbgl/geometry/vertex_buffer.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/geometry/fill_buffer.hpp>
-#include <mbgl/geometry/line_buffer.hpp>
#include <mbgl/geometry/icon_buffer.hpp>
+#include <mbgl/geometry/line_buffer.hpp>
#include <mbgl/geometry/text_buffer.hpp>
-#include <mbgl/map/tile_parser.hpp>
+#include <iosfwd>
+#include <memory>
#include <unordered_map>
namespace mbgl {
+class Bucket;
+class Map;
+class Painter;
+class SourceInfo;
+class StyleLayer;
+class TileParser;
class VectorTileData : public TileData {
friend class TileParser;
public:
- VectorTileData(Tile::ID id, Map &map, const std::string url);
+ VectorTileData(Tile::ID id, Map &map, const SourceInfo &source);
~VectorTileData();
virtual void beforeParse();
@@ -48,6 +51,9 @@ protected:
std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets;
std::unique_ptr<TileParser> parser;
+
+public:
+ const float depth;
};
}
diff --git a/include/mbgl/platform/event.hpp b/include/mbgl/platform/event.hpp
index b55c721c99..01a23aa255 100644
--- a/include/mbgl/platform/event.hpp
+++ b/include/mbgl/platform/event.hpp
@@ -68,6 +68,7 @@ constexpr EventSeverity disabledEventSeverities[] = {
constexpr Event disabledEvents[] = {
+ Event(-1) // Avoid zero size array
};
constexpr EventPermutation disabledEventPermutations[] = {
diff --git a/include/mbgl/renderer/icon_bucket.hpp b/include/mbgl/renderer/icon_bucket.hpp
deleted file mode 100644
index e3b311332d..0000000000
--- a/include/mbgl/renderer/icon_bucket.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef MBGL_RENDERER_ICONBUCKET
-#define MBGL_RENDERER_ICONBUCKET
-
-#include <mbgl/renderer/bucket.hpp>
-#include <mbgl/geometry/elements_buffer.hpp>
-#include <mbgl/geometry/icon_buffer.hpp>
-#include <mbgl/style/style_bucket.hpp>
-
-#include <vector>
-#include <memory>
-
-#ifndef BUFFER_OFFSET
-#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
-#endif
-
-namespace mbgl {
-
-class Style;
-class IconVertexBuffer;
-class BucketDescription;
-class IconShader;
-class DotShader;
-class SpriteAtlas;
-class VectorTileFeature;
-
-class IconBucket : public Bucket {
-public:
- IconBucket(IconVertexBuffer& vertexBuffer,
- const StyleBucketIcon& properties);
-
- virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
- virtual bool hasData() const;
-
- void addFeature(const VectorTileFeature &feature, SpriteAtlas &sprite_atlas);
-
- void drawIcons(IconShader& shader);
- void drawIcons(DotShader& shader);
-
-public:
- const StyleBucketIcon &properties;
-
-private:
-
- IconVertexBuffer& vertexBuffer;
- VertexArrayObject array;
-
- const size_t vertex_start;
- size_t vertex_end = 0;
-};
-
-}
-
-#endif
diff --git a/include/mbgl/renderer/painter.hpp b/include/mbgl/renderer/painter.hpp
index 9868b5d9da..b4023de167 100644
--- a/include/mbgl/renderer/painter.hpp
+++ b/include/mbgl/renderer/painter.hpp
@@ -38,8 +38,7 @@ class StyleSource;
class FillBucket;
class LineBucket;
-class IconBucket;
-class TextBucket;
+class SymbolBucket;
class RasterBucket;
struct FillProperties;
@@ -62,6 +61,8 @@ public:
void cleanup();
+ // Renders the backdrop of the OpenGL view. This also paints in areas where we don't have any
+ // tiles whatsoever.
void clear();
// Updates the default matrices to the current viewport dimensions.
@@ -73,10 +74,6 @@ public:
// Renders debug information for a tile.
void renderTileDebug(const Tile& tile);
- // Renders the backdrop of the OpenGL view. This also paints in areas where we don't have any
- // tiles whatsoever.
- void renderMatte();
-
// Renders the red debug frame around a tile, visualizing its perimeter.
void renderDebugFrame();
@@ -85,8 +82,7 @@ public:
void renderFill(FillBucket& bucket, const FillProperties& properties, const Tile::ID& id, const mat4 &mat);
void renderFill(FillBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
void renderLine(LineBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
- void renderIcon(IconBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
- void renderText(TextBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
+ void renderSymbol(SymbolBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
void renderRaster(RasterBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
void preparePrerender(PrerenderedTexture &texture);
@@ -121,7 +117,7 @@ public:
bool needsAnimation() const;
private:
void setupShaders();
- const mat4 &translatedMatrix(const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchorType anchor = TranslateAnchorType::Default);
+ const mat4 &translatedMatrix(const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchorType anchor = TranslateAnchorType::Map);
void prepareTile(const Tile& tile);
diff --git a/include/mbgl/renderer/symbol_bucket.hpp b/include/mbgl/renderer/symbol_bucket.hpp
new file mode 100644
index 0000000000..c003230cae
--- /dev/null
+++ b/include/mbgl/renderer/symbol_bucket.hpp
@@ -0,0 +1,109 @@
+#ifndef MBGL_RENDERER_SYMBOLBUCKET
+#define MBGL_RENDERER_SYMBOLBUCKET
+
+#include "bucket.hpp"
+#include <mbgl/geometry/vao.hpp>
+#include <mbgl/geometry/elements_buffer.hpp>
+#include <mbgl/geometry/text_buffer.hpp>
+#include <mbgl/geometry/icon_buffer.hpp>
+#include <mbgl/map/vector_tile.hpp>
+#include <mbgl/text/types.hpp>
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
+#include <memory>
+#include <map>
+#include <vector>
+
+namespace mbgl {
+
+class Style;
+class TextShader;
+class IconShader;
+class DotShader;
+class Collision;
+class SpriteAtlas;
+class Sprite;
+class GlyphAtlas;
+class GlyphStore;
+class FontStack;
+
+class SymbolFeature {
+public:
+ pbf geometry;
+ std::u32string label;
+ std::string sprite;
+};
+
+
+class Symbol {
+public:
+ vec2<float> tl, tr, bl, br;
+ Rect<uint16_t> tex;
+ float angle;
+ float minScale = 0.0f;
+ float maxScale = std::numeric_limits<float>::infinity();
+ CollisionAnchor anchor;
+};
+
+typedef std::vector<Symbol> Symbols;
+
+
+class SymbolBucket : public Bucket {
+public:
+ SymbolBucket(const StyleBucketSymbol &properties, Collision &collision);
+
+ virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID &id);
+ virtual bool hasData() const;
+ virtual bool hasTextData() const;
+ virtual bool hasIconData() const;
+
+ void addFeatures(const VectorTileLayer &layer, const FilterExpression &filter,
+ const Tile::ID &id, SpriteAtlas &spriteAtlas, Sprite &sprite,
+ GlyphAtlas &glyphAtlas, GlyphStore &glyphStore);
+
+ void addGlyphs(const PlacedGlyphs &glyphs, float placementZoom, PlacementRange placementRange,
+ float zoom);
+
+ void drawGlyphs(TextShader &shader);
+ void drawIcons(IconShader& shader);
+
+private:
+
+ std::vector<SymbolFeature> processFeatures(const VectorTileLayer &layer, const FilterExpression &filter, GlyphStore &glyphStore, const Sprite &sprite);
+
+
+ void addFeature(const pbf &geom_pbf, const Shaping &shaping, const GlyphPositions &face, const Rect<uint16_t> &image);
+ void addFeature(const std::vector<Coordinate> &line, const Shaping &shaping, const GlyphPositions &face, const Rect<uint16_t> &image);
+
+
+ // Adds placed items to the buffer.
+ template <typename Buffer>
+ void addSymbols(Buffer &buffer, const PlacedGlyphs &symbols, float scale, PlacementRange placementRange);
+
+ // Adds glyphs to the glyph atlas so that they have a left/top/width/height coordinates associated to them that we can use for writing to a buffer.
+ void addGlyphsToAtlas(uint64_t tileid, const std::string stackname, const std::u32string &string,
+ const FontStack &fontStack, GlyphAtlas &glyphAtlas, GlyphPositions &face);
+
+public:
+ const StyleBucketSymbol &properties;
+
+private:
+ Collision &collision;
+
+ struct {
+ TextVertexBuffer vertices;
+ TriangleElementsBuffer triangles;
+ std::vector<ElementGroup> groups;
+ } text;
+
+ struct {
+ IconVertexBuffer vertices;
+ TriangleElementsBuffer triangles;
+ std::vector<ElementGroup> groups;
+ } icon;
+
+};
+}
+
+#endif
diff --git a/include/mbgl/renderer/text_bucket.hpp b/include/mbgl/renderer/text_bucket.hpp
deleted file mode 100644
index cb4b8f2cda..0000000000
--- a/include/mbgl/renderer/text_bucket.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef MBGL_RENDERER_TEXTBUCKET
-#define MBGL_RENDERER_TEXTBUCKET
-
-#include "bucket.hpp"
-#include <mbgl/geometry/vao.hpp>
-#include <mbgl/geometry/elements_buffer.hpp>
-#include <mbgl/map/vector_tile.hpp>
-#include <mbgl/text/types.hpp>
-#include <mbgl/text/glyph.hpp>
-#include <mbgl/style/style_bucket.hpp>
-
-#include <memory>
-#include <map>
-#include <vector>
-
-namespace mbgl {
-
-class Style;
-class TextVertexBuffer;
-class TriangleElementsBuffer;
-class TextShader;
-class Placement;
-struct pbf;
-
-class TextBucket : public Bucket {
- typedef ElementGroup triangle_group_type;
-
-public:
- TextBucket(
- TextVertexBuffer &vertexBuffer,
- TriangleElementsBuffer &triangleElementsBuffer,
- const StyleBucketText &properties, Placement &placement);
-
- virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID &id);
- virtual bool hasData() const;
-
- void addGlyphs(const PlacedGlyphs &glyphs, float placementZoom,
- PlacementRange placementRange, float zoom);
-
- void addFeature(const pbf &geometry,
- const GlyphPositions &face,
- const Shaping &shaping);
-
- void drawGlyphs(TextShader &shader);
-
-public:
- const StyleBucketText &properties;
-
-private:
- TextVertexBuffer& vertexBuffer;
- TriangleElementsBuffer& triangleElementsBuffer;
- Placement &placement;
-
- const size_t vertex_start;
- const size_t triangle_elements_start;
-
- std::vector<triangle_group_type> triangleGroups;
-};
-}
-
-#endif
diff --git a/include/mbgl/shader/icon_shader.hpp b/include/mbgl/shader/icon_shader.hpp
index b97b3c2be3..54869fe48d 100644
--- a/include/mbgl/shader/icon_shader.hpp
+++ b/include/mbgl/shader/icon_shader.hpp
@@ -11,30 +11,57 @@ public:
void bind(char *offset);
- void setImage(int32_t image);
- void setColor(const std::array<float, 4>& color);
- void setDimension(const std::array<float, 2>& dimension);
- void setSize(float size);
- void setRatio(float ratio);
+ void setExtrudeMatrix(const std::array<float, 16>& exmatrix);
+ void setAngle(float angle);
+ void setZoom(float zoom);
+ void setFlip(float flip);
+ void setFadeDist(float fadedist);
+ void setMinFadeZoom(float minfadezoom);
+ void setMaxFadeZoom(float maxfadezoom);
+ void setFadeZoom(float fadezoom);
+ void setOpacity(float opacity);
+ void setTextureSize(const std::array<float, 2> &texsize);
private:
int32_t a_pos = -1;
+ int32_t a_offset = -1;
int32_t a_tex = -1;
+ int32_t a_angle = -1;
+ int32_t a_minzoom = -1;
+ int32_t a_maxzoom = -1;
+ int32_t a_rangeend = -1;
+ int32_t a_rangestart = -1;
+ int32_t a_labelminzoom = -1;
- int32_t image = -1;
- int32_t u_image = -1;
+ std::array<float, 16> exmatrix = {{}};
+ int32_t u_exmatrix = -1;
- std::array<float, 4> color = {{}};
- int32_t u_color = -1;
+ float angle = 0;
+ int32_t u_angle = -1;
- std::array<float, 2> dimension = {{}};
- int32_t u_dimension = -1;
+ float zoom = 0;
+ int32_t u_zoom = -1;
- float size = 0;
- int32_t u_size = -1;
+ float flip = 0;
+ int32_t u_flip = -1;
- float ratio = 0;
- int32_t u_ratio = -1;
+ float fadedist = 0;
+ int32_t u_fadedist = -1;
+
+ float minfadezoom = 0;
+ int32_t u_minfadezoom = -1;
+
+ float maxfadezoom = 0;
+ int32_t u_maxfadezoom = -1;
+
+ float fadezoom = 0;
+ int32_t u_fadezoom = -1;
+
+ float opacity = 0;
+ int32_t u_opacity = -1;
+
+ std::array<float, 2> texsize = {{}};
+ int32_t u_texsize = -1;
};
}
diff --git a/include/mbgl/shader/line_shader.hpp b/include/mbgl/shader/line_shader.hpp
index 38efe0b71f..c476b5c4c6 100644
--- a/include/mbgl/shader/line_shader.hpp
+++ b/include/mbgl/shader/line_shader.hpp
@@ -16,6 +16,7 @@ public:
void setLineWidth(const std::array<float, 2>& linewidth);
void setRatio(float ratio);
void setDashArray(const std::array<float, 2>& dasharray);
+ void setBlur(float blur);
void setDebug(float debug);
private:
@@ -37,6 +38,9 @@ private:
std::array<float, 2> dasharray = {{}};
int32_t u_dasharray = -1;
+
+ float blur = 0.0f;
+ int32_t u_blur = -1;
};
diff --git a/include/mbgl/style/property_key.hpp b/include/mbgl/style/property_key.hpp
index d9005f2f4a..68dc709597 100644
--- a/include/mbgl/style/property_key.hpp
+++ b/include/mbgl/style/property_key.hpp
@@ -30,7 +30,15 @@ enum class PropertyKey {
IconOpacity,
IconRotate,
- IconRotateAnchor,
+ IconSize,
+ IconColor,
+ IconHaloColor,
+ IconHaloWidth,
+ IconHaloBlur,
+ IconTranslate, // for transitions only
+ IconTranslateX,
+ IconTranslateY,
+ IconTranslateAnchor,
TextOpacity,
TextSize,
@@ -38,6 +46,10 @@ enum class PropertyKey {
TextHaloColor,
TextHaloWidth,
TextHaloBlur,
+ TextTranslate, // for transitions only
+ TextTranslateX,
+ TextTranslateY,
+ TextTranslateAnchor,
CompositeOpacity,
diff --git a/include/mbgl/style/style.hpp b/include/mbgl/style/style.hpp
index 6aab71a4c6..3df58ab42b 100644
--- a/include/mbgl/style/style.hpp
+++ b/include/mbgl/style/style.hpp
@@ -48,13 +48,15 @@ public:
const BackgroundProperties &getBackgroundProperties() const;
+ const std::string &getSpriteURL() const;
+
public:
- std::shared_ptr<Sprite> sprite;
std::shared_ptr<StyleLayerGroup> layers;
std::vector<std::string> appliedClasses;
- std::string sprite_url;
std::string glyph_url;
+private:
+ std::string sprite_url;
private:
PropertyTransition defaultTransition;
diff --git a/include/mbgl/style/style_bucket.hpp b/include/mbgl/style/style_bucket.hpp
index 62f072d9cd..530e0c1259 100644
--- a/include/mbgl/style/style_bucket.hpp
+++ b/include/mbgl/style/style_bucket.hpp
@@ -4,8 +4,10 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/filter_expression.hpp>
#include <mbgl/style/style_source.hpp>
+
#include <mbgl/util/vec.hpp>
#include <mbgl/util/variant.hpp>
+#include <mbgl/util/noncopyable.hpp>
#include <memory>
#include <forward_list>
@@ -16,56 +18,74 @@ class Source;
class StyleBucketFill {
public:
- WindingType winding = WindingType::Default;
+ WindingType winding = WindingType::NonZero;
};
class StyleBucketLine {
public:
- CapType cap = CapType::Default;
- JoinType join = JoinType::Default;
+ CapType cap = CapType::Butt;
+ JoinType join = JoinType::Miter;
float miter_limit = 2.0f;
float round_limit = 1.0f;
};
-class StyleBucketIcon {
+class StyleBucketSymbol {
public:
- uint16_t size = 16;
- vec2<float> translate {0, 0};
- TranslateAnchorType translate_anchor = TranslateAnchorType::Default;
- std::string icon;
- float spacing = 0.0f;
- float padding = 2.0f;
-};
-
-class StyleBucketText {
-public:
- std::string field;
- TextPathType path = TextPathType::Default;
- TextTransformType transform = TextTransformType::Default;
- std::string font;
- float max_size = 16.0f;
- float max_width = 15.0f * 24;
- float line_height = 1.2f * 24;
- float letter_spacing = 0.0f;
- float alignment = 0.5f;
- float vertical_alignment = 0.5;
- vec2<float> translate {0, 0};
- TranslateAnchorType translate_anchor = TranslateAnchorType::Default;
- float max_angle_delta = M_PI;
+ // Make movable only.
+ inline StyleBucketSymbol() = default;
+ inline StyleBucketSymbol(StyleBucketSymbol &&) = default;
+ inline StyleBucketSymbol& operator=(StyleBucketSymbol &&) = default;
+ inline StyleBucketSymbol(const StyleBucketSymbol &) = delete;
+ inline StyleBucketSymbol& operator=(const StyleBucketSymbol &) = delete;
+
+ PlacementType placement = PlacementType::Point;
float min_distance = 250.0f;
- float rotate = 0.0f; // what is this?
- float padding = 2.0f;
- float slant = 0.0f;
- bool always_visible = false;
+
+ struct {
+ bool allow_overlap = false;
+ bool ignore_placement = false;
+ bool optional = false;
+ RotationAlignmentType rotation_alignment = RotationAlignmentType::Viewport;
+ float max_size = 1.0f;
+ std::string image;
+ float rotate = 0.0f;
+ float padding = 2.0f;
+ bool keep_upright = false;
+ vec2<float> offset = {0, 0};
+ TranslateAnchorType translate_anchor = TranslateAnchorType::Map;
+ } icon;
+
+ struct {
+ RotationAlignmentType rotation_alignment = RotationAlignmentType::Viewport;
+ std::string field;
+ std::string font;
+ float max_size = 16.0f;
+ float max_width = 15.0f * 24 /* em */;
+ float line_height = 1.2f * 24 /* em */;
+ float letter_spacing = 0.0f * 24 /* em */;
+ TextJustifyType justify = TextJustifyType::Center;
+ TextHorizontalAlignType horizontal_align = TextHorizontalAlignType::Center;
+ TextVerticalAlignType vertical_align = TextVerticalAlignType::Center;
+ float max_angle = 45.0f /* degrees */;
+ float rotate = 0.0f;
+ float slant = 0.0f;
+ float padding = 2.0f;
+ bool keep_upright = true;
+ TextTransformType transform = TextTransformType::None;
+ vec2<float> offset = {0, 0};
+ TranslateAnchorType translate_anchor = TranslateAnchorType::Map;
+ bool allow_overlap = false;
+ bool ignore_placement = false;
+ bool optional = false;
+ } text;
};
class StyleBucketRaster {
public:
};
-typedef util::variant<StyleBucketFill, StyleBucketLine, StyleBucketIcon,
- StyleBucketText, StyleBucketRaster,
- std::false_type> StyleBucketRender;
+typedef util::variant<StyleBucketFill, StyleBucketLine, StyleBucketSymbol,
+ StyleBucketRaster, std::false_type> StyleBucketRender;
class StyleBucket {
@@ -79,6 +99,8 @@ public:
std::string source_layer;
FilterExpression filter;
StyleBucketRender render = std::false_type();
+ float min_zoom = -std::numeric_limits<float>::infinity();
+ float max_zoom = std::numeric_limits<float>::infinity();
};
diff --git a/include/mbgl/style/style_parser.hpp b/include/mbgl/style/style_parser.hpp
index 431e3af8db..8b8dc74f21 100644
--- a/include/mbgl/style/style_parser.hpp
+++ b/include/mbgl/style/style_parser.hpp
@@ -62,8 +62,8 @@ private:
// Parses optional properties into a render bucket.
template<typename T>
bool parseRenderProperty(JSVal value, T &target, const char *name);
- template <typename T, typename Parser>
- bool parseRenderProperty(JSVal value, T &target, const char *name, Parser &parser);
+ template <typename Parser, typename T>
+ bool parseRenderProperty(JSVal value, T &target, const char *name);
// Parses optional properties into style class properties.
template <typename T>
diff --git a/include/mbgl/style/style_properties.hpp b/include/mbgl/style/style_properties.hpp
index c7606be254..35ea97781b 100644
--- a/include/mbgl/style/style_properties.hpp
+++ b/include/mbgl/style/style_properties.hpp
@@ -19,7 +19,7 @@ struct FillProperties {
Color fill_color = {{ 0, 0, 0, 1 }};
Color stroke_color = {{ 0, 0, 0, -1 }};
std::array<float, 2> translate = {{ 0, 0 }};
- TranslateAnchorType translateAnchor = TranslateAnchorType::Default;
+ TranslateAnchorType translateAnchor = TranslateAnchorType::Map;
std::string image;
inline bool isVisible() const {
@@ -32,8 +32,8 @@ struct LineProperties {
float opacity = 1.0f;
Color color = {{ 0, 0, 0, 1 }};
std::array<float, 2> translate = {{ 0, 0 }};
- TranslateAnchorType translateAnchor = TranslateAnchorType::Default;
- float width = 0;
+ TranslateAnchorType translateAnchor = TranslateAnchorType::Map;
+ float width = 1;
float offset = 0;
float blur = 0;
std::array<float, 2> dash_array = {{ 1, -1 }};
@@ -44,30 +44,38 @@ struct LineProperties {
}
};
-struct IconProperties {
- inline IconProperties() {}
- float opacity = 1.0f;
- float rotate = 0.0f;
- RotateAnchorType rotate_anchor = RotateAnchorType::Default;
+struct SymbolProperties {
+ inline SymbolProperties() {}
+
+ struct {
+ float opacity = 1.0f;
+ float rotate = 0.0f;
+ float size = 1.0f;
+ Color color = {{ 0, 0, 0, 1 }};
+ Color halo_color = {{ 0, 0, 0, 0 }};
+ float halo_width = 0.0f;
+ float halo_blur = 0.0f;
+ std::array<float, 2> translate = {{ 0, 0 }};
+ TranslateAnchorType translate_anchor = TranslateAnchorType::Map;
+ } icon;
+
+ struct {
+ float opacity = 1.0f;
+ float size = 12.0f;
+ Color color = {{ 0, 0, 0, 1 }};
+ Color halo_color = {{ 0, 0, 0, 0 }};
+ float halo_width = 0.0f;
+ float halo_blur = 0.0f;
+ std::array<float, 2> translate = {{ 0, 0 }};
+ TranslateAnchorType translate_anchor = TranslateAnchorType::Map;
+ } text;
inline bool isVisible() const {
- return opacity > 0;
+ return (icon.opacity > 0 && (icon.color[3] > 0 || icon.halo_color[3] > 0) && icon.size > 0) ||
+ (text.opacity > 0 && (text.color[3] > 0 || text.halo_color[3] > 0) && text.size > 0);
}
};
-struct TextProperties {
- inline TextProperties() {}
- float opacity = 1.0f;
- float size = 12.0f;
- Color color = {{ 0, 0, 0, 1 }};
- Color halo_color = {{ 1, 1, 1, 0.75 }};
- float halo_width = 0.25f;
- float halo_blur = 1.0f;
-
- inline bool isVisible() const {
- return opacity > 0 && (color[3] > 0 || halo_color[3] > 0) && size > 0;
- }
-};
struct CompositeProperties {
inline CompositeProperties() {}
@@ -94,14 +102,13 @@ struct RasterProperties {
struct BackgroundProperties {
inline BackgroundProperties() {}
- Color color = {{ 1, 1, 1, 1 }};
+ Color color = {{ 0, 0, 0, 1 }};
};
typedef util::variant<
FillProperties,
LineProperties,
- IconProperties,
- TextProperties,
+ SymbolProperties,
CompositeProperties,
RasterProperties,
BackgroundProperties,
diff --git a/include/mbgl/style/style_source.hpp b/include/mbgl/style/style_source.hpp
index 6b86c30907..fa5c8dfb34 100644
--- a/include/mbgl/style/style_source.hpp
+++ b/include/mbgl/style/style_source.hpp
@@ -9,7 +9,7 @@ namespace mbgl {
class Source;
-class StyleSource {
+class SourceInfo {
public:
const SourceType type;
const std::string url;
@@ -17,13 +17,21 @@ public:
const int32_t min_zoom;
const int32_t max_zoom;
+ SourceInfo(SourceType type = SourceType::Vector, const std::string &url = "",
+ uint32_t tile_size = 512, int32_t min_zoom = 0, int32_t max_zoom = 22)
+ : type(type), url(url), tile_size(tile_size), min_zoom(min_zoom), max_zoom(max_zoom) {}
+};
+
+
+class StyleSource {
+public:
+ const SourceInfo info;
+
bool enabled = false;
std::shared_ptr<Source> source;
- StyleSource(SourceType type = SourceType::Vector, const std::string &url = "",
- uint32_t tile_size = 512, uint32_t min_zoom = 0, uint32_t max_zoom = 22)
- : type(type), url(url), tile_size(tile_size), min_zoom(min_zoom), max_zoom(max_zoom) {}
-};
+ StyleSource(const SourceInfo &info) : info(info) {}
};
+}
#endif
diff --git a/include/mbgl/style/types.hpp b/include/mbgl/style/types.hpp
index ca2061fa91..55b7685fd3 100644
--- a/include/mbgl/style/types.hpp
+++ b/include/mbgl/style/types.hpp
@@ -11,12 +11,13 @@ namespace mbgl {
// Stores a premultiplied color, with all four channels ranging from 0..1
typedef std::array<float, 4> Color;
+// -------------------------------------------------------------------------------------------------
+
enum class StyleLayerType : uint8_t {
Unknown,
Fill,
Line,
- Icon,
- Text,
+ Symbol,
Raster,
Composite,
Background
@@ -26,133 +27,172 @@ MBGL_DEFINE_ENUM_CLASS(StyleLayerTypeClass, StyleLayerType, {
{ StyleLayerType::Unknown, "unknown" },
{ StyleLayerType::Fill, "fill" },
{ StyleLayerType::Line, "line" },
- { StyleLayerType::Icon, "icon" },
- { StyleLayerType::Text, "text" },
+ { StyleLayerType::Symbol, "symbol" },
{ StyleLayerType::Raster, "raster" },
{ StyleLayerType::Composite, "composite" },
{ StyleLayerType::Background, "background" },
{ StyleLayerType(-1), "unknown" },
});
+// -------------------------------------------------------------------------------------------------
+
+enum class SourceType : uint8_t {
+ Vector,
+ Raster,
+ GeoJSON,
+ Video
+};
+
+MBGL_DEFINE_ENUM_CLASS(SourceTypeClass, SourceType, {
+ { SourceType::Vector, "vector" },
+ { SourceType::Raster, "raster" },
+ { SourceType::GeoJSON, "geojson" },
+ { SourceType::Video, "video" },
+});
-enum class WindingType : uint8_t {
+// -------------------------------------------------------------------------------------------------
+
+enum class WindingType : bool {
EvenOdd,
NonZero,
- Default = NonZero
};
+MBGL_DEFINE_ENUM_CLASS(WindingTypeClass, WindingType, {
+ { WindingType::EvenOdd, "even-odd" },
+ { WindingType::NonZero, "non-zero" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
enum class CapType : uint8_t {
- None,
Round,
Butt,
Square,
- Default = None
};
+MBGL_DEFINE_ENUM_CLASS(CapTypeClass, CapType, {
+ { CapType::Round, "round" },
+ { CapType::Butt, "butt" },
+ { CapType::Square, "square" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
enum class JoinType : uint8_t {
- None,
Miter,
Bevel,
- Round,
- Default = None
+ Round
};
-enum class TextPathType : uint8_t {
- Horizontal,
- Curve,
- Default = Horizontal
-};
+MBGL_DEFINE_ENUM_CLASS(JoinTypeClass, JoinType, {
+ { JoinType::Miter, "miter" },
+ { JoinType::Bevel, "bevel" },
+ { JoinType::Round, "round" },
+});
-enum class TextTransformType : uint8_t {
- None,
- Uppercase,
- Lowercase,
- Default = None
+// -------------------------------------------------------------------------------------------------
+
+enum class TranslateAnchorType : bool {
+ Map,
+ Viewport
};
-enum class TranslateAnchorType : uint8_t {
+MBGL_DEFINE_ENUM_CLASS(TranslateAnchorTypeClass, TranslateAnchorType, {
+ { TranslateAnchorType::Map, "map" },
+ { TranslateAnchorType::Viewport, "viewport" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class RotateAnchorType : bool {
Map,
Viewport,
- Default = Map
};
-enum class RotateAnchorType : uint8_t {
+MBGL_DEFINE_ENUM_CLASS(RotateAnchorTypeClass, RotateAnchorType, {
+ { RotateAnchorType::Map, "map" },
+ { RotateAnchorType::Viewport, "viewport" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class PlacementType : bool {
+ Point,
+ Line,
+};
+
+MBGL_DEFINE_ENUM_CLASS(PlacementTypeClass, PlacementType, {
+ { PlacementType::Point, "point" },
+ { PlacementType::Line, "line" },
+});
+
+// -------------------------------------------------------------------------------------------------
+
+enum class RotationAlignmentType : bool {
Map,
Viewport,
- Default = Viewport
};
-enum class SourceType : uint8_t {
- Vector,
- Raster,
- GeoJSON,
- Video,
- Default = Vector
-};
+MBGL_DEFINE_ENUM_CLASS(RotationAlignmentTypeClass, RotationAlignmentType, {
+ { RotationAlignmentType::Map, "map" },
+ { RotationAlignmentType::Viewport, "viewport" },
+});
-inline WindingType parseWindingType(const std::string &type) {
- if (type == "even-odd") return WindingType::EvenOdd;
- if (type == "non-zero") return WindingType::NonZero;
- return WindingType::Default;
-}
+// -------------------------------------------------------------------------------------------------
-inline CapType parseCapType(const std::string &cap) {
- if (cap == "round") return CapType::Round;
- if (cap == "butt") return CapType::Butt;
- if (cap == "square") return CapType::Square;
- return CapType::None;
-}
+enum class TextJustifyType : uint8_t {
+ Center,
+ Left,
+ Right
+};
-inline JoinType parseJoinType(const std::string &join) {
- if (join == "miter") return JoinType::Miter;
- if (join == "bevel") return JoinType::Bevel;
- if (join == "round") return JoinType::Round;
- return JoinType::None;
-}
+MBGL_DEFINE_ENUM_CLASS(TextJustifyTypeClass, TextJustifyType, {
+ { TextJustifyType::Center, "center" },
+ { TextJustifyType::Left, "left" },
+ { TextJustifyType::Right, "right" },
+});
-inline TextPathType parseTextPathType(const std::string &path) {
- if (path == "horizontal") return TextPathType::Horizontal;
- if (path == "curve") return TextPathType::Curve;
- return TextPathType::Default;
-}
+// -------------------------------------------------------------------------------------------------
-inline TextTransformType parseTextTransformType(const std::string& transform) {
- if (transform == "uppercase") return TextTransformType::Uppercase;
- if (transform == "lowercase") return TextTransformType::Lowercase;
- return TextTransformType::Default;
+enum class TextHorizontalAlignType : uint8_t {
+ Left,
+ Center,
+ Right,
};
-inline TranslateAnchorType parseTranslateAnchorType(const std::string &anchor) {
- if (anchor == "map") return TranslateAnchorType::Map;
- if (anchor == "viewport") return TranslateAnchorType::Viewport;
- return TranslateAnchorType::Default;
-}
+MBGL_DEFINE_ENUM_CLASS(TextHorizontalAlignTypeClass, TextHorizontalAlignType, {
+ { TextHorizontalAlignType::Left, "left" },
+ { TextHorizontalAlignType::Center, "center" },
+ { TextHorizontalAlignType::Right, "right" },
+});
-inline RotateAnchorType parseRotateAnchorType(const std::string &anchor) {
- if (anchor == "map") return RotateAnchorType::Map;
- if (anchor == "viewport") return RotateAnchorType::Viewport;
- return RotateAnchorType::Default;
-}
+// -------------------------------------------------------------------------------------------------
-inline float parseAlignmentType(const std::string &alignment) {
- if (alignment == "right") return 1.0f;
- if (alignment == "left") return 0.0f;
- return 0.5f;
-}
+enum class TextVerticalAlignType : uint8_t {
+ Top,
+ Center,
+ Bottom,
+};
-inline float parseVerticalAlignmentType(const std::string &alignment) {
- if (alignment == "bottom") return 1.0f;
- if (alignment == "top") return 0.0f;
- return 0.5f;
-}
+MBGL_DEFINE_ENUM_CLASS(TextVerticalAlignTypeClass, TextVerticalAlignType, {
+ { TextVerticalAlignType::Top, "top" },
+ { TextVerticalAlignType::Center, "center" },
+ { TextVerticalAlignType::Bottom, "bottom" },
+});
-inline SourceType parseSourceType(const std::string &source) {
- if (source == "vector") return SourceType::Vector;
- if (source == "raster") return SourceType::Raster;
- if (source == "geojson") return SourceType::GeoJSON;
- if (source == "video") return SourceType::Video;
- return SourceType::Default;
-}
+// -------------------------------------------------------------------------------------------------
+
+enum class TextTransformType : uint8_t {
+ None,
+ Uppercase,
+ Lowercase,
+};
+
+MBGL_DEFINE_ENUM_CLASS(TextTransformTypeClass, TextTransformType, {
+ { TextTransformType::None, "none" },
+ { TextTransformType::Uppercase, "uppercase" },
+ { TextTransformType::Lowercase, "lowercase" },
+});
}
diff --git a/include/mbgl/text/collision.hpp b/include/mbgl/text/collision.hpp
index 31103a7439..87ebdb279e 100644
--- a/include/mbgl/text/collision.hpp
+++ b/include/mbgl/text/collision.hpp
@@ -8,24 +8,23 @@ namespace mbgl {
class Collision {
public:
- Collision();
+ Collision(float zoom, float tileExtent, float tileSize, float placementDepth = 1);
~Collision();
- PlacementProperty place(const GlyphBoxes &boxes,
- const CollisionAnchor &anchor,
- float minPlacementScale, float maxPlacementScale,
- float padding, bool horizontal, bool alwaysVisible);
- float getPlacementScale(const GlyphBoxes &glyphs, float minPlacementScale,
- float maxPlacementScale, float pad);
- PlacementRange getPlacementRange(const GlyphBoxes &glyphs,
- float placementScale, bool horizontal);
- void insert(const GlyphBoxes &glyphs, const CollisionAnchor &anchor,
- float placementScale, const PlacementRange &placementRange,
- bool horizontal, float padding);
+ float getPlacementScale(const GlyphBoxes &glyphs, float minPlacementScale);
+ PlacementRange getPlacementRange(const GlyphBoxes &glyphs, float placementScale,
+ bool horizontal);
+ void insert(const GlyphBoxes &glyphs, const CollisionAnchor &anchor, float placementScale,
+ const PlacementRange &placementRange, bool horizontal);
private:
- void *cTree;
void *hTree;
+ void *cTree;
+
+public:
+ const float tilePixelRatio;
+ const float zoom;
+ const float maxPlacementScale;
};
}
diff --git a/include/mbgl/text/glyph.hpp b/include/mbgl/text/glyph.hpp
index 899c8fffee..38f9e116ab 100644
--- a/include/mbgl/text/glyph.hpp
+++ b/include/mbgl/text/glyph.hpp
@@ -16,7 +16,7 @@ GlyphRange getGlyphRange(char32_t glyph);
struct GlyphMetrics {
operator bool() const {
- return width == 0 && height == 0 && advance == 0;
+ return !(width == 0 && height == 0 && advance == 0);
}
// Glyph metrics.
@@ -35,7 +35,7 @@ struct Glyph {
: rect(rect), metrics(metrics) {}
operator bool() const {
- return !metrics && !rect;
+ return metrics || rect;
}
const Rect<uint16_t> rect;
@@ -44,18 +44,17 @@ struct Glyph {
typedef std::map<uint32_t, Glyph> GlyphPositions;
-class GlyphPlacement {
+class PositionedGlyph {
public:
- inline explicit GlyphPlacement(uint32_t face, uint32_t glyph, uint32_t x, uint32_t y)
- : face(face), glyph(glyph), x(x), y(y) {}
+ inline explicit PositionedGlyph(uint32_t glyph, uint32_t x, uint32_t y)
+ : glyph(glyph), x(x), y(y) {}
- uint32_t face = 0;
uint32_t glyph = 0;
int32_t x = 0;
int32_t y = 0;
};
-typedef std::vector<GlyphPlacement> Shaping;
+typedef std::vector<PositionedGlyph> Shaping;
}
#endif
diff --git a/include/mbgl/text/glyph_store.hpp b/include/mbgl/text/glyph_store.hpp
index 9c874b31b0..e0c0391c73 100644
--- a/include/mbgl/text/glyph_store.hpp
+++ b/include/mbgl/text/glyph_store.hpp
@@ -3,6 +3,7 @@
#include <mbgl/text/glyph.hpp>
#include <mbgl/util/pbf.hpp>
+#include <mbgl/util/vec.hpp>
#include <cstdint>
#include <vector>
@@ -13,6 +14,7 @@
namespace mbgl {
+class FileSource;
class SDFGlyph {
public:
@@ -30,17 +32,11 @@ public:
void insert(uint32_t id, const SDFGlyph &glyph);
const std::map<uint32_t, GlyphMetrics> &getMetrics() const;
const std::map<uint32_t, SDFGlyph> &getSDFs() const;
- const Shaping getShaping(const std::u32string &string,
- const float &maxWidth,
- const float &lineHeight,
- const float &alignment,
- const float &verticalAlignment,
- const float &letterSpacing) const;
- void lineWrap(Shaping &shaping,
- const float &lineHeight,
- const float &maxWidth,
- const float &alignment,
- const float &verticalAlignment) const;
+ const Shaping getShaping(const std::u32string &string, float maxWidth, float lineHeight,
+ float horizontalAlign, float verticalAlign, float justify,
+ float spacing, const vec2<float> &translate) const;
+ void lineWrap(Shaping &shaping, float lineHeight, float maxWidth, float horizontalAlign,
+ float verticalAlign, float justify) const;
private:
std::map<uint32_t, std::string> bitmaps;
@@ -51,7 +47,7 @@ private:
class GlyphPBF {
public:
- GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange);
+ GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange, const std::shared_ptr<FileSource> &fileSource);
void parse(FontStack &stack);
@@ -67,13 +63,15 @@ private:
// Manages Glyphrange PBF loading.
class GlyphStore {
public:
- GlyphStore(const std::string &glyphURL);
+ GlyphStore(const std::shared_ptr<FileSource> &fileSource);
// Block until all specified GlyphRanges of the specified font stack are loaded.
void waitForGlyphRanges(const std::string &fontStack, const std::set<GlyphRange> &glyphRanges);
FontStack &getFontStack(const std::string &fontStack);
+ void setURL(const std::string &url);
+
private:
// Loads an individual glyph range from the font stack and adds it to rangeSets
std::shared_future<GlyphPBF &> loadGlyphRange(const std::string &fontStack, std::map<GlyphRange, std::unique_ptr<GlyphPBF>> &rangeSets, GlyphRange range);
@@ -81,9 +79,10 @@ private:
FontStack &createFontStack(const std::string &fontStack);
public:
- const std::string glyphURL;
+ std::string glyphURL;
private:
+ const std::shared_ptr<FileSource> fileSource;
std::unordered_map<std::string, std::map<GlyphRange, std::unique_ptr<GlyphPBF>>> ranges;
std::unordered_map<std::string, std::unique_ptr<FontStack>> stacks;
std::mutex mtx;
diff --git a/include/mbgl/text/placement.hpp b/include/mbgl/text/placement.hpp
index 69a1a10b72..28eb8d5317 100644
--- a/include/mbgl/text/placement.hpp
+++ b/include/mbgl/text/placement.hpp
@@ -1,36 +1,30 @@
#ifndef MBGL_TEXT_PLACEMENT
#define MBGL_TEXT_PLACEMENT
-#include <mbgl/text/collision.hpp>
-#include <mbgl/geometry/geometry.hpp>
-#include <mbgl/util/vec.hpp>
+#include <mbgl/text/types.hpp>
#include <mbgl/text/glyph.hpp>
-#include <vector>
+
+#include <mbgl/util/vec.hpp>
namespace mbgl {
-class TextBucket;
-class StyleBucketText;
+struct Anchor;
+class StyleBucketSymbol;
class Placement {
public:
- Placement(int8_t zoom);
+ static Placement getIcon(Anchor &anchor, const Rect<uint16_t> &image, float iconBoxScale,
+ const std::vector<Coordinate> &line, const StyleBucketSymbol &props);
- void addFeature(TextBucket &bucket, const std::vector<Coordinate> &line,
- const StyleBucketText &info,
- const GlyphPositions &face,
- const Shaping &shaping);
+ static Placement getGlyphs(Anchor &anchor, const vec2<float> &origin, const Shaping &shaping,
+ const GlyphPositions &face, float boxScale, bool horizontal,
+ const std::vector<Coordinate> &line, const StyleBucketSymbol &props);
-private:
- const int8_t zoom;
- Collision collision;
- const float zOffset;
- const float maxPlacementScale;
+ static const float globalMinScale;
-public:
- static const int tileExtent;
- static const int glyphSize;
- static const float minScale;
+ GlyphBoxes boxes;
+ PlacedGlyphs shapes;
+ float minScale;
};
}
diff --git a/include/mbgl/text/types.hpp b/include/mbgl/text/types.hpp
index 9a9284b588..e2539bff62 100644
--- a/include/mbgl/text/types.hpp
+++ b/include/mbgl/text/types.hpp
@@ -6,6 +6,8 @@
#include <array>
#include <vector>
+#include <boost/optional.hpp>
+
namespace mbgl {
typedef vec2<float> CollisionPoint;
@@ -35,23 +37,23 @@ struct CollisionRect {
// These are the glyph boxes that we want to have placed.
struct GlyphBox {
explicit GlyphBox() {}
- explicit GlyphBox(const CollisionRect &bbox, const CollisionRect &box,
- float minScale)
- : bbox(bbox), box(box), minScale(minScale) {}
- explicit GlyphBox(const CollisionRect &box, float minScale, float maxScale,
- const CollisionAnchor &anchor, bool rotate)
- : anchor(anchor),
- box(box),
- rotate(rotate),
- minScale(minScale),
- maxScale(maxScale) {}
+ explicit GlyphBox(const CollisionRect &box,
+ const CollisionAnchor &anchor,
+ float minScale,
+ float maxScale,
+ float padding)
+ : box(box), anchor(anchor), minScale(minScale), maxScale(maxScale), padding(padding) {}
+ explicit GlyphBox(const CollisionRect &box,
+ float minScale,
+ float padding)
+ : box(box), minScale(minScale), padding(padding) {}
- CollisionAnchor anchor;
- CollisionRect bbox;
CollisionRect box;
- bool rotate = false;
+ CollisionAnchor anchor;
float minScale = 0.0f;
float maxScale = std::numeric_limits<float>::infinity();
+ float padding = 0.0f;
+ boost::optional<CollisionRect> hBox;
};
typedef std::vector<GlyphBox> GlyphBoxes;
@@ -61,19 +63,23 @@ typedef std::vector<GlyphBox> GlyphBoxes;
struct PlacedGlyph {
explicit PlacedGlyph(const vec2<float> &tl, const vec2<float> &tr,
const vec2<float> &bl, const vec2<float> &br,
- const Rect<uint16_t> &tex, float angle, const GlyphBox &glyphBox)
+ const Rect<uint16_t> &tex, float angle, const vec2<float> &anchor,
+ float minScale, float maxScale)
: tl(tl),
tr(tr),
bl(bl),
br(br),
tex(tex),
angle(angle),
- glyphBox(glyphBox) {}
+ anchor(anchor),
+ minScale(minScale),
+ maxScale(maxScale) {}
vec2<float> tl, tr, bl, br;
Rect<uint16_t> tex;
float angle;
- GlyphBox glyphBox;
+ vec2<float> anchor;
+ float minScale, maxScale;
};
typedef std::vector<PlacedGlyph> PlacedGlyphs;
@@ -81,9 +87,8 @@ typedef std::vector<PlacedGlyph> PlacedGlyphs;
// These are the placed boxes contained in the rtree.
struct PlacementBox {
CollisionAnchor anchor;
- CollisionRect bbox;
CollisionRect box;
- bool rotate = false;
+ boost::optional<CollisionRect> hBox;
PlacementRange placementRange = {{0.0f, 0.0f}};
float placementScale = 0.0f;
float maxScale = std::numeric_limits<float>::infinity();
diff --git a/include/mbgl/util/filesource.hpp b/include/mbgl/util/filesource.hpp
new file mode 100644
index 0000000000..0d339cbac7
--- /dev/null
+++ b/include/mbgl/util/filesource.hpp
@@ -0,0 +1,45 @@
+#ifndef MBGL_UTIL_FILESOURCE
+#define MBGL_UTIL_FILESOURCE
+
+#include <string>
+#include <memory>
+#include <functional>
+
+namespace uv {
+class loop;
+}
+
+namespace mbgl {
+
+namespace platform {
+struct Response;
+}
+
+enum class ResourceType : uint8_t {
+ Unknown,
+ Tile,
+ Glyphs,
+ Image,
+ JSON
+};
+
+class FileSource {
+public:
+ FileSource();
+
+ void setBase(const std::string &value);
+ const std::string &getBase() const;
+
+ void load(ResourceType type, const std::string &url, std::function<void(platform::Response *)> callback, const std::shared_ptr<uv::loop> loop = nullptr);
+
+private:
+ // Stores a URL that is used as a base for loading resources with relative path.
+ std::string base;
+
+ // Stores the absolute path to the cache directory.
+ const std::string cache;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/util/rect.hpp b/include/mbgl/util/rect.hpp
index a216b8e145..dedd4afc94 100644
--- a/include/mbgl/util/rect.hpp
+++ b/include/mbgl/util/rect.hpp
@@ -5,7 +5,8 @@ namespace mbgl {
template <typename T>
struct Rect {
- explicit Rect(T x, T y, T w, T h) : x(x), y(y), w(w), h(h) {}
+ inline Rect() {}
+ inline Rect(T x, T y, T w, T h) : x(x), y(y), w(w), h(h) {}
T x = 0, y = 0;
T w = 0, h = 0;
@@ -14,7 +15,7 @@ struct Rect {
return Rect(x * value, y * value, w * value, h * value);
}
- operator bool() const { return w == 0 || h == 0; }
+ operator bool() const { return w != 0 && h != 0; }
};
}
diff --git a/include/mbgl/util/token.hpp b/include/mbgl/util/token.hpp
index a794e0489c..786654133a 100644
--- a/include/mbgl/util/token.hpp
+++ b/include/mbgl/util/token.hpp
@@ -15,7 +15,7 @@ namespace mbgl {
namespace util {
namespace detail {
-const regex_impl::regex tokenRegex("\\{(\\w+)\\}");
+const regex_impl::regex tokenRegex("\\{([\\w-]+)\\}");
const regex_impl::sregex_token_iterator tokensEnd = regex_impl::sregex_token_iterator();
}
diff --git a/include/mbgl/util/uv.hpp b/include/mbgl/util/uv.hpp
index f36da83e4d..518e007afe 100644
--- a/include/mbgl/util/uv.hpp
+++ b/include/mbgl/util/uv.hpp
@@ -16,18 +16,37 @@
#pragma clang diagnostic pop
#endif
+#include <string>
+
namespace uv {
+inline std::string cwd() {
+ size_t max = 0;
+ std::string dir;
+ do {
+ max += 256;
+ dir.resize(max);
+ uv_cwd(const_cast<char *>(dir.data()), &max);
+ } while (max == dir.size());
+ dir.resize(max - 1);
+ return dir;
+}
+
class loop {
public:
- inline loop() : l(uv_loop_new()) {}
- inline ~loop() { uv_loop_delete(l); }
+ inline loop() {
+ if (uv_loop_init(&l) != 0) {
+ throw std::runtime_error("failed to initialize loop");
+ }
+ }
+
+ inline ~loop() { uv_loop_close(&l); }
- inline uv_loop_t *operator*() { return l; }
+ inline uv_loop_t *operator*() { return &l; }
private:
- uv_loop_t *l;
+ uv_loop_t l;
};
class mutex {
diff --git a/ios/mapbox-gl-cocoa b/ios/mapbox-gl-cocoa
-Subproject 6d29b1a2be6cf29e84349605a42140c038d80c8
+Subproject ced284d8a7bfc66540d8af50f811fd4df0e0886
diff --git a/linux/main.cpp b/linux/main.cpp
index e603be55e4..b1241d64e0 100644
--- a/linux/main.cpp
+++ b/linux/main.cpp
@@ -45,22 +45,13 @@ int main(int argc, char *argv[]) {
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);
- // read default stylesheet from disk
- std::ifstream stylefile("./style.min.js");
- if (!stylefile.good()) {
- fprintf(stderr, "Cannot read style file\n");
- return 1;
- }
- std::stringstream stylejson;
- stylejson << stylefile.rdbuf();
-
view = new GLFWView();
mbgl::Map map(*view);
// Load settings
mbgl::Settings_JSON settings;
map.setLonLatZoom(settings.longitude, settings.latitude, settings.zoom);
- map.setAngle(settings.angle);
+ map.setBearing(settings.bearing);
map.setDebug(settings.debug);
// Set access token if present
@@ -72,13 +63,14 @@ int main(int argc, char *argv[]) {
}
// Load style
- map.setStyleJSON(stylejson.str());
+ const std::string style = std::string("file://") + uv::cwd() + std::string("/styles/bright/style.json");
+ map.setStyleURL(style);
int ret = view->run();
// Save settings
map.getLonLatZoom(settings.longitude, settings.latitude, settings.zoom);
- settings.angle = map.getAngle();
+ settings.bearing = map.getBearing();
settings.debug = map.getDebug();
settings.save();
diff --git a/linux/mapboxgl-app.gyp b/linux/mapboxgl-app.gyp
index 1d09b5444b..7b703ed75c 100644
--- a/linux/mapboxgl-app.gyp
+++ b/linux/mapboxgl-app.gyp
@@ -53,7 +53,7 @@
],
'dependencies': [
'../mapboxgl.gyp:mapboxgl',
- '../mapboxgl.gyp:copy_default_stylesheet',
+ '../mapboxgl.gyp:copy_styles',
'../mapboxgl.gyp:copy_certificate_bundle',
],
},
diff --git a/macosx/Info.plist b/macosx/Info.plist
index 366a5d8abc..514db118ea 100644
--- a/macosx/Info.plist
+++ b/macosx/Info.plist
@@ -32,5 +32,16 @@
<string>0.0.1</string>
<key>NSHighResolutionCapable</key>
<true/>
+ <key>CFBundleURLTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleURLName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>mapboxgl</string>
+ </array>
+ </dict>
+ </array>
</dict>
</plist> \ No newline at end of file
diff --git a/macosx/main.mm b/macosx/main.mm
index da78f089c5..9ecc307c05 100644
--- a/macosx/main.mm
+++ b/macosx/main.mm
@@ -4,35 +4,102 @@
#import <Foundation/Foundation.h>
+@interface URLHandler : NSObject
+@property (nonatomic) mbgl::Map *map;
+
+- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
+ withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
+@end
+
+@implementation URLHandler
+
+- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
+ withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
+ (void)replyEvent;
+
+ NSString* urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
+ NSURL *url = [NSURL URLWithString:urlString];
+ NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
+ for (NSString *param in [[url query] componentsSeparatedByString:@"&"]) {
+ NSArray *parts = [param componentsSeparatedByString:@"="];
+ if([parts count] < 2) continue;
+ [params setObject:[parts objectAtIndex:1] forKey:[parts objectAtIndex:0]];
+ }
+
+ double latitude = 0, longitude = 0, zoom = 0, bearing = 0;
+ bool hasCenter = false, hasZoom = false, hasBearing = false;
+
+ NSString *centerString = [params objectForKey:@"center"];
+ if (centerString) {
+ NSArray *latlon = [centerString componentsSeparatedByString:@","];
+ if ([latlon count] == 2) {
+ latitude = [[latlon objectAtIndex:0] doubleValue];
+ longitude = [[latlon objectAtIndex:1] doubleValue];
+ hasCenter = true;
+ }
+ }
+
+ NSString *zoomString = [params objectForKey:@"zoom"];
+ if (zoomString) {
+ zoom = [zoomString doubleValue];
+ hasZoom = true;
+ }
+
+ NSString *bearingString = [params objectForKey:@"bearing"];
+ if (bearingString) {
+ bearing = [bearingString doubleValue];
+ hasBearing = true;
+ }
+
+ if ([self map]) {
+ if (hasCenter && hasZoom) {
+ [self map]->setLonLatZoom(longitude, latitude, zoom);
+ } else if (hasCenter) {
+ [self map]->setLonLat(longitude, latitude);
+ } else if (hasZoom) {
+ [self map]->setZoom(zoom);
+ }
+
+ if (hasBearing) {
+ [self map]->setBearing(bearing);
+ }
+ }
+}
+@end
+
int main() {
mbgl::Log::Set<mbgl::NSLogBackend>();
GLFWView view;
mbgl::Map map(view);
+ URLHandler *handler = [[URLHandler alloc] init];
+ [handler setMap:&map];
+ NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
+ [appleEventManager setEventHandler:handler andSelector:@selector(handleGetURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
+
// Load settings
mbgl::Settings_NSUserDefaults settings;
map.setLonLatZoom(settings.longitude, settings.latitude, settings.zoom);
- map.setAngle(settings.angle);
+ map.setBearing(settings.bearing);
map.setDebug(settings.debug);
+
// Set access token if present
NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"];
if ( ! accessToken) mbgl::Log::Warning(mbgl::Event::Setup, "No access token set. Mapbox vector tiles won't work.");
if (accessToken) map.setAccessToken([accessToken cStringUsingEncoding:[NSString defaultCStringEncoding]]);
// Load style
- NSString *path = [[NSBundle mainBundle] pathForResource:@"style.min" ofType:@"js"];
- NSString *json = [NSString stringWithContentsOfFile:path
- encoding:[NSString defaultCStringEncoding]
- error:nil];
- map.setStyleJSON((std::string)[json cStringUsingEncoding:[NSString defaultCStringEncoding]]);
+ const std::string path([[[NSBundle mainBundle] pathForResource:@"style" ofType:@"json" inDirectory:@"styles/bright"] UTF8String]);
+
+ map.setStyleURL(std::string("file://") + path);
int ret = view.run();
// Save settings
map.getLonLatZoom(settings.longitude, settings.latitude, settings.zoom);
- settings.angle = map.getAngle();
+ settings.bearing = map.getBearing();
settings.debug = map.getDebug();
settings.save();
diff --git a/macosx/mapboxgl-app.gyp b/macosx/mapboxgl-app.gyp
index 59dfc66470..480dc2a114 100644
--- a/macosx/mapboxgl-app.gyp
+++ b/macosx/mapboxgl-app.gyp
@@ -23,7 +23,6 @@
'mac_bundle': 1,
'mac_bundle_resources': [
'Icon.icns',
- '<(SHARED_INTERMEDIATE_DIR)/bin/style.min.js'
],
'xcode_settings': {
'SDKROOT': 'macosx',
@@ -40,7 +39,8 @@
'CLANG_ENABLE_OBJC_ARC': 'YES'
},
'dependencies': [
- '../mapboxgl.gyp:mapboxgl'
+ '../mapboxgl.gyp:bundle_styles',
+ '../mapboxgl.gyp:mapboxgl',
]
}
]
diff --git a/mapboxgl.gyp b/mapboxgl.gyp
index 0c08989ce8..5a526f8e90 100644
--- a/mapboxgl.gyp
+++ b/mapboxgl.gyp
@@ -54,7 +54,7 @@
],
},
{
- 'target_name': 'build_stylesheet',
+ 'target_name': 'bundle_styles',
'type': 'none',
'hard_dependency': 1,
'dependencies': [
@@ -62,40 +62,39 @@
],
'actions': [
{
- 'action_name': 'Build Stylesheet',
- 'inputs': [
- 'bin/default.style.json',
- ],
- 'outputs': [
- '<(SHARED_INTERMEDIATE_DIR)/bin/style.min.js',
- ],
- 'action': ['<@(node)', 'bin/build-style.js', '<@(_inputs)', '<(SHARED_INTERMEDIATE_DIR)/bin']
+ 'action_name': 'Touch Stylesheet Directory',
+ 'inputs': ['styles'],
+ 'outputs': ['styles'],
+ 'action': ['touch', 'styles'], # required for xcode http://openradar.appspot.com/7232149
}
],
'direct_dependent_settings': {
- 'sources': [
- '<(SHARED_INTERMEDIATE_DIR)/bin/style.min.js',
+ 'mac_bundle_resources': [
+ 'styles',
],
}
},
{
- 'target_name': 'copy_default_stylesheet',
+ 'target_name': 'copy_styles',
'type': 'none',
'hard_dependency': 1,
- 'dependencies': [
- 'build_stylesheet'
+ 'actions': [
+ {
+ 'action_name': 'Touch Stylesheet Directory',
+ 'inputs': ['styles'],
+ 'outputs': ['styles'],
+ 'action': ['touch', 'styles'], # required for xcode http://openradar.appspot.com/7232149
+ }
],
'copies': [
{
- 'files': [
- '<(SHARED_INTERMEDIATE_DIR)/bin/style.min.js',
- ],
+ 'files': [ 'styles' ],
'destination': '<(PRODUCT_DIR)'
}
]
},
{
- 'target_name': 'copy_default_stylesheet_fixtures',
+ 'target_name': 'copy_fixtures',
'type': 'none',
'hard_dependency': 1,
'dependencies': [
@@ -103,9 +102,7 @@
],
'copies': [
{
- 'files': [
- 'bin/default.style.json',
- ],
+ 'files': [ 'styles' ],
'destination': 'test/fixtures/style_parser'
}
]
@@ -127,7 +124,6 @@
'type': 'static_library',
'hard_dependency': 1,
'dependencies': [
- 'build_stylesheet',
'shaders',
],
'sources': [
@@ -195,7 +191,6 @@
'type': 'static_library',
'hard_dependency': 1,
'dependencies': [
- 'build_stylesheet',
'shaders',
],
'sources': [
diff --git a/scripts/compare_images.js b/scripts/compare_images.js
deleted file mode 100755
index ef854b038e..0000000000
--- a/scripts/compare_images.js
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/usr/bin/env node
-
-var fs = require('fs');
-var path = require('path');
-var spawn = require('child_process').spawn;
-
-var base_dir = path.join(path.resolve('.'), 'test/fixtures/styles');
-
-var files = fs.readdirSync(base_dir).filter(function(name) {
- return name.match(/\.info\.json$/);
-});
-
-var html =
- '<style>\n' +
- ' body { font-family: Helvetica; }\n' +
- ' h2 a { color:white; text-decoration:none; }\n' +
- '</style>\n' +
- '<table>\n' +
- '<tr>\n' +
- ' <th>Actual</th>\n' +
- ' <th>Expected</th>\n' +
- ' <th>Info</th>\n' +
- '</tr>\n';
-
-var exitCode = 0;
-var failures = 0;
-
-processFiles();
-
-function processFiles() {
- if (!files.length) return done();
-
- var name = files.shift();
-
- var info = require(path.join(base_dir, name));
-
- var keys = Object.keys(info);
-
- processFileTest();
-
- function processFileTest() {
- if (!keys.length) return processFiles();
-
- var key = keys.shift();
-
- var base = path.basename(name, '.info.json');
-
- var actual = path.join(base_dir, base + '/' + key + '.actual.png');
- var expected = path.join(base_dir, base + '/' + key + '.expected.png');
- var diff = path.join(base_dir, base + '/' + key + '.diff.png');
-
- var compare = spawn('compare', ['-metric', 'MAE', actual, expected, diff ]);
- var error = '';
- compare.stderr.on('data', function(data) {
- error += data.toString();
- });
- compare.on('exit', function(code, signal) {
- // The compare program returns 2 on error otherwise 0 if the images are similar or 1 if they are dissimilar.
- if (code == 2) {
- writeResult(base, key, info[key], error.trim(), Infinity);
- exitCode = 2;
- } else {
- var match = error.match(/^\d+(?:\.\d+)?\s+\(([^\)]+)\)\s*$/);
- var difference = match ? parseFloat(match[1]) : Infinity;
- writeResult(base, key, info[key], match ? '' : error, difference);
-
- }
- processFileTest();
- });
- compare.stdin.end();
- }
-}
-
-function writeResult(base, key, info, error, difference) {
- var color = 'green';
- var allowedDifference = ('diff' in info) ? info.diff : 0.01;
- if (difference > allowedDifference) {
- color = 'red';
- if (exitCode < 1) {
- exitCode = 1;
- }
- failures++;
- }
-
- html +=
- '<tr>\n' +
- ' <td><img src="' + base + '/' + key + '.actual.png" onmouseover="this.src=\'' + base + '/' + key + '.expected.png\'" onmouseout="this.src=\'' + base + '/' + key + '.actual.png\'"></td>\n' +
- ' <td><img src="' + base + '/' + key + '.expected.png" onmouseover="this.src=\'' + base + '/' + key + '.diff.png\'" onmouseout="this.src=\'' + base + '/' + key + '.expected.png\'"></td>\n' +
- ' <td>\n' +
- ' <h2 style="text-align:center; background:' + color + '"><a href="' + base + '.style.json">' + base + '/' + key + '</a></h2>\n' +
- (error ? ' <p>' + error + '</p>\n' : '') +
- ' <ul>\n' +
- ' <li>diff: <strong>' + difference + '</strong></li>\n' +
- ' <li>zoom: <strong>' + (info.zoom || 0) + '</strong></li>\n' +
- ' <li>center: <strong>' + (info.center || [0, 0]) + '</strong></li>\n' +
- ' <li>bearing: <strong>' + (info.bearing || 0) + '</strong></li>\n' +
- ' <li>width: <strong>' + (info.width || 512) + '</strong></li>\n' +
- ' <li>height: <strong>' + (info.height || 512) + '</strong></li>\n' +
- ' </ul>\n' +
- ' </td>\n' +
- '</tr>\n'
- ;
-}
-
-function done() {
- html += "</table>\n";
-
- fs.writeFileSync(path.join(base_dir, 'index.html'), html);
- console.warn('Results at: ' + path.join(base_dir, 'index.html'));
- if (failures) {
- console.warn('\x1B[1m\x1B[31m' + failures + ' ' + (failures == 1 ? 'image doesn\'t' : 'images don\'t') + ' match\x1B[39m\x1B[22m');
- } else {
- console.warn('\x1B[1m\x1B[32mAll images match\x1B[39m\x1B[22m');
- }
-
- process.exit(exitCode);
-} \ No newline at end of file
diff --git a/scripts/deploy_results.sh b/scripts/deploy_results.sh
deleted file mode 100755
index bf13def012..0000000000
--- a/scripts/deploy_results.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-set -o pipefail
-
-aws s3 cp test/fixtures/styles/ s3://mapbox-gl-testing/headless/$TRAVIS_JOB_NUMBER/ --acl public-read --recursive
-
-echo http://mapbox-gl-testing.s3.amazonaws.com/headless/$TRAVIS_JOB_NUMBER/index.html
diff --git a/src/geometry/icon_buffer.cpp b/src/geometry/icon_buffer.cpp
index a25b2de068..c571dfa69e 100644
--- a/src/geometry/icon_buffer.cpp
+++ b/src/geometry/icon_buffer.cpp
@@ -1,18 +1,35 @@
#include <mbgl/geometry/icon_buffer.hpp>
#include <mbgl/platform/gl.hpp>
+#include <mbgl/util/math.hpp>
#include <cmath>
-using namespace mbgl;
+namespace mbgl {
-void IconVertexBuffer::add(vertex_type x, vertex_type y, uint16_t tx, uint16_t ty) {
+const double IconVertexBuffer::angleFactor = 128.0 / M_PI;
+
+size_t IconVertexBuffer::add(int16_t x, int16_t y, float ox, float oy, int16_t tx, int16_t ty, float angle, float minzoom, std::array<float, 2> range, float maxzoom, float labelminzoom) {
+ const size_t idx = index();
void *data = addElement();
- vertex_type *vertices = static_cast<vertex_type *>(data);
- vertices[0] = x;
- vertices[1] = y;
+ int16_t *shorts = static_cast<int16_t *>(data);
+ shorts[0] /* pos */ = x;
+ shorts[1] /* pos */ = y;
+ shorts[2] /* offset */ = std::round(ox * 64); // use 1/64 pixels for placement
+ shorts[3] /* offset */ = std::round(oy * 64);
+
+ uint8_t *ubytes = static_cast<uint8_t *>(data);
+ ubytes[8] /* labelminzoom */ = labelminzoom * 10;
+ ubytes[9] /* minzoom */ = minzoom * 10; // 1/10 zoom levels: z16 == 160.
+ ubytes[10] /* maxzoom */ = std::fmin(maxzoom, 25) * 10; // 1/10 zoom levels: z16 == 160.
+ ubytes[11] /* angle */ = (int16_t)std::round(angle * angleFactor) % 256;
+ ubytes[12] /* rangeend */ = util::max((int16_t)std::round(range[0] * angleFactor), (int16_t)0) % 256;
+ ubytes[13] /* rangestart */ = util::min((int16_t)std::round(range[1] * angleFactor), (int16_t)255) % 256;
+
+ shorts[8] /* tex */ = tx;
+ shorts[9] /* tex */ = ty;
+
+ return idx;
+}
- uint16_t *texture = static_cast<uint16_t *>(data);
- texture[2] = tx;
- texture[3] = ty;
}
diff --git a/src/geometry/interpolate.cpp b/src/geometry/interpolate.cpp
index d9cfdfa1db..618136ff47 100644
--- a/src/geometry/interpolate.cpp
+++ b/src/geometry/interpolate.cpp
@@ -1,9 +1,30 @@
#include <mbgl/geometry/interpolate.hpp>
+#include <mbgl/util/math.hpp>
+
+#include <cmath>
+
namespace mbgl {
+const float minScale = 0.5f;
+const std::array<std::vector<float>, 4> minScaleArrays = {{
+ /*1:*/ { minScale },
+ /*2:*/ { minScale, 2 },
+ /*4:*/ { minScale, 4, 2, 4 },
+ /*8:*/ { minScale, 8, 4, 8, 2, 8, 4, 8 }
+}};
+
+
Anchors interpolate(const std::vector<Coordinate> &vertices, float spacing,
- float minScale, int start) {
+ const float /*minScale*/, float maxScale, const float tilePixelRatio,
+ const int start) {
+
+ maxScale = std::round(std::fmax(std::fmin(8.0f, maxScale / 2.0f), 1.0f));
+ spacing *= tilePixelRatio / maxScale;
+ const size_t index = util::clamp<size_t>(std::floor(std::log(maxScale) / std::log(2)), 0, minScaleArrays.size() - 1);
+ const std::vector<float> &minScales = minScaleArrays[index];
+ const size_t len = minScales.size();
+
float distance = 0.0f;
float markedDistance = 0.0f;
int added = start;
@@ -23,9 +44,7 @@ Anchors interpolate(const std::vector<Coordinate> &vertices, float spacing,
float t = (markedDistance - distance) / segmentDist,
x = util::interp(a.x, b.x, t), y = util::interp(a.y, b.y, t),
- s = added % 8 == 0 ? minScale : added % 4 == 0
- ? 2
- : added % 2 == 0 ? 4 : 8;
+ s = minScales[added % len];
if (x >= 0 && x < 4096 && y >= 0 && y < 4096) {
points.emplace_back(x, y, angle, s, i);
diff --git a/src/geometry/sprite_atlas.cpp b/src/geometry/sprite_atlas.cpp
index 8fa3e83888..71d3cbee99 100644
--- a/src/geometry/sprite_atlas.cpp
+++ b/src/geometry/sprite_atlas.cpp
@@ -88,27 +88,6 @@ void copy_bitmap(const uint32_t *src, const int src_stride, const int src_x, con
}
}
-void draw_circle(uint32_t *dst, const int dst_stride, const int dst_x, const int dst_y,
- const int width, const int height, const float blur,
- const uint8_t r = 0xFF, const uint8_t g = 0xFF, const uint8_t b = 0xFF) {
- const int sprite_stride = dst_stride;
- const int radius = util::min(width, height);
- for (int y = 0; y < height; y++) {
- const int img_y = (dst_y + y) * sprite_stride + dst_x;
- for (int x = 0; x < height; x++) {
- const float dist = util::length(float(x) / radius - 0.5f, float(y) / radius - 0.5f);
- const float t = util::smoothstep(0.5f, 0.5f - blur, dist);
- const uint8_t alpha = t * 255;
-
- uint32_t color = (uint32_t(r * t) << 0) |
- (uint32_t(g * t) << 8) |
- (uint32_t(b * t) << 16) |
- (uint32_t(alpha) << 24);
- dst[img_y + x] = color;
- }
- }
-}
-
Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(size_t width, size_t height) {
// We have to allocate a new area in the bin, and store an empty image in it.
// Add a 1px border around every image.
@@ -125,44 +104,6 @@ Rect<SpriteAtlas::dimension> SpriteAtlas::allocateImage(size_t width, size_t hei
return rect;
}
-Rect<SpriteAtlas::dimension> SpriteAtlas::getIcon(const int size, const std::string &name) {
- std::lock_guard<std::mutex> lock(mtx);
-
- auto rect_it = images.find(name);
- if (rect_it != images.end()) {
- return rect_it->second;
- }
-
- Rect<dimension> rect = allocateImage(size, size);
- if (rect.w == 0) {
- if (debug::spriteWarnings) {
- fprintf(stderr, "[WARNING] sprite atlas bitmap overflow\n");
- }
- return rect;
- }
-
- images.emplace(name, rect);
-
- allocate();
-
- // Draw an antialiased circle.
- draw_circle(
- reinterpret_cast<uint32_t *>(data),
- width * pixelRatio,
- rect.x * pixelRatio,
- rect.y * pixelRatio,
- size * pixelRatio,
- size * pixelRatio,
- 1.0f / size / pixelRatio
- );
-
- uninitialized.emplace(name);
-
- dirty = true;
-
- return rect;
-}
-
Rect<SpriteAtlas::dimension> SpriteAtlas::getImage(const std::string &name, const Sprite &sprite) {
std::lock_guard<std::mutex> lock(mtx);
@@ -191,6 +132,12 @@ Rect<SpriteAtlas::dimension> SpriteAtlas::getImage(const std::string &name, cons
return rect;
}
+
+Rect<SpriteAtlas::dimension> SpriteAtlas::waitForImage(const std::string &name, const Sprite &sprite) {
+ sprite.waitUntilLoaded();
+ return getImage(name, sprite);
+}
+
void SpriteAtlas::allocate() {
if (!data) {
dimension w = static_cast<dimension>(width * pixelRatio);
diff --git a/src/map/map.cpp b/src/map/map.cpp
index c7039cc927..ef7b9548bd 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -1,5 +1,6 @@
#include <mbgl/map/map.hpp>
#include <mbgl/map/source.hpp>
+#include <mbgl/map/view.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/map/sprite.hpp>
#include <mbgl/util/transition.hpp>
@@ -10,25 +11,36 @@
#include <mbgl/util/constants.hpp>
#include <mbgl/util/uv.hpp>
#include <mbgl/util/std.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/text/glyph_store.hpp>
+#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/style/style_layer_group.hpp>
#include <mbgl/style/style_bucket.hpp>
+#include <mbgl/util/texturepool.hpp>
#include <mbgl/geometry/sprite_atlas.hpp>
+#include <mbgl/util/filesource.hpp>
+#include <mbgl/platform/log.hpp>
#include <algorithm>
#include <memory>
#include <iostream>
+#define _USE_MATH_DEFINES
+#include <cmath>
+
using namespace mbgl;
Map::Map(View& view)
- : view(view),
+ : loop(std::make_shared<uv::loop>()),
+ view(view),
transform(view),
+ fileSource(std::make_shared<FileSource>()),
style(std::make_shared<Style>()),
glyphAtlas(std::make_shared<GlyphAtlas>(1024, 1024)),
+ glyphStore(std::make_shared<GlyphStore>(fileSource)),
spriteAtlas(std::make_shared<SpriteAtlas>(512, 512)),
texturepool(std::make_shared<Texturepool>()),
- painter(*this),
- loop(std::make_shared<uv::loop>()) {
+ painter(*this) {
view.initialize(this);
@@ -160,7 +172,7 @@ void Map::render(uv_async_t *async) {
void Map::terminate(uv_async_t *async) {
// Closes all open handles on the loop. This means that the loop will automatically terminate.
uv_loop_t *loop = static_cast<uv_loop_t *>(async->data);
- uv_walk(loop, [](uv_handle_t *handle, void *arg) {
+ uv_walk(loop, [](uv_handle_t *handle, void */*arg*/) {
if (!uv_is_closing(handle)) {
uv_close(handle, NULL);
}
@@ -175,9 +187,30 @@ void Map::setup() {
painter.setup();
}
-void Map::setStyleJSON(std::string newStyleJSON) {
+void Map::setStyleURL(const std::string &url) {
+ fileSource->load(ResourceType::JSON, url, [&](platform::Response *res) {
+ if (res->code == 200) {
+ // Calculate the base
+ const size_t pos = url.rfind('/');
+ std::string base = "";
+ if (pos != std::string::npos) {
+ base = url.substr(0, pos + 1);
+ }
+
+ this->setStyleJSON(res->body, base);
+ } else {
+ Log::Error(Event::Setup, "loading style failed: %d (%s)", res->code, res->error_message.c_str());
+ }
+ }, loop);
+}
+
+
+void Map::setStyleJSON(std::string newStyleJSON, const std::string &base) {
styleJSON.swap(newStyleJSON);
+ sprite.reset();
style->loadJSON((const uint8_t *)styleJSON.c_str());
+ fileSource->setBase(base);
+ glyphStore->setURL(style->glyph_url);
update();
}
@@ -193,6 +226,17 @@ std::string Map::getAccessToken() const {
return accessToken;
}
+std::shared_ptr<Sprite> Map::getSprite() {
+ const float pixelRatio = state.getPixelRatio();
+ const std::string &sprite_url = style->getSpriteURL();
+ if (!sprite || sprite->pixelRatio != pixelRatio) {
+ sprite = Sprite::Create(sprite_url, pixelRatio, fileSource);
+ }
+
+ return sprite;
+}
+
+
#pragma mark - Size
// Note: This function is called from another thread. Make sure you only call threadsafe functions!
@@ -333,20 +377,20 @@ void Map::rotateBy(double sx, double sy, double ex, double ey, double duration)
}
// Note: This function is called from another thread. Make sure you only call threadsafe functions!
-void Map::setAngle(double angle, double duration) {
- transform.setAngle(angle, duration * 1_second);
+void Map::setBearing(double degrees, double duration) {
+ transform.setAngle(-degrees * M_PI / 180, duration * 1_second);
update();
}
// Note: This function is called from another thread. Make sure you only call threadsafe functions!
-void Map::setAngle(double angle, double cx, double cy) {
- transform.setAngle(angle, cx, cy);
+void Map::setBearing(double degrees, double cx, double cy) {
+ transform.setAngle(-degrees * M_PI / 180, cx, cy);
update();
}
// Note: This function is called from another thread. Make sure you only call threadsafe functions!
-double Map::getAngle() const {
- return transform.getAngle();
+double Map::getBearing() const {
+ return -transform.getAngle() / M_PI * 180;
}
// Note: This function is called from another thread. Make sure you only call threadsafe functions!
@@ -421,13 +465,13 @@ void Map::updateSources() {
updateSources(style->layers);
// Then, construct or destroy the actual source object, depending on enabled state.
- for (const std::shared_ptr<StyleSource> &source : activeSources) {
- if (source->enabled) {
- if (!source->source) {
- source->source = std::make_shared<Source>(*source, getAccessToken());
+ for (const std::shared_ptr<StyleSource> &style_source : activeSources) {
+ if (style_source->enabled) {
+ if (!style_source->source) {
+ style_source->source = std::make_shared<Source>(style_source->info, getAccessToken());
}
} else {
- source->source.reset();
+ style_source->source.reset();
}
}
@@ -494,24 +538,6 @@ void Map::prepare() {
bool dimensionsChanged = oldState.getFramebufferWidth() != state.getFramebufferWidth() ||
oldState.getFramebufferHeight() != state.getFramebufferHeight();
- if (pixelRatioChanged) {
- style->sprite = std::make_shared<Sprite>(*this, state.getPixelRatio());
- if (style->sprite_url.size()) {
- style->sprite->load(style->sprite_url);
- }
- spriteAtlas->resize(state.getPixelRatio());
- }
-
- // Create a new glyph store object in case the glyph URL changed.
- // TODO: Move this to a less frequently called place; we only need to do this when the
- // stylesheet changes.
- if (glyphStore && glyphStore->glyphURL != style->glyph_url) {
- glyphStore.reset();
- }
- if (!glyphStore && style->glyph_url.size()) {
- glyphStore = std::make_shared<GlyphStore>(style->glyph_url);
- }
-
if (pixelRatioChanged || dimensionsChanged) {
painter.clearFramebuffers();
}
@@ -521,9 +547,8 @@ void Map::prepare() {
style->updateProperties(state.getNormalizedZoom(), animationTime);
// Allow the sprite atlas to potentially pull new sprite images if needed.
- if (style->sprite && style->sprite->isLoaded()) {
- spriteAtlas->update(*style->sprite);
- }
+ spriteAtlas->resize(state.getPixelRatio());
+ spriteAtlas->update(*getSprite());
updateTiles();
}
@@ -557,8 +582,6 @@ void Map::render() {
source->source->finishRender(painter);
}
- painter.renderMatte();
-
// Schedule another rerender when we definitely need a next frame.
if (transform.needsTransition() || style->hasTransitions()) {
update();
@@ -637,7 +660,7 @@ void Map::renderLayer(std::shared_ptr<StyleLayer> layer_desc, RenderPass pass) {
}
}
}
- } else if (layer_desc->id == "background") {
+ } else if (layer_desc->type == StyleLayerType::Background) {
// This layer defines the background color.
} else {
// This is a singular layer.
@@ -653,6 +676,20 @@ void Map::renderLayer(std::shared_ptr<StyleLayer> layer_desc, RenderPass pass) {
StyleSource &style_source = *layer_desc->bucket->style_source;
+ // Skip this layer if there is no data.
+ if (!style_source.source) {
+ return;
+ }
+
+ // Skip this layer if it's outside the range of min/maxzoom.
+ // This may occur when there /is/ a bucket created for this layer, but the min/max-zoom
+ // is set to a fractional value, or value that is larger than the source maxzoom.
+ const double zoom = state.getZoom();
+ if (layer_desc->bucket->min_zoom > zoom ||
+ layer_desc->bucket->max_zoom <= zoom) {
+ return;
+ }
+
// Abort early if we can already deduce from the bucket type that
// we're not going to render anything anyway during this pass.
switch (layer_desc->type) {
@@ -663,13 +700,9 @@ void Map::renderLayer(std::shared_ptr<StyleLayer> layer_desc, RenderPass pass) {
if (pass == Opaque) return;
if (!layer_desc->getProperties<LineProperties>().isVisible()) return;
break;
- case StyleLayerType::Icon:
+ case StyleLayerType::Symbol:
if (pass == Opaque) return;
- if (!layer_desc->getProperties<IconProperties>().isVisible()) return;
- break;
- case StyleLayerType::Text:
- if (pass == Opaque) return;
- if (!layer_desc->getProperties<TextProperties>().isVisible()) return;
+ if (!layer_desc->getProperties<SymbolProperties>().isVisible()) return;
break;
case StyleLayerType::Raster:
if (pass == Translucent) return;
@@ -684,8 +717,6 @@ void Map::renderLayer(std::shared_ptr<StyleLayer> layer_desc, RenderPass pass) {
<< layer_desc->type << ")" << std::endl;
}
- if (style_source.source) {
- style_source.source->render(painter, layer_desc);
- }
+ style_source.source->render(painter, layer_desc);
}
}
diff --git a/src/map/raster_tile_data.cpp b/src/map/raster_tile_data.cpp
index ef6bea7e62..a3c6d21a68 100644
--- a/src/map/raster_tile_data.cpp
+++ b/src/map/raster_tile_data.cpp
@@ -5,8 +5,8 @@
using namespace mbgl;
-RasterTileData::RasterTileData(Tile::ID id, Map &map, const std::string url)
- : TileData(id, map, url),
+RasterTileData::RasterTileData(Tile::ID id, Map &map, const SourceInfo &source)
+ : TileData(id, map, source),
bucket(map.getTexturepool()) {
}
@@ -29,6 +29,6 @@ void RasterTileData::render(Painter &painter, std::shared_ptr<StyleLayer> layer_
bucket.render(painter, layer_desc, id);
}
-bool RasterTileData::hasData(std::shared_ptr<StyleLayer> layer_desc) const {
+bool RasterTileData::hasData(std::shared_ptr<StyleLayer> /*layer_desc*/) const {
return bucket.hasData();
}
diff --git a/src/map/source.cpp b/src/map/source.cpp
index e46bb0abd8..f9e34d926d 100644
--- a/src/map/source.cpp
+++ b/src/map/source.cpp
@@ -7,7 +7,6 @@
#include <mbgl/util/string.hpp>
#include <mbgl/util/texturepool.hpp>
#include <mbgl/util/vec.hpp>
-#include <mbgl/util/token.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/style/style_layer.hpp>
@@ -18,21 +17,14 @@
namespace mbgl {
-Source::Source(StyleSource style_source, const std::string &access_token)
- : type(style_source.type),
- url(normalizeSourceURL(style_source.url, access_token)),
- tile_size(style_source.tile_size),
- min_zoom(style_source.min_zoom),
- max_zoom(style_source.max_zoom) {}
-
-Source::Source(SourceType type, const std::string &url,
- uint32_t tile_size, uint32_t min_zoom, uint32_t max_zoom,
- const std::string &access_token)
- : type(type),
- url(normalizeSourceURL(url, access_token)),
- tile_size(tile_size),
- min_zoom(min_zoom),
- max_zoom(max_zoom) {}
+Source::Source(SourceInfo info, const std::string &access_token)
+ : info(
+ info.type,
+ normalizeSourceURL(info.url, access_token),
+ info.tile_size,
+ info.min_zoom,
+ info.max_zoom
+ ) {}
std::string Source::normalizeSourceURL(const std::string &url, const std::string &access_token) {
const std::string t = "mapbox://";
@@ -153,18 +145,10 @@ TileData::State Source::addTile(Map &map, const Tile::ID& id) {
if (!new_tile.data) {
// If we don't find working tile data, we're just going to load it.
- const std::string formed_url = util::replaceTokens(url, [&](const std::string &token) -> std::string {
- if (token == "z") return std::to_string(normalized_id.z);
- if (token == "x") return std::to_string(normalized_id.x);
- if (token == "y") return std::to_string(normalized_id.y);
- if (token == "ratio") return (map.getState().getPixelRatio() > 1.0 ? "@2x" : "");
- return "";
- });
-
- if (type == SourceType::Vector) {
- new_tile.data = std::make_shared<VectorTileData>(normalized_id, map, formed_url);
- } else if (type == SourceType::Raster) {
- new_tile.data = std::make_shared<RasterTileData>(normalized_id, map, formed_url);
+ if (info.type == SourceType::Vector) {
+ new_tile.data = std::make_shared<VectorTileData>(normalized_id, map, info);
+ } else if (info.type == SourceType::Raster) {
+ new_tile.data = std::make_shared<RasterTileData>(normalized_id, map, info);
} else {
throw std::runtime_error("source type not implemented");
}
@@ -232,14 +216,14 @@ bool Source::updateTiles(Map &map) {
// Figure out what tiles we need to load
int32_t clamped_zoom = map.getState().getIntegerZoom();
- if (clamped_zoom > max_zoom) clamped_zoom = max_zoom;
- if (clamped_zoom < min_zoom) clamped_zoom = min_zoom;
+ if (clamped_zoom > info.max_zoom) clamped_zoom = info.max_zoom;
+ if (clamped_zoom < info.min_zoom) clamped_zoom = info.min_zoom;
int32_t max_covering_zoom = clamped_zoom + 1;
- if (max_covering_zoom > max_zoom) max_covering_zoom = max_zoom;
+ if (max_covering_zoom > info.max_zoom) max_covering_zoom = info.max_zoom;
int32_t min_covering_zoom = clamped_zoom - 10;
- if (min_covering_zoom < min_zoom) min_covering_zoom = min_zoom;
+ if (min_covering_zoom < info.min_zoom) min_covering_zoom = info.min_zoom;
// Map four viewport corners to pixel coordinates
box box = map.getState().cornersToBox(clamped_zoom);
@@ -379,7 +363,7 @@ void _scanTriangle(const mbgl::vec2<double> a, const mbgl::vec2<double> b, const
}
double Source::getZoom(const TransformState &state) const {
- double offset = log(util::tileSize / tile_size) / log(2);
+ double offset = log(util::tileSize / info.tile_size) / log(2);
offset += (state.getPixelRatio() > 1.0 ? 1 :0);
return state.getZoom() + offset;
}
@@ -387,7 +371,7 @@ double Source::getZoom(const TransformState &state) const {
std::forward_list<mbgl::Tile::ID> Source::covering_tiles(const TransformState &state, int32_t clamped_zoom, const box& points) {
int32_t dim = std::pow(2, clamped_zoom);
std::forward_list<mbgl::Tile::ID> tiles;
- bool is_raster = (type == SourceType::Raster);
+ bool is_raster = (info.type == SourceType::Raster);
double search_zoom = getZoom(state);
auto scanLine = [&tiles, clamped_zoom, is_raster, search_zoom](int32_t x0, int32_t x1, int32_t y, int32_t ymax) {
diff --git a/src/map/sprite.cpp b/src/map/sprite.cpp
index fd8a4ec7b5..f396fec07d 100644
--- a/src/map/sprite.cpp
+++ b/src/map/sprite.cpp
@@ -5,6 +5,7 @@
#include <string>
#include <mbgl/platform/platform.hpp>
+#include <mbgl/util/filesource.hpp>
#include <mbgl/util/uv.hpp>
#include <mbgl/util/std.hpp>
@@ -20,76 +21,98 @@ SpritePosition::SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t
pixelRatio(pixelRatio) {
}
-Sprite::Sprite(Map &map, float pixelRatio)
- : pixelRatio(pixelRatio),
+std::shared_ptr<Sprite> Sprite::Create(const std::string& base_url, float pixelRatio, const std::shared_ptr<FileSource> &fileSource) {
+ std::shared_ptr<Sprite> sprite(std::make_shared<Sprite>(Key(), base_url, pixelRatio));
+ sprite->load(fileSource);
+ return sprite;
+}
+
+Sprite::Sprite(const Key &, const std::string& base_url, float pixelRatio)
+ : valid(base_url.length() > 0),
+ pixelRatio(pixelRatio),
+ spriteURL(base_url + (pixelRatio > 1 ? "@2x" : "") + ".png"),
+ jsonURL(base_url + (pixelRatio > 1 ? "@2x" : "") + ".json"),
raster(),
- map(map),
- loaded(false) {
+ loadedImage(false),
+ loadedJSON(false),
+ future(promise.get_future()) {
+}
+
+void Sprite::waitUntilLoaded() const {
+ future.wait();
+}
+
+Sprite::operator bool() const {
+ return valid && isLoaded() && !pos.empty();
}
-void Sprite::load(const std::string& base_url) {
- loaded = false;
- url = base_url;
- std::shared_ptr<Sprite> sprite = shared_from_this();
- std::string suffix = (pixelRatio > 1 ? "@2x" : "");
+// Note: This is a separate function that must be called exactly once after creation
+// The reason this isn't part of the constructor is that calling shared_from_this() in
+// the constructor fails.
+void Sprite::load(const std::shared_ptr<FileSource> &fileSource) {
+ if (!valid) {
+ // Treat a non-existent sprite as a successfully loaded empty sprite.
+ loadedImage = true;
+ loadedJSON = true;
+ promise.set_value();
+ return;
+ }
+
+ std::shared_ptr<Sprite> sprite = shared_from_this();
- platform::request_http(base_url + suffix + ".json", [sprite](platform::Response *res) {
+ fileSource->load(ResourceType::JSON, jsonURL, [sprite](platform::Response *res) {
if (res->code == 200) {
sprite->body.swap(res->body);
- sprite->asyncParseJSON();
+ sprite->parseJSON();
+ sprite->complete();
} else {
- fprintf(stderr, "failed to load sprite info\n");
- fprintf(stderr, "error %d: %s\n", res->code, res->error_message.c_str());
+ Log::Warning(Event::Sprite, "Failed to load sprite info: Error %d: %s", res->code, res->error_message.c_str());
+ if (!sprite->future.valid()) {
+ sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res->error_message)));
+ }
}
- }, map.getLoop());
+ });
- platform::request_http(base_url + suffix + ".png", [sprite](platform::Response *res) {
+ fileSource->load(ResourceType::Image, spriteURL, [sprite](platform::Response *res) {
if (res->code == 200) {
- sprite->image.swap(res->body);
- sprite->asyncParseImage();
+ sprite->image.swap(res->body);
+ sprite->parseImage();
+ sprite->complete();
} else {
- fprintf(stderr, "failed to load sprite image\n");
- fprintf(stderr, "error %d: %s\n", res->code, res->error_message.c_str());
+ Log::Warning(Event::Sprite, "Failed to load sprite image: Error %d: %s", res->code, res->error_message.c_str());
+ if (!sprite->future.valid()) {
+ sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res->error_message)));
+ }
}
- }, map.getLoop());
+ });
}
-void Sprite::complete(std::shared_ptr<Sprite> &sprite) {
- const bool raster = bool(sprite->raster);
- const bool json = bool(sprite->pos.size());
- if (raster && json && !sprite->loaded) {
- sprite->loaded = true;
- sprite->map.update();
- Log::Info(Event::Sprite, "loaded %s", sprite->url.c_str());
+void Sprite::complete() {
+ if (loadedImage && loadedJSON) {
+ Log::Info(Event::Sprite, "loaded %s", spriteURL.c_str());
+ promise.set_value();
}
}
bool Sprite::isLoaded() const {
- return loaded;
+ return loadedImage && loadedJSON;
}
-void Sprite::asyncParseImage() {
- new uv::work<std::shared_ptr<Sprite>>(map.getLoop(), parseImage, complete, shared_from_this());
+void Sprite::parseImage() {
+ raster = std::make_unique<util::Image>(image);
+ image.clear();
+ loadedImage = true;
}
-void Sprite::asyncParseJSON() {
- new uv::work<std::shared_ptr<Sprite>>(map.getLoop(), parseJSON, complete, shared_from_this());
-}
-
-void Sprite::parseImage(std::shared_ptr<Sprite> &sprite) {
- sprite->raster = std::make_unique<util::Image>(sprite->image);
- sprite->image.clear();
-}
-
-void Sprite::parseJSON(std::shared_ptr<Sprite> &sprite) {
+void Sprite::parseJSON() {
rapidjson::Document d;
- d.Parse<0>(sprite->body.c_str());
- sprite->body.clear();
-
- if (d.IsObject()) {
- std::unordered_map<std::string, SpritePosition> pos;
+ d.Parse<0>(body.c_str());
+ body.clear();
+ if (d.HasParseError()) {
+ Log::Warning(Event::Sprite, "sprite JSON is invalid");
+ } else if (d.IsObject()) {
for (rapidjson::Value::ConstMemberIterator itr = d.MemberBegin(); itr != d.MemberEnd(); ++itr) {
const std::string& name = itr->name.GetString();
const rapidjson::Value& value = itr->value;
@@ -109,9 +132,11 @@ void Sprite::parseJSON(std::shared_ptr<Sprite> &sprite) {
pos.emplace(name, SpritePosition { x, y, width, height, pixelRatio });
}
}
-
- sprite->pos.swap(pos);
+ } else {
+ Log::Warning(Event::Sprite, "sprite JSON root is not an object");
}
+
+ loadedJSON = true;
}
const SpritePosition &Sprite::getSpritePosition(const std::string& name) const {
diff --git a/src/map/tile_data.cpp b/src/map/tile_data.cpp
index 82f8fdedfc..a94eb00fbf 100644
--- a/src/map/tile_data.cpp
+++ b/src/map/tile_data.cpp
@@ -1,15 +1,25 @@
#include <mbgl/map/tile_data.hpp>
#include <mbgl/map/map.hpp>
+#include <mbgl/style/style_source.hpp>
+#include <mbgl/util/token.hpp>
#include <mbgl/util/string.hpp>
+#include <mbgl/util/filesource.hpp>
using namespace mbgl;
-TileData::TileData(Tile::ID id, Map &map, const std::string url)
+TileData::TileData(Tile::ID id, Map &map, const SourceInfo &source)
: id(id),
state(State::initial),
map(map),
- url(url),
+ source(source),
+ url(util::replaceTokens(source.url, [&](const std::string &token) -> std::string {
+ if (token == "z") return std::to_string(id.z);
+ if (token == "x") return std::to_string(id.x);
+ if (token == "y") return std::to_string(id.y);
+ if (token == "ratio") return (map.getState().getPixelRatio() > 1.0 ? "@2x" : "");
+ return "";
+ })),
debugBucket(debugFontBuffer) {
// Initialize tile debug coordinates
const std::string str = util::sprintf<32>("%d/%d/%d", id.z, id.x, id.y);
@@ -29,7 +39,7 @@ void TileData::request() {
// Note: Somehow this feels slower than the change to request_http()
std::weak_ptr<TileData> weak_tile = shared_from_this();
- req = platform::request_http(url, [weak_tile](platform::Response *res) {
+ map.getFileSource()->load(ResourceType::Tile, url, [weak_tile](platform::Response *res) {
std::shared_ptr<TileData> tile = weak_tile.lock();
if (!tile || tile->state == State::obsolete) {
// noop. Tile is obsolete and we're now just waiting for the refcount
@@ -46,7 +56,7 @@ void TileData::request() {
fprintf(stderr, "[%s] tile loading failed: %d, %s\n", tile->url.c_str(), res->code, res->error_message.c_str());
#endif
}
- }, map.getLoop());
+ });
}
void TileData::cancel() {
diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp
index 8af61c6aab..97b071a163 100644
--- a/src/map/tile_parser.cpp
+++ b/src/map/tile_parser.cpp
@@ -6,8 +6,7 @@
#include <mbgl/style/style_layer_group.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/renderer/line_bucket.hpp>
-#include <mbgl/renderer/icon_bucket.hpp>
-#include <mbgl/renderer/text_bucket.hpp>
+#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
#include <mbgl/util/raster.hpp>
#include <mbgl/util/constants.hpp>
@@ -35,14 +34,16 @@ TileParser::TileParser(const std::string &data, VectorTileData &tile,
const std::shared_ptr<const Style> &style,
const std::shared_ptr<GlyphAtlas> &glyphAtlas,
const std::shared_ptr<GlyphStore> &glyphStore,
- const std::shared_ptr<SpriteAtlas> &spriteAtlas)
+ const std::shared_ptr<SpriteAtlas> &spriteAtlas,
+ const std::shared_ptr<Sprite> &sprite)
: vector_data(pbf((const uint8_t *)data.data(), data.size())),
tile(tile),
style(style),
glyphAtlas(glyphAtlas),
glyphStore(glyphStore),
spriteAtlas(spriteAtlas),
- placement(tile.id.z) {
+ sprite(sprite),
+ collision(tile.id.z, 4096, tile.source.tile_size, tile.depth) {
}
void TileParser::parse() {
@@ -51,21 +52,6 @@ void TileParser::parse() {
bool TileParser::obsolete() const { return tile.state == TileData::State::obsolete; }
-void TileParser::addGlyph(uint64_t tileid, const std::string stackname,
- const std::u32string &string, const FontStack &fontStack,
- GlyphAtlas &glyphAtlas, GlyphPositions &face) {
- const std::map<uint32_t, SDFGlyph> &sdfs = fontStack.getSDFs();
- // Loop through all characters and add glyph to atlas, positions.
- for (uint32_t chr : string) {
- auto sdf_it = sdfs.find(chr);
- if (sdf_it != sdfs.end()) {
- const SDFGlyph& sdf = sdf_it->second;
- const Rect<uint16_t> rect = glyphAtlas.addGlyph(tileid, stackname, sdf);
- face.emplace(chr, Glyph{rect, sdf.metrics});
- }
- }
-}
-
void TileParser::parseStyleLayers(std::shared_ptr<StyleLayerGroup> group) {
if (!group) {
return;
@@ -108,6 +94,10 @@ std::unique_ptr<Bucket> TileParser::createBucket(std::shared_ptr<StyleBucket> bu
return nullptr;
}
+ // Skip this bucket if we are to not render this
+ if (tile.id.z < std::floor(bucket_desc->min_zoom) && std::floor(bucket_desc->min_zoom) < tile.source.max_zoom) return nullptr;
+ if (tile.id.z >= std::ceil(bucket_desc->max_zoom)) return nullptr;
+
auto layer_it = vector_data.layers.find(bucket_desc->source_layer);
if (layer_it != vector_data.layers.end()) {
const VectorTileLayer &layer = layer_it->second;
@@ -115,10 +105,8 @@ std::unique_ptr<Bucket> TileParser::createBucket(std::shared_ptr<StyleBucket> bu
return createFillBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketFill>());
} else if (bucket_desc->render.is<StyleBucketLine>()) {
return createLineBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketLine>());
- } else if (bucket_desc->render.is<StyleBucketIcon>()) {
- return createIconBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketIcon>());
- } else if (bucket_desc->render.is<StyleBucketText>()) {
- return createTextBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketText>());
+ } else if (bucket_desc->render.is<StyleBucketSymbol>()) {
+ return createSymbolBucket(layer, bucket_desc->filter, bucket_desc->render.get<StyleBucketSymbol>());
} else if (bucket_desc->render.is<StyleBucketRaster>()) {
return nullptr;
} else {
@@ -136,7 +124,7 @@ std::unique_ptr<Bucket> TileParser::createBucket(std::shared_ptr<StyleBucket> bu
}
template <class Bucket>
-void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter) {
+void TileParser::addBucketGeometries(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter) {
FilteredVectorTileLayer filtered_layer(layer, filter);
for (pbf feature : filtered_layer) {
if (obsolete())
@@ -153,103 +141,20 @@ void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer,
}
}
-template <class Bucket, typename... Args>
-void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter, Args&& ...args) {
- FilteredVectorTileLayer filtered_layer(layer, filter);
- for (const pbf &feature_pbf : filtered_layer) {
- if (obsolete()) {
- return;
- }
- bucket->addFeature({feature_pbf, layer}, std::forward<Args>(args)...);
- }
-}
-
-
std::unique_ptr<Bucket> TileParser::createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill) {
std::unique_ptr<FillBucket> bucket = std::make_unique<FillBucket>(tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer, fill);
- addBucketFeatures(bucket, layer, filter);
+ addBucketGeometries(bucket, layer, filter);
return obsolete() ? nullptr : std::move(bucket);
}
std::unique_ptr<Bucket> TileParser::createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line) {
std::unique_ptr<LineBucket> bucket = std::make_unique<LineBucket>(tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer, line);
- addBucketFeatures(bucket, layer, filter);
+ addBucketGeometries(bucket, layer, filter);
return obsolete() ? nullptr : std::move(bucket);
}
-std::unique_ptr<Bucket> TileParser::createIconBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketIcon &icon) {
- std::unique_ptr<IconBucket> bucket = std::make_unique<IconBucket>(tile.iconVertexBuffer, icon);
- addBucketFeatures(bucket, layer, filter, *spriteAtlas);
+std::unique_ptr<Bucket> TileParser::createSymbolBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketSymbol &symbol) {
+ std::unique_ptr<SymbolBucket> bucket = std::make_unique<SymbolBucket>(symbol, collision);
+ bucket->addFeatures(layer, filter, tile.id, *spriteAtlas, *sprite, *glyphAtlas, *glyphStore);
return obsolete() ? nullptr : std::move(bucket);
}
-
-std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketText &text) {
-
- // Make sure that we always have a valid glyph store. If this is not set, the stylesheet
- // doesn't specify a glyph URL.
- if (!glyphStore) {
- return nullptr;
- }
-
- const StyleBucketText &properties = text;
-
- std::unique_ptr<TextBucket> bucket = std::make_unique<TextBucket>(
- tile.textVertexBuffer, tile.triangleElementsBuffer, properties, placement);
-
- util::utf8_to_utf32 ucs4conv;
-
- std::vector<std::pair<std::u32string, pbf>> labels;
-
- // Determine and load glyph ranges
- {
- std::set<GlyphRange> ranges;
-
- FilteredVectorTileLayer filtered_layer(layer, filter);
- for (const pbf &feature_pbf : filtered_layer) {
- if (obsolete())
- return nullptr;
- VectorTileFeature feature{feature_pbf, layer};
-
- std::string u8string = util::replaceTokens(properties.field, feature.properties);
-
- auto& convert = std::use_facet<std::ctype<char>>(std::locale());
- if (properties.transform == TextTransformType::Uppercase) {
- convert.toupper(&u8string[0], &u8string[0] + u8string.size());
- } else if (properties.transform == TextTransformType::Lowercase) {
- convert.tolower(&u8string[0], &u8string[0] + u8string.size());
- }
-
- std::u32string string = ucs4conv.convert(u8string);
-
- // Loop through all characters of this text and collect unique codepoints.
- for (char32_t chr : string) {
- ranges.insert(getGlyphRange(chr));
- }
-
- labels.emplace_back(string, feature.geometry);
- }
-
- glyphStore->waitForGlyphRanges(properties.font, ranges);
- }
-
- // Create a copy!
- const FontStack &fontStack = glyphStore->getFontStack(properties.font);
- GlyphPositions face;
-
- // Shape and place all labels.
- for (const std::pair<std::u32string, pbf> &label : labels) {
-
- // Shape labels.
- const Shaping shaping = fontStack.getShaping(label.first, properties.max_width,
- properties.line_height, properties.alignment,
- properties.vertical_alignment, properties.letter_spacing);
-
- // Place labels.
- addGlyph(tile.id.to_uint64(), properties.font, label.first, fontStack, *glyphAtlas,
- face);
-
- bucket->addFeature(label.second, face, shaping);
- }
-
- return std::move(bucket);
-}
diff --git a/src/map/transform.cpp b/src/map/transform.cpp
index ccf92f974b..6338df6a48 100644
--- a/src/map/transform.cpp
+++ b/src/map/transform.cpp
@@ -1,9 +1,11 @@
#include <mbgl/map/transform.hpp>
+#include <mbgl/map/view.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/time.hpp>
+#include <mbgl/util/transition.hpp>
#include <mbgl/platform/platform.hpp>
#include <cstdio>
@@ -96,8 +98,8 @@ void Transform::setLonLat(const double lon, const double lat, const timestamp du
uv::writelock lock(mtx);
const double f = std::fmin(std::fmax(std::sin(D2R * lat), -0.9999), 0.9999);
- double xn = -std::round(lon * Bc);
- double yn = std::round(0.5 * Cc * std::log((1 + f) / (1 - f)));
+ double xn = -lon * Bc;
+ double yn = 0.5 * Cc * std::log((1 + f) / (1 - f));
_setScaleXY(current.scale, xn, yn, duration);
}
@@ -109,13 +111,12 @@ void Transform::setLonLatZoom(const double lon, const double lat, const double z
double new_scale = std::pow(2.0, zoom);
const double s = new_scale * util::tileSize;
- zc = s / 2;
Bc = s / 360;
Cc = s / (2 * M_PI);
const double f = std::fmin(std::fmax(std::sin(D2R * lat), -0.9999), 0.9999);
- double xn = -std::round(lon * Bc);
- double yn = std::round(0.5 * Cc * log((1 + f) / (1 - f)));
+ double xn = -lon * Bc;
+ double yn = 0.5 * Cc * log((1 + f) / (1 - f));
_setScaleXY(new_scale, xn, yn, duration);
}
@@ -307,7 +308,6 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl
}
const double s = final.scale * util::tileSize;
- zc = s / 2;
Bc = s / 360;
Cc = s / (2 * M_PI);
diff --git a/src/map/vector_tile_data.cpp b/src/map/vector_tile_data.cpp
index 7d0e0fb5a8..2bf339b65f 100644
--- a/src/map/vector_tile_data.cpp
+++ b/src/map/vector_tile_data.cpp
@@ -1,13 +1,16 @@
#include <mbgl/map/vector_tile_data.hpp>
+#include <mbgl/map/tile_parser.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_bucket.hpp>
+#include <mbgl/geometry/glyph_atlas.hpp>
using namespace mbgl;
-VectorTileData::VectorTileData(Tile::ID id, Map &map, const std::string url)
- : TileData(id, map, url) {
+VectorTileData::VectorTileData(Tile::ID id, Map &map, const SourceInfo &source)
+ : TileData(id, map, source),
+ depth(id.z >= source.max_zoom ? map.getMaxZoom() - id.z : 1) {
}
VectorTileData::~VectorTileData() {
@@ -18,7 +21,8 @@ VectorTileData::~VectorTileData() {
}
void VectorTileData::beforeParse() {
- parser = std::make_unique<TileParser>(data, *this, map.getStyle(), map.getGlyphAtlas(), map.getGlyphStore(), map.getSpriteAtlas());
+
+ parser = std::make_unique<TileParser>(data, *this, map.getStyle(), map.getGlyphAtlas(), map.getGlyphStore(), map.getSpriteAtlas(), map.getSprite());
}
void VectorTileData::parse() {
@@ -63,7 +67,7 @@ bool VectorTileData::hasData(std::shared_ptr<StyleLayer> layer_desc) const {
auto databucket_it = buckets.find(layer_desc->bucket->name);
if (databucket_it != buckets.end()) {
assert(databucket_it->second);
- return databucket_it->second->hasData();
+ return databucket_it->second->hasData();
}
}
return false;
diff --git a/src/renderer/debug_bucket.cpp b/src/renderer/debug_bucket.cpp
index c9a68e2efb..e51dd75b1e 100644
--- a/src/renderer/debug_bucket.cpp
+++ b/src/renderer/debug_bucket.cpp
@@ -14,7 +14,7 @@ DebugBucket::DebugBucket(DebugFontBuffer& fontBuffer)
: fontBuffer(fontBuffer) {
}
-void DebugBucket::render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& /*id*/) {
+void DebugBucket::render(Painter& painter, std::shared_ptr<StyleLayer> /*layer_desc*/, const Tile::ID& /*id*/) {
painter.renderDebugText(*this);
}
diff --git a/src/renderer/icon_bucket.cpp b/src/renderer/icon_bucket.cpp
deleted file mode 100644
index af988fee80..0000000000
--- a/src/renderer/icon_bucket.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#include <mbgl/renderer/icon_bucket.hpp>
-#include <mbgl/geometry/icon_buffer.hpp>
-#include <mbgl/geometry/elements_buffer.hpp>
-#include <mbgl/geometry/geometry.hpp>
-#include <mbgl/geometry/sprite_atlas.hpp>
-
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/style/style.hpp>
-#include <mbgl/map/sprite.hpp>
-#include <mbgl/map/vector_tile.hpp>
-
-#include <mbgl/platform/gl.hpp>
-#include <mbgl/util/constants.hpp>
-#include <mbgl/util/token.hpp>
-
-#include <cassert>
-
-struct geometry_too_long_exception : std::exception {};
-
-using namespace mbgl;
-
-IconBucket::IconBucket(IconVertexBuffer& vertexBuffer,
- const StyleBucketIcon& properties)
- : properties(properties),
- vertexBuffer(vertexBuffer),
- vertex_start(vertexBuffer.index()) {
-}
-
-void IconBucket::addFeature(const VectorTileFeature &feature, SpriteAtlas &sprite_atlas) {
- std::string field;
-
- if (properties.icon.size()) {
- field = util::replaceTokens(properties.icon, feature.properties);
- }
-
- if (!field.size()) {
- field = "<circle>";
- }
-
- const Rect<uint16_t> rect = sprite_atlas.getIcon(properties.size, field);
- const uint16_t tx = rect.x + rect.w / 2;
- const uint16_t ty = rect.y + rect.h / 2;
-
- Geometry::command cmd;
- pbf geom = feature.geometry;
- Geometry geometry(geom);
- int32_t x, y;
- while ((cmd = geometry.next(x, y)) != Geometry::end) {
- if (cmd == Geometry::move_to) {
- vertexBuffer.add(x, y, tx, ty);
- } else {
- if (debug::tileParseWarnings) {
- fprintf(stderr, "[WARNING] other command than move_to in icon geometry\n");
- }
- }
- }
-
- vertex_end = vertexBuffer.index();
-}
-
-void IconBucket::render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) {
- painter.renderIcon(*this, layer_desc, id);
-}
-
-bool IconBucket::hasData() const {
- return vertex_end > 0;
-}
-
-void IconBucket::drawIcons(IconShader& shader) {
- char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize);
- array.bind(shader, vertexBuffer, vertex_index);
- glDrawArrays(GL_POINTS, 0, (GLsizei)(vertex_end - vertex_start));
-}
-
-void IconBucket::drawIcons(DotShader& shader) {
- char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize);
- array.bind(shader, vertexBuffer, vertex_index);
- glDrawArrays(GL_POINTS, 0, (GLsizei)(vertex_end - vertex_start));
-}
diff --git a/src/renderer/line_bucket.cpp b/src/renderer/line_bucket.cpp
index 44fe784b1a..2e04820e42 100644
--- a/src/renderer/line_bucket.cpp
+++ b/src/renderer/line_bucket.cpp
@@ -80,7 +80,7 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
CapType beginCap = properties.cap;
CapType endCap = closed ? CapType::Butt : properties.cap;
- JoinType currentJoin = JoinType::None;
+ JoinType currentJoin = JoinType::Miter;
Coordinate currentVertex = Coordinate::null(),
prevVertex = Coordinate::null(),
diff --git a/src/renderer/painter.cpp b/src/renderer/painter.cpp
index a323b0582a..e6977171a4 100644
--- a/src/renderer/painter.cpp
+++ b/src/renderer/painter.cpp
@@ -1,5 +1,6 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/map/map.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/string.hpp>
@@ -205,21 +206,3 @@ const mat4 &Painter::translatedMatrix(const std::array<float, 2> &translation, c
return vtxMatrix;
}
}
-
-void Painter::renderMatte() {
- gl::group group("matte");
- glDisable(GL_DEPTH_TEST);
- glStencilFunc(GL_EQUAL, 0x0, 0xFF);
-
- Color matte = {{ 0, 0, 0, 1 }};
-
- useProgram(plainShader->program);
- plainShader->setMatrix(nativeMatrix);
-
- // Draw the clipping mask
- matteArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0));
- plainShader->setColor(matte);
- glDrawArrays(GL_TRIANGLES, 0, (GLsizei)tileStencilBuffer.index());
-
- glEnable(GL_DEPTH_TEST);
-}
diff --git a/src/renderer/painter_fill.cpp b/src/renderer/painter_fill.cpp
index f78f006df0..29d77e05d9 100644
--- a/src/renderer/painter_fill.cpp
+++ b/src/renderer/painter_fill.cpp
@@ -1,5 +1,6 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/map/sprite.hpp>
@@ -70,10 +71,10 @@ void Painter::renderFill(FillBucket& bucket, const FillProperties& properties, c
}
if ((fill_color[3] >= 1.0f) == (pass == Opaque)) {
- const std::shared_ptr<Sprite> &sprite = map.getStyle()->sprite;
+ Sprite &sprite = *map.getSprite();
if (properties.image.size() && sprite) {
SpriteAtlas &spriteAtlas = *map.getSpriteAtlas();
- Rect<uint16_t> imagePos = spriteAtlas.getImage(properties.image, *sprite);
+ Rect<uint16_t> imagePos = spriteAtlas.getImage(properties.image, sprite);
float factor = 8.0 / std::pow(2, map.getState().getIntegerZoom() - id.z);
diff --git a/src/renderer/painter_framebuffers.cpp b/src/renderer/painter_framebuffers.cpp
index 83ad189877..f221b884ce 100644
--- a/src/renderer/painter_framebuffers.cpp
+++ b/src/renderer/painter_framebuffers.cpp
@@ -1,6 +1,7 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/map/map.hpp>
+#include <mbgl/map/view.hpp>
#include <mbgl/util/clip_ids.hpp>
using namespace mbgl;
diff --git a/src/renderer/painter_icon.cpp b/src/renderer/painter_icon.cpp
deleted file mode 100644
index 158030df19..0000000000
--- a/src/renderer/painter_icon.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/icon_bucket.hpp>
-#include <mbgl/map/map.hpp>
-#include <mbgl/map/sprite.hpp>
-#include <mbgl/style/style_layer.hpp>
-#include <mbgl/geometry/sprite_atlas.hpp>
-#include <mbgl/util/math.hpp>
-
-using namespace mbgl;
-
-void Painter::renderIcon(IconBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) {
- // Abort early.
- if (!bucket.hasData()) return;
- if (pass == Opaque) return;
-
- const IconProperties &properties = layer_desc->getProperties<IconProperties>();
-
-// TODO: when translating icon, are we doing this in the bucket already?
-// const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
-
- SpriteAtlas &spriteAtlas = *map.getSpriteAtlas();
-
- useProgram(iconShader->program);
- iconShader->setMatrix(matrix);
-// TODO: update
- iconShader->setColor({{ 1, 1, 1, 1 }});
- iconShader->setImage(0);
- iconShader->setRatio(map.getState().getPixelRatio());
- iconShader->setDimension({{
- spriteAtlas.getTextureWidth(),
- spriteAtlas.getTextureHeight(),
- }});
-
- spriteAtlas.bind(map.getState().isChanging());
-
- const float iconSize = bucket.properties.size * map.getState().getPixelRatio();
- iconShader->setSize(iconSize);
-#ifndef GL_ES_VERSION_2_0
- glPointSize(iconSize);
- glEnable(GL_POINT_SPRITE);
-#endif
-
- glDepthRange(strata, 1.0f);
- bucket.drawIcons(*iconShader);
-}
diff --git a/src/renderer/painter_line.cpp b/src/renderer/painter_line.cpp
index 00b3a48474..dc09f58951 100644
--- a/src/renderer/painter_line.cpp
+++ b/src/renderer/painter_line.cpp
@@ -14,11 +14,13 @@ void Painter::renderLine(LineBucket& bucket, std::shared_ptr<StyleLayer> layer_d
float width = properties.width;
float offset = properties.offset / 2;
+ float antialiasing = 1 / map.getState().getPixelRatio();
+ float blur = properties.blur + antialiasing;
// These are the radii of the line. We are limiting it to 16, which will result
// in a point size of 64 on retina.
- float inset = std::fmin((std::fmax(-1, offset - width / 2 - 0.5) + 1), 16.0f);
- float outset = std::fmin(offset + width / 2 + 0.5, 16.0f);
+ float inset = std::fmin((std::fmax(-1, offset - width / 2 - antialiasing / 2) + 1), 16.0f);
+ float outset = std::fmin(offset + width / 2 + antialiasing / 2, 16.0f);
Color color = properties.color;
color[0] *= properties.opacity;
@@ -80,6 +82,7 @@ void Painter::renderLine(LineBucket& bucket, std::shared_ptr<StyleLayer> layer_d
lineShader->setDashArray({{ dash_length, dash_gap }});
lineShader->setLineWidth({{ outset, inset }});
lineShader->setRatio(map.getState().getPixelRatio());
+ lineShader->setBlur(blur);
lineShader->setColor(color);
bucket.drawLines(*lineShader);
}
diff --git a/src/renderer/painter_prerender.cpp b/src/renderer/painter_prerender.cpp
index ea461ca5d2..5d61b95535 100644
--- a/src/renderer/painter_prerender.cpp
+++ b/src/renderer/painter_prerender.cpp
@@ -17,7 +17,7 @@ void Painter::preparePrerender(PrerenderedTexture &texture) {
glViewport(0, 0, texture.properties.size, texture.properties.size);
}
-void Painter::finishPrerender(PrerenderedTexture &texture) {
+void Painter::finishPrerender(PrerenderedTexture &/*texture*/) {
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
diff --git a/src/renderer/painter_raster.cpp b/src/renderer/painter_raster.cpp
index 228d609aaa..ef2eab2a6c 100644
--- a/src/renderer/painter_raster.cpp
+++ b/src/renderer/painter_raster.cpp
@@ -5,10 +5,10 @@
using namespace mbgl;
-void Painter::renderRaster(RasterBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& /*id*/) {
+void Painter::renderRaster(RasterBucket& bucket, std::shared_ptr<StyleLayer> /*layer_desc*/, const Tile::ID& /*id*/) {
if (pass == Translucent) return;
- const RasterProperties &properties = layer_desc->getProperties<RasterProperties>();
+ // const RasterProperties &properties = layer_desc->getProperties<RasterProperties>();
depthMask(false);
diff --git a/src/renderer/painter_symbol.cpp b/src/renderer/painter_symbol.cpp
new file mode 100644
index 0000000000..a2238a3544
--- /dev/null
+++ b/src/renderer/painter_symbol.cpp
@@ -0,0 +1,217 @@
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/renderer/symbol_bucket.hpp>
+#include <mbgl/style/style_layer.hpp>
+#include <mbgl/geometry/glyph_atlas.hpp>
+#include <mbgl/geometry/sprite_atlas.hpp>
+#include <mbgl/map/map.hpp>
+#include <mbgl/util/math.hpp>
+#include <cmath>
+
+namespace mbgl {
+
+void Painter::renderSymbol(SymbolBucket &bucket, std::shared_ptr<StyleLayer> layer_desc,
+ const Tile::ID &/*id*/) {
+ // Abort early.
+ if (pass == Opaque) {
+ return;
+ }
+
+ const SymbolProperties &properties = layer_desc->getProperties<SymbolProperties>();
+
+
+ if (bucket.hasTextData()) {
+ mat4 exMatrix;
+ matrix::copy(exMatrix, projMatrix);
+ if (bucket.properties.placement == PlacementType::Line) {
+ matrix::rotate_z(exMatrix, exMatrix, map.getState().getAngle());
+ }
+
+ // If layerStyle.size > bucket.info.fontSize then labels may collide
+ float fontSize = std::fmin(properties.text.size, bucket.properties.text.max_size);
+ matrix::scale(exMatrix, exMatrix, fontSize / 24.0f, fontSize / 24.0f, 1.0f);
+
+ useProgram(textShader->program);
+ textShader->setMatrix(matrix);
+ textShader->setExtrudeMatrix(exMatrix);
+
+ GlyphAtlas &glyphAtlas = *map.getGlyphAtlas();
+ glyphAtlas.bind();
+ textShader->setTextureSize(
+ {{static_cast<float>(glyphAtlas.width), static_cast<float>(glyphAtlas.height)}});
+
+ // Convert the -pi..pi to an int8 range.
+ float angle = std::round((map.getState().getAngle()) / M_PI * 128);
+
+ // adjust min/max zooms for variable font sies
+ float zoomAdjust = log(fontSize / bucket.properties.text.max_size) / log(2);
+
+ textShader->setAngle((int32_t)(angle + 256) % 256);
+ textShader->setFlip(bucket.properties.placement == PlacementType::Line ? 1 : 0);
+ textShader->setZoom((map.getState().getNormalizedZoom() - zoomAdjust) *
+ 10); // current zoom level
+
+ // Label fading
+ const timestamp duration = 300_milliseconds;
+ const timestamp currentTime = util::now();
+
+ std::deque<FrameSnapshot> &history = frameHistory.history;
+
+ // Remove frames until only one is outside the duration, or until there are only three
+ while (history.size() > 3 && history[1].t + duration < currentTime) {
+ history.pop_front();
+ }
+
+ if (history[1].t + duration < currentTime) {
+ history[0].z = history[1].z;
+ }
+
+ assert("there should never be less than three frames in the history" &&
+ (history.size() >= 3));
+
+ // Find the range of zoom levels we want to fade between
+ float startingZ = history.front().z;
+ const FrameSnapshot lastFrame = history.back();
+ float endingZ = lastFrame.z;
+ float lowZ = std::fmin(startingZ, endingZ);
+ float highZ = std::fmax(startingZ, endingZ);
+
+ // Calculate the speed of zooming, and how far it would zoom in terms of zoom levels in one
+ // duration
+ float zoomDiff = endingZ - history[1].z, timeDiff = lastFrame.t - history[1].t;
+ float fadedist = zoomDiff / (timeDiff / duration);
+
+#if defined(DEBUG)
+// if (std::isnan(fadedist))
+// fprintf(stderr, "fadedist should never be NaN\n");
+#endif
+
+ // At end of a zoom when the zoom stops changing continue pretending to zoom at that speed
+ // bump is how much farther it would have been if it had continued zooming at the same rate
+ float bump = (currentTime - lastFrame.t) / duration * fadedist;
+
+ textShader->setFadeDist(fadedist * 10);
+ textShader->setMinFadeZoom(std::floor(lowZ * 10));
+ textShader->setMaxFadeZoom(std::floor(highZ * 10));
+ textShader->setFadeZoom((map.getState().getNormalizedZoom() + bump) * 10);
+
+ // This defines the gamma around the SDF cutoff value.
+ const float sdfGamma = 1.0f / 10.0f;
+
+ // Our signed distance fields are scaled so that 1 pixel is scaled to 32 pixels.
+ // Our cutoff between positive and negative values is hard coded to 64 (== 2 pixels).
+ // This means that our 6/8 of the value range lies outside the glyph outline.
+ const float sdfOffset = (256.0f - 64.0f) / 32.0f;
+
+ // Currently, all of our fonts are rendered with a font size of 24px.
+ const float sdfFontSize = 24.0f;
+
+ // The default gamma value has to be adjust for the current pixelratio so that we're not
+ // drawing
+ // blurry font on retina screens.
+ const float gamma = sdfGamma * sdfFontSize / fontSize / map.getState().getPixelRatio();
+
+ // We're drawing in the translucent pass which is bottom-to-top, so we need
+ // to draw the halo first.
+ if (properties.text.halo_color[3] > 0.0f) {
+ const float haloWidth = util::clamp(
+ (sdfOffset - properties.text.halo_width / (fontSize / sdfFontSize)) / 8.0f, 0.0f,
+ 1.0f);
+
+ if (properties.text.halo_blur != 0.0f) {
+ // We are converting the halo_blur value to current screen pixels.
+ // Then we're dividing it by two because the gamma value is added/subtracted into
+ // both
+ // directions in the shader, but the halo_blur describes the entire width of the
+ // blur.
+ // Note that this does *not* have to be adjusted for retina screens, because we want
+ // the
+ // same blur width when we explicitly specify one.
+ textShader->setGamma((properties.text.halo_blur / (fontSize / sdfFontSize)) / 8.0f /
+ 2.0f);
+ } else {
+ textShader->setGamma(sdfGamma);
+ }
+
+ if (properties.text.opacity < 1.0f) {
+ Color color = properties.text.halo_color;
+ color[0] *= properties.text.opacity;
+ color[1] *= properties.text.opacity;
+ color[2] *= properties.text.opacity;
+ color[3] *= properties.text.opacity;
+ textShader->setColor(color);
+ } else {
+ textShader->setColor(properties.text.halo_color);
+ }
+ textShader->setBuffer(haloWidth);
+ glDepthRange(strata, 1.0f);
+ bucket.drawGlyphs(*textShader);
+ }
+
+ if (properties.text.color[3] > 0.0f) {
+ // Then, we draw the text over the halo
+ textShader->setGamma(gamma);
+ if (properties.text.opacity < 1.0f) {
+ Color color = properties.text.color;
+ color[0] *= properties.text.opacity;
+ color[1] *= properties.text.opacity;
+ color[2] *= properties.text.opacity;
+ color[3] *= properties.text.opacity;
+ textShader->setColor(color);
+ } else {
+ textShader->setColor(properties.text.color);
+ }
+ textShader->setBuffer((256.0f - 64.0f) / 256.0f);
+ glDepthRange(strata + strata_epsilon, 1.0f);
+ bucket.drawGlyphs(*textShader);
+ }
+ }
+
+ if (bucket.hasIconData()) {
+ mat4 exMatrix;
+ matrix::copy(exMatrix, projMatrix);
+
+ const float angleOffset =
+ bucket.properties.icon.rotation_alignment == RotationAlignmentType::Map
+ ? map.getState().getAngle()
+ : 0;
+
+ if (angleOffset) {
+ matrix::rotate_z(exMatrix, exMatrix, angleOffset);
+ }
+
+ // If layerStyle.size > bucket.info.fontSize then labels may collide
+ const float fontSize = properties.icon.size != 0 ? properties.icon.size : bucket.properties.icon.max_size;
+ const float fontScale = fontSize / 1.0f;
+ matrix::scale(exMatrix, exMatrix, fontScale, fontScale, 1.0f);
+
+ useProgram(iconShader->program);
+ iconShader->setMatrix(matrix);
+ iconShader->setExtrudeMatrix(exMatrix);
+
+ SpriteAtlas &spriteAtlas = *map.getSpriteAtlas();
+ spriteAtlas.bind(map.getState().isChanging() || bucket.properties.placement == PlacementType::Line || angleOffset != 0 || fontScale != 1);
+ iconShader->setTextureSize(
+ {{static_cast<float>(spriteAtlas.getWidth()), static_cast<float>(spriteAtlas.getHeight())}});
+
+ // Convert the -pi..pi to an int8 range.
+ const float angle = std::round((map.getState().getAngle()) / M_PI * 128);
+
+ // adjust min/max zooms for variable font sies
+ float zoomAdjust = log(fontSize / bucket.properties.icon.max_size) / log(2);
+
+ iconShader->setAngle((int32_t)(angle + 256) % 256);
+ iconShader->setFlip(bucket.properties.placement == PlacementType::Line ? 1 : 0);
+ iconShader->setZoom((map.getState().getNormalizedZoom() - zoomAdjust) *
+ 10); // current zoom level
+
+ iconShader->setFadeDist(0 * 10);
+ iconShader->setMinFadeZoom(map.getState().getNormalizedZoom() * 10);
+ iconShader->setMaxFadeZoom(map.getState().getNormalizedZoom() * 10);
+ iconShader->setFadeZoom(map.getState().getNormalizedZoom() * 10);
+ iconShader->setOpacity(properties.icon.opacity);
+
+ glDepthRange(strata, 1.0f);
+ bucket.drawIcons(*iconShader);
+ }
+}
+}
diff --git a/src/renderer/painter_text.cpp b/src/renderer/painter_text.cpp
deleted file mode 100644
index 54fa1a7371..0000000000
--- a/src/renderer/painter_text.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/renderer/text_bucket.hpp>
-#include <mbgl/style/style_layer.hpp>
-#include <mbgl/map/map.hpp>
-#include <mbgl/util/math.hpp>
-#include <cmath>
-
-using namespace mbgl;
-
-void Painter::renderText(TextBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id) {
- // Abort early.
- if (pass == Opaque) return;
- if (!bucket.hasData()) return;
-
- const TextProperties &properties = layer_desc->getProperties<TextProperties>();
-
- mat4 exMatrix;
- matrix::copy(exMatrix, projMatrix);
- if (bucket.properties.path == TextPathType::Curve) {
- matrix::rotate_z(exMatrix, exMatrix, map.getState().getAngle());
- }
-
- // If layerStyle.size > bucket.info.fontSize then labels may collide
- float fontSize = std::fmin(properties.size, bucket.properties.max_size);
- matrix::scale(exMatrix, exMatrix, fontSize / 24.0f, fontSize / 24.0f, 1.0f);
-
-// TODO: figure out whether we actually need to account for this while painting; we might already have
-// done this during label placement.
-// const mat4 &vtxMatrix = translatedMatrix(properties.translate, id, properties.translateAnchor);
-
- useProgram(textShader->program);
- textShader->setMatrix(matrix);
- textShader->setExtrudeMatrix(exMatrix);
-
- GlyphAtlas &glyphAtlas = *map.getGlyphAtlas();
- glyphAtlas.bind();
- textShader->setTextureSize({{static_cast<float>(glyphAtlas.width),
- static_cast<float>(glyphAtlas.height)}});
-
- // Convert the -pi..pi to an int8 range.
- float angle = std::round((map.getState().getAngle()) / M_PI * 128);
-
- // adjust min/max zooms for variable font sies
- float zoomAdjust = log(fontSize / bucket.properties.max_size) / log(2);
-
- textShader->setAngle((int32_t)(angle + 256) % 256);
- textShader->setFlip(bucket.properties.path == TextPathType::Curve ? 1 : 0);
- textShader->setZoom((map.getState().getNormalizedZoom() - zoomAdjust) * 10); // current zoom level
-
- // Label fading
- const timestamp duration = 300_milliseconds;
- const timestamp currentTime = util::now();
-
- std::deque<FrameSnapshot> &history = frameHistory.history;
-
- // Remove frames until only one is outside the duration, or until there are only three
- while (history.size() > 3 && history[1].t + duration < currentTime) {
- history.pop_front();
- }
-
- if (history[1].t + duration < currentTime) {
- history[0].z = history[1].z;
- }
-
- assert("there should never be less than three frames in the history" && (history.size() >= 3));
-
- // Find the range of zoom levels we want to fade between
- float startingZ = history.front().z;
- const FrameSnapshot lastFrame = history.back();
- float endingZ = lastFrame.z;
- float lowZ = std::fmin(startingZ, endingZ);
- float highZ = std::fmax(startingZ, endingZ);
-
- // Calculate the speed of zooming, and how far it would zoom in terms of zoom levels in one duration
- float zoomDiff = endingZ - history[1].z,
- timeDiff = lastFrame.t - history[1].t;
- float fadedist = zoomDiff / (timeDiff / duration);
-
-#if defined(DEBUG)
- if (std::isnan(fadedist)) fprintf(stderr, "fadedist should never be NaN\n");
-#endif
-
- // At end of a zoom when the zoom stops changing continue pretending to zoom at that speed
- // bump is how much farther it would have been if it had continued zooming at the same rate
- float bump = (currentTime - lastFrame.t) / duration * fadedist;
-
- textShader->setFadeDist(fadedist * 10);
- textShader->setMinFadeZoom(std::floor(lowZ * 10));
- textShader->setMaxFadeZoom(std::floor(highZ * 10));
- textShader->setFadeZoom((map.getState().getNormalizedZoom() + bump) * 10);
-
- // This defines the gamma around the SDF cutoff value.
- const float sdfGamma = 0.75f / 10.0f;
-
- // Our signed distance fields are scaled so that 1 pixel is scaled to 32 pixels.
- // Our cutoff between positive and negative values is hard coded to 64 (== 2 pixels).
- // This means that our 6/8 of the value range lies outside the glyph outline.
- const float sdfOffset = (256.0f - 64.0f) / 32.0f;
-
- // Currently, all of our fonts are rendered with a font size of 24px.
- const float sdfFontSize = 24.0f;
-
- // The default gamma value has to be adjust for the current pixelratio so that we're not drawing
- // blurry font on retina screens.
- const float gamma = sdfGamma * sdfFontSize / fontSize / map.getState().getPixelRatio();
-
- // We're drawing in the translucent pass which is bottom-to-top, so we need
- // to draw the halo first.
- if (properties.halo_color[3] > 0.0f) {
- const float haloWidth = util::clamp((sdfOffset - properties.halo_width / (fontSize / sdfFontSize)) / 8.0f, 0.0f, 1.0f);
-
- if (properties.halo_blur != 0.0f) {
- // We are converting the halo_blur value to current screen pixels.
- // Then we're dividing it by two because the gamma value is added/subtracted into both
- // directions in the shader, but the halo_blur describes the entire width of the blur.
- // Note that this does *not* have to be adjusted for retina screens, because we want the
- // same blur width when we explicitly specify one.
- textShader->setGamma((properties.halo_blur / (fontSize / sdfFontSize)) / 8.0f / 2.0f);
- } else {
- textShader->setGamma(sdfGamma);
- }
-
- if (properties.opacity < 1.0f) {
- Color color = properties.halo_color;
- color[0] *= properties.opacity;
- color[1] *= properties.opacity;
- color[2] *= properties.opacity;
- color[3] *= properties.opacity;
- textShader->setColor(color);
- } else {
- textShader->setColor(properties.halo_color);
- }
- textShader->setBuffer(haloWidth);
- glDepthRange(strata, 1.0f);
- bucket.drawGlyphs(*textShader);
- }
-
- if (properties.color[3] > 0.0f) {
- // Then, we draw the text over the halo
- textShader->setGamma(gamma);
- if (properties.opacity < 1.0f) {
- Color color = properties.color;
- color[0] *= properties.opacity;
- color[1] *= properties.opacity;
- color[2] *= properties.opacity;
- color[3] *= properties.opacity;
- textShader->setColor(color);
- } else {
- textShader->setColor(properties.color);
- }
- textShader->setBuffer((256.0f - 64.0f) / 256.0f);
- glDepthRange(strata + strata_epsilon, 1.0f);
- bucket.drawGlyphs(*textShader);
- }
-}
diff --git a/src/renderer/symbol_bucket.cpp b/src/renderer/symbol_bucket.cpp
new file mode 100644
index 0000000000..4072cf0c61
--- /dev/null
+++ b/src/renderer/symbol_bucket.cpp
@@ -0,0 +1,394 @@
+#include <mbgl/renderer/symbol_bucket.hpp>
+#include <mbgl/geometry/text_buffer.hpp>
+#include <mbgl/geometry/icon_buffer.hpp>
+#include <mbgl/geometry/glyph_atlas.hpp>
+#include <mbgl/geometry/sprite_atlas.hpp>
+#include <mbgl/geometry/geometry.hpp>
+#include <mbgl/geometry/anchor.hpp>
+#include <mbgl/geometry/interpolate.hpp>
+#include <mbgl/renderer/painter.hpp>
+#include <mbgl/text/glyph_store.hpp>
+#include <mbgl/text/placement.hpp>
+#include <mbgl/platform/log.hpp>
+#include <mbgl/text/collision.hpp>
+#include <mbgl/map/sprite.hpp>
+
+#include <mbgl/util/utf.hpp>
+#include <mbgl/util/token.hpp>
+#include <mbgl/util/math.hpp>
+
+namespace mbgl {
+
+SymbolBucket::SymbolBucket(const StyleBucketSymbol &properties, Collision &collision)
+ : properties(properties), collision(collision) {}
+
+void SymbolBucket::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc,
+ const Tile::ID &id) {
+ painter.renderSymbol(*this, layer_desc, id);
+}
+
+bool SymbolBucket::hasData() const { return hasTextData() || hasIconData(); }
+
+bool SymbolBucket::hasTextData() const { return !text.groups.empty(); }
+
+bool SymbolBucket::hasIconData() const { return !icon.groups.empty(); }
+
+void SymbolBucket::addGlyphsToAtlas(uint64_t tileid, const std::string stackname,
+ const std::u32string &string, const FontStack &fontStack,
+ GlyphAtlas &glyphAtlas, GlyphPositions &face) {
+ const std::map<uint32_t, SDFGlyph> &sdfs = fontStack.getSDFs();
+ // Loop through all characters and add glyph to atlas, positions.
+ for (uint32_t chr : string) {
+ auto sdf_it = sdfs.find(chr);
+ if (sdf_it != sdfs.end()) {
+ const SDFGlyph &sdf = sdf_it->second;
+ const Rect<uint16_t> rect = glyphAtlas.addGlyph(tileid, stackname, sdf);
+ face.emplace(chr, Glyph{rect, sdf.metrics});
+ }
+ }
+}
+
+std::vector<SymbolFeature> SymbolBucket::processFeatures(const VectorTileLayer &layer,
+ const FilterExpression &filter,
+ GlyphStore &glyphStore,
+ const Sprite &sprite) {
+ const bool text = properties.text.field.size();
+ const bool icon = properties.icon.image.size();
+
+ std::vector<SymbolFeature> features;
+
+ if (!text && !icon) {
+ return features;
+ }
+
+ util::utf8_to_utf32 ucs4conv;
+
+ // Determine and load glyph ranges
+ std::set<GlyphRange> ranges;
+
+ FilteredVectorTileLayer filtered_layer(layer, filter);
+ for (const pbf &feature_pbf : filtered_layer) {
+ const VectorTileFeature feature{feature_pbf, layer};
+
+ SymbolFeature ft;
+
+ if (text) {
+ std::string u8string = util::replaceTokens(properties.text.field, feature.properties);
+
+ auto &convert = std::use_facet<std::ctype<char>>(std::locale());
+ if (properties.text.transform == TextTransformType::Uppercase) {
+ convert.toupper(&u8string[0], &u8string[0] + u8string.size());
+ } else if (properties.text.transform == TextTransformType::Lowercase) {
+ convert.tolower(&u8string[0], &u8string[0] + u8string.size());
+ }
+
+ ft.label = ucs4conv.convert(u8string);
+
+ if (ft.label.size()) {
+ // Loop through all characters of this text and collect unique codepoints.
+ for (char32_t chr : ft.label) {
+ ranges.insert(getGlyphRange(chr));
+ }
+ }
+ }
+
+ if (icon) {
+ ft.sprite = util::replaceTokens(properties.icon.image, feature.properties);
+ }
+
+ if (ft.label.length() || ft.sprite.length()) {
+ ft.geometry = feature.geometry;
+ features.push_back(std::move(ft));
+ }
+ }
+
+ glyphStore.waitForGlyphRanges(properties.text.font, ranges);
+ sprite.waitUntilLoaded();
+
+ return features;
+}
+
+void SymbolBucket::addFeatures(const VectorTileLayer &layer, const FilterExpression &filter,
+ const Tile::ID &id, SpriteAtlas &spriteAtlas, Sprite &sprite,
+ GlyphAtlas &glyphAtlas, GlyphStore &glyphStore) {
+
+ const std::vector<SymbolFeature> features = processFeatures(layer, filter, glyphStore, sprite);
+
+ float horizontalAlign = 0.5;
+ if (properties.text.horizontal_align == TextHorizontalAlignType::Right)
+ horizontalAlign = 1;
+ else if (properties.text.horizontal_align == TextHorizontalAlignType::Left)
+ horizontalAlign = 0;
+
+ float verticalAlign = 0.5;
+ if (properties.text.vertical_align == TextVerticalAlignType::Bottom)
+ verticalAlign = 1;
+ else if (properties.text.vertical_align == TextVerticalAlignType::Top)
+ verticalAlign = 0;
+
+ float justify = 0.5;
+ if (properties.text.justify == TextJustifyType::Right) justify = 1;
+ else if (properties.text.justify == TextJustifyType::Left) justify = 0;
+
+ const FontStack &fontStack = glyphStore.getFontStack(properties.text.font);
+
+ for (const SymbolFeature &feature : features) {
+ Shaping shaping;
+ Rect<uint16_t> image;
+ GlyphPositions face;
+
+ // if feature has text, shape the text
+ if (feature.label.length()) {
+ shaping = fontStack.getShaping(
+ /* string */ feature.label,
+ /* maxWidth */ properties.text.max_width,
+ /* lineHeight */ properties.text.line_height,
+ /* horizontalAlign */ horizontalAlign,
+ /* verticalAlign */ verticalAlign,
+ /* justify */ justify,
+ /* spacing */ properties.text.letter_spacing,
+ /* translate */ properties.text.offset);
+
+ // Add the glyphs we need for this label to the glyph atlas.
+ if (shaping.size()) {
+ addGlyphsToAtlas(id.to_uint64(), properties.text.font, feature.label, fontStack,
+ glyphAtlas, face);
+ }
+ }
+
+ // if feature has icon, get sprite atlas position
+ if (feature.sprite.length()) {
+ image = spriteAtlas.waitForImage(feature.sprite, sprite);
+ }
+
+ // if either shaping or icon position is present, add the feature
+ if (shaping.size() || image) {
+ addFeature(feature.geometry, shaping, face, image);
+ }
+ }
+}
+
+void SymbolBucket::addFeature(const pbf &geom_pbf, const Shaping &shaping,
+ const GlyphPositions &face, const Rect<uint16_t> &image) {
+ // Decode all lines.
+ std::vector<Coordinate> line;
+ Geometry::command cmd;
+
+ Coordinate coord;
+ pbf geom(geom_pbf);
+ Geometry geometry(geom);
+ int32_t x, y;
+ while ((cmd = geometry.next(x, y)) != Geometry::end) {
+ if (cmd == Geometry::move_to) {
+ if (!line.empty()) {
+ addFeature(line, shaping, face, image);
+ line.clear();
+ }
+ }
+ line.emplace_back(x, y);
+ }
+ if (line.size()) {
+ addFeature(line, shaping, face, image);
+ }
+}
+
+bool byScale(const Anchor &a, const Anchor &b) { return a.scale < b.scale; }
+
+const PlacementRange fullRange{{2 * M_PI, 0}};
+
+void SymbolBucket::addFeature(const std::vector<Coordinate> &line, const Shaping &shaping,
+ const GlyphPositions &face, const Rect<uint16_t> &image) {
+ assert(line.size());
+
+ const float minScale = 0.5f;
+ const float glyphSize = 24.0f;
+
+ const bool horizontalText =
+ properties.text.rotation_alignment == RotationAlignmentType::Viewport;
+ const bool horizontalIcon =
+ properties.icon.rotation_alignment == RotationAlignmentType::Viewport;
+ const float fontScale = properties.text.max_size / glyphSize;
+ const float textBoxScale = collision.tilePixelRatio * fontScale;
+ const float iconBoxScale = collision.tilePixelRatio * properties.icon.max_size;
+ const bool iconWithoutText = properties.text.optional || !shaping.size();
+ const bool textWithoutIcon = properties.icon.optional || !image;
+
+ Anchors anchors;
+
+ if (properties.placement == PlacementType::Line) {
+ // Line labels
+ anchors = interpolate(line, properties.min_distance, minScale, collision.maxPlacementScale,
+ collision.tilePixelRatio);
+
+ // Sort anchors by segment so that we can start placement with the
+ // anchors that can be shown at the lowest zoom levels.
+ std::sort(anchors.begin(), anchors.end(), byScale);
+
+ } else {
+ // Point labels
+ anchors = {Anchor{float(line[0].x), float(line[0].y), 0, minScale}};
+ }
+
+ // TODO: figure out correct ascender height.
+ const vec2<float> origin = {0, -17};
+
+ for (Anchor &anchor : anchors) {
+
+ // Calculate the scales at which the text and icons can be first shown without overlap
+ Placement glyphPlacement;
+ Placement iconPlacement;
+ float glyphScale = 0;
+ float iconScale = 0;
+
+ if (shaping.size()) {
+ glyphPlacement = Placement::getGlyphs(anchor, origin, shaping, face, textBoxScale,
+ horizontalText, line, properties);
+ glyphScale =
+ properties.text.allow_overlap
+ ? glyphPlacement.minScale
+ : collision.getPlacementScale(glyphPlacement.boxes, glyphPlacement.minScale);
+ if (!glyphScale && !iconWithoutText)
+ continue;
+ }
+
+ if (image) {
+ iconPlacement = Placement::getIcon(anchor, image, iconBoxScale, line, properties);
+ iconScale =
+ properties.icon.allow_overlap
+ ? iconPlacement.minScale
+ : collision.getPlacementScale(iconPlacement.boxes, iconPlacement.minScale);
+ if (!iconScale && !textWithoutIcon)
+ continue;
+ }
+
+ if (!iconWithoutText && !textWithoutIcon) {
+ iconScale = glyphScale = util::max(iconScale, glyphScale);
+ } else if (!textWithoutIcon && glyphScale) {
+ glyphScale = util::max(iconScale, glyphScale);
+ } else if (!iconWithoutText && iconScale) {
+ iconScale = util::max(iconScale, glyphScale);
+ }
+
+ // Get the rotation ranges it is safe to show the glyphs
+ PlacementRange glyphRange =
+ (!glyphScale || properties.text.allow_overlap)
+ ? fullRange
+ : collision.getPlacementRange(glyphPlacement.boxes, glyphScale, horizontalText);
+ PlacementRange iconRange =
+ (!iconScale || properties.icon.allow_overlap)
+ ? fullRange
+ : collision.getPlacementRange(iconPlacement.boxes, iconScale, horizontalIcon);
+
+ const PlacementRange maxRange = {{
+ util::min(iconRange[0], glyphRange[0]), util::max(iconRange[1], glyphRange[1]),
+ }};
+
+ if (!iconWithoutText && !textWithoutIcon) {
+ iconRange = glyphRange = maxRange;
+ } else if (!textWithoutIcon) {
+ glyphRange = maxRange;
+ } else if (!iconWithoutText) {
+ iconRange = maxRange;
+ }
+
+ // Insert final placement into collision tree and add glyphs/icons to buffers
+ if (glyphScale) {
+ if (!properties.text.ignore_placement) {
+ collision.insert(glyphPlacement.boxes, anchor, glyphScale, glyphRange,
+ horizontalText);
+ }
+ addSymbols(text, glyphPlacement.shapes, glyphScale, glyphRange);
+ }
+
+ if (iconScale) {
+ if (!properties.icon.ignore_placement) {
+ collision.insert(iconPlacement.boxes, anchor, iconScale, iconRange, horizontalIcon);
+ }
+ addSymbols(icon, iconPlacement.shapes, iconScale, iconRange);
+ }
+ }
+}
+
+template <typename Buffer>
+void SymbolBucket::addSymbols(Buffer &buffer, const PlacedGlyphs &symbols, float scale,
+ PlacementRange placementRange) {
+ const float zoom = collision.zoom;
+
+ const float placementZoom = std::log(scale) / std::log(2) + zoom;
+
+ for (const PlacedGlyph &symbol : symbols) {
+ const auto &tl = symbol.tl;
+ const auto &tr = symbol.tr;
+ const auto &bl = symbol.bl;
+ const auto &br = symbol.br;
+ const auto &tex = symbol.tex;
+ const auto &angle = symbol.angle;
+
+ float minZoom =
+ util::max(static_cast<float>(zoom + log(symbol.minScale) / log(2)), placementZoom);
+ float maxZoom = util::min(static_cast<float>(zoom + log(symbol.maxScale) / log(2)), 25.0f);
+ const auto &glyphAnchor = symbol.anchor;
+
+ if (maxZoom <= minZoom)
+ continue;
+
+ // Lower min zoom so that while fading out the label
+ // it can be shown outside of collision-free zoom levels
+ if (minZoom == placementZoom) {
+ minZoom = 0;
+ }
+
+ const int glyph_vertex_length = 4;
+
+ if (!buffer.groups.size() ||
+ (buffer.groups.back().vertex_length + glyph_vertex_length > 65535)) {
+ // Move to a new group because the old one can't hold the geometry.
+ buffer.groups.emplace_back();
+ }
+
+ // We're generating triangle fans, so we always start with the first
+ // coordinate in this polygon.
+ ElementGroup &triangleGroup = buffer.groups.back();
+ uint32_t triangleIndex = triangleGroup.vertex_length;
+
+ // coordinates (2 triangles)
+ buffer.vertices.add(glyphAnchor.x, glyphAnchor.y, tl.x, tl.y, tex.x, tex.y, angle, minZoom,
+ placementRange, maxZoom, placementZoom);
+ buffer.vertices.add(glyphAnchor.x, glyphAnchor.y, tr.x, tr.y, tex.x + tex.w, tex.y, angle,
+ minZoom, placementRange, maxZoom, placementZoom);
+ buffer.vertices.add(glyphAnchor.x, glyphAnchor.y, bl.x, bl.y, tex.x, tex.y + tex.h, angle,
+ minZoom, placementRange, maxZoom, placementZoom);
+ buffer.vertices.add(glyphAnchor.x, glyphAnchor.y, br.x, br.y, tex.x + tex.w, tex.y + tex.h,
+ angle, minZoom, placementRange, maxZoom, placementZoom);
+
+ // add the two triangles, referencing the four coordinates we just inserted.
+ buffer.triangles.add(triangleIndex + 0, triangleIndex + 1, triangleIndex + 2);
+ buffer.triangles.add(triangleIndex + 1, triangleIndex + 2, triangleIndex + 3);
+
+ triangleGroup.vertex_length += glyph_vertex_length;
+ triangleGroup.elements_length += 2;
+ }
+}
+
+void SymbolBucket::drawGlyphs(TextShader &shader) {
+ char *vertex_index = BUFFER_OFFSET(0);
+ char *elements_index = BUFFER_OFFSET(0);
+ for (ElementGroup &group : text.groups) {
+ group.array.bind(shader, text.vertices, text.triangles, vertex_index);
+ glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index);
+ vertex_index += group.vertex_length * text.vertices.itemSize;
+ elements_index += group.elements_length * text.triangles.itemSize;
+ }
+}
+
+void SymbolBucket::drawIcons(IconShader &shader) {
+ char *vertex_index = BUFFER_OFFSET(0);
+ char *elements_index = BUFFER_OFFSET(0);
+ for (ElementGroup &group : icon.groups) {
+ group.array.bind(shader, icon.vertices, icon.triangles, vertex_index);
+ glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index);
+ vertex_index += group.vertex_length * icon.vertices.itemSize;
+ elements_index += group.elements_length * icon.triangles.itemSize;
+ }
+}
+}
diff --git a/src/renderer/text_bucket.cpp b/src/renderer/text_bucket.cpp
deleted file mode 100644
index 45c7bf971f..0000000000
--- a/src/renderer/text_bucket.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-#include <mbgl/renderer/text_bucket.hpp>
-#include <mbgl/geometry/text_buffer.hpp>
-#include <mbgl/geometry/elements_buffer.hpp>
-#include <mbgl/geometry/geometry.hpp>
-
-#include <mbgl/renderer/painter.hpp>
-#include <mbgl/style/style.hpp>
-#include <mbgl/map/vector_tile.hpp>
-#include <mbgl/text/placement.hpp>
-#include <mbgl/text/glyph_store.hpp>
-#include <mbgl/util/constants.hpp>
-
-#include <mbgl/util/math.hpp>
-#include <mbgl/platform/gl.hpp>
-
-#include <iostream>
-
-#include <cassert>
-
-using namespace mbgl;
-
-TextBucket::TextBucket(
- TextVertexBuffer &vertexBuffer,
- TriangleElementsBuffer &triangleElementsBuffer,
- const StyleBucketText &properties, Placement &placement)
- : properties(properties),
- vertexBuffer(vertexBuffer),
- triangleElementsBuffer(triangleElementsBuffer),
- placement(placement),
- vertex_start(vertexBuffer.index()),
- triangle_elements_start(triangleElementsBuffer.index()) {}
-
-void TextBucket::addGlyphs(const PlacedGlyphs &glyphs, float placementZoom,
- PlacementRange placementRange, float zoom) {
- placementZoom += zoom;
-
- for (const PlacedGlyph &glyph : glyphs) {
- const auto &tl = glyph.tl;
- const auto &tr = glyph.tr;
- const auto &bl = glyph.bl;
- const auto &br = glyph.br;
- const auto &tex = glyph.tex;
- const auto &angle = glyph.angle;
-
- float minZoom = util::max(
- static_cast<float>(zoom + log(glyph.glyphBox.minScale) / log(2)),
- placementZoom);
- float maxZoom = util::min(
- static_cast<float>(zoom + log(glyph.glyphBox.maxScale) / log(2)),
- 25.0f);
- const auto &glyphAnchor = glyph.glyphBox.anchor;
-
- if (maxZoom <= minZoom)
- continue;
-
- // Lower min zoom so that while fading out the label
- // it can be shown outside of collision-free zoom levels
- if (minZoom == placementZoom) {
- minZoom = 0;
- }
-
- const int glyph_vertex_length = 4;
-
- if (!triangleGroups.size() ||
- (triangleGroups.back().vertex_length + glyph_vertex_length >
- 65535)) {
- // Move to a new group because the old one can't hold the geometry.
- triangleGroups.emplace_back();
- }
-
- // We're generating triangle fans, so we always start with the first
- // coordinate in this polygon.
- triangle_group_type &triangleGroup = triangleGroups.back();
- uint32_t triangleIndex = triangleGroup.vertex_length;
-
- // coordinates (2 triangles)
- vertexBuffer.add(glyphAnchor.x, glyphAnchor.y, tl.x, tl.y, tex.x,
- tex.y, angle, minZoom, placementRange, maxZoom,
- placementZoom);
- vertexBuffer.add(glyphAnchor.x, glyphAnchor.y, tr.x, tr.y,
- tex.x + tex.w, tex.y, angle, minZoom, placementRange,
- maxZoom, placementZoom);
- vertexBuffer.add(glyphAnchor.x, glyphAnchor.y, bl.x, bl.y, tex.x,
- tex.y + tex.h, angle, minZoom, placementRange,
- maxZoom, placementZoom);
- vertexBuffer.add(glyphAnchor.x, glyphAnchor.y, br.x, br.y,
- tex.x + tex.w, tex.y + tex.h, angle, minZoom,
- placementRange, maxZoom, placementZoom);
-
- // add the two triangles, referencing the four coordinates we just
- // inserted.
- triangleElementsBuffer.add(triangleIndex + 0, triangleIndex + 1,
- triangleIndex + 2);
- triangleElementsBuffer.add(triangleIndex + 1, triangleIndex + 2,
- triangleIndex + 3);
-
- triangleGroup.vertex_length += glyph_vertex_length;
- triangleGroup.elements_length += 2;
- }
-};
-
-void TextBucket::addFeature(const pbf &geom_pbf,
- const GlyphPositions &face,
- const Shaping &shaping) {
- // Decode all lines.
- std::vector<Coordinate> line;
- Geometry::command cmd;
-
- Coordinate coord;
- pbf geom(geom_pbf);
- Geometry geometry(geom);
- int32_t x, y;
- while ((cmd = geometry.next(x, y)) != Geometry::end) {
- if (cmd == Geometry::move_to) {
- if (!line.empty()) {
- placement.addFeature(*this, line, properties, face, shaping);
- line.clear();
- }
- }
- line.emplace_back(x, y);
- }
- if (line.size()) {
- placement.addFeature(*this, line, properties, face, shaping);
- }
-}
-
-void TextBucket::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc,
- const Tile::ID &id) {
- painter.renderText(*this, layer_desc, id);
-}
-
-bool TextBucket::hasData() const {
- return !triangleGroups.empty();
-}
-
-void TextBucket::drawGlyphs(TextShader &shader) {
- char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize);
- char *elements_index =
- BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize);
- for (triangle_group_type &group : triangleGroups) {
- group.array.bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index);
- glDrawElements(GL_TRIANGLES, group.elements_length * 3, GL_UNSIGNED_SHORT, elements_index);
- vertex_index += group.vertex_length * vertexBuffer.itemSize;
- elements_index += group.elements_length * triangleElementsBuffer.itemSize;
- }
-}
diff --git a/src/shader/icon.fragment.glsl b/src/shader/icon.fragment.glsl
index 52c9e65aa5..6e8130ef1e 100644
--- a/src/shader/icon.fragment.glsl
+++ b/src/shader/icon.fragment.glsl
@@ -1,11 +1,10 @@
-uniform sampler2D u_image;
-uniform vec2 u_dimension;
-uniform vec4 u_color;
-uniform float u_size;
+uniform sampler2D u_texture;
varying vec2 v_tex;
+varying float v_alpha;
void main() {
- vec2 pos = (v_tex + (gl_PointCoord - 0.5) * u_size) / u_dimension;
- gl_FragColor = u_color * texture2D(u_image, pos);
+ // Note: We don't need to premultiply here as the image we use is already
+ // premultiplied in the sprite atlas.
+ gl_FragColor = texture2D(u_texture, v_tex) * v_alpha;
}
diff --git a/src/shader/icon.vertex.glsl b/src/shader/icon.vertex.glsl
index d0ffe4b33e..f8d94a2639 100644
--- a/src/shader/icon.vertex.glsl
+++ b/src/shader/icon.vertex.glsl
@@ -1,14 +1,73 @@
attribute vec2 a_pos;
+attribute vec2 a_offset;
attribute vec2 a_tex;
+attribute float a_angle;
+attribute float a_minzoom;
+attribute float a_maxzoom;
+attribute float a_rangeend;
+attribute float a_rangestart;
+attribute float a_labelminzoom;
+
+// posmatrix is for the vertex position, exmatrix is for rotating and projecting
+// the extrusion vector.
uniform mat4 u_matrix;
-uniform float u_size;
-uniform float u_ratio;
+uniform mat4 u_exmatrix;
+uniform float u_angle;
+uniform float u_zoom;
+uniform float u_flip;
+uniform float u_fadedist;
+uniform float u_minfadezoom;
+uniform float u_maxfadezoom;
+uniform float u_fadezoom;
+uniform float u_opacity;
+
+uniform vec2 u_texsize;
varying vec2 v_tex;
+varying float v_alpha;
void main() {
- gl_Position = u_matrix * vec4(a_pos, 0, 1);
- gl_PointSize = u_size;
- v_tex = a_tex * u_ratio;
+
+ float a_fadedist = 10.0;
+ float rev = 0.0;
+
+ // u_angle is angle of the map, -128..128 representing 0..2PI
+ // a_angle is angle of the label, 0..256 representing 0..2PI, where 0 is horizontal text
+ float rotated = mod(a_angle + u_angle, 256.0);
+ // if the label rotates with the map, and if the rotated label is upside down, hide it
+ if (u_flip > 0.0 && rotated >= 64.0 && rotated < 192.0) rev = 1.0;
+
+ // If the label should be invisible, we move the vertex outside
+ // of the view plane so that the triangle gets clipped. This makes it easier
+ // for us to create degenerate triangle strips.
+ // u_zoom is the current zoom level adjusted for the change in font size
+ float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom)) + rev;
+
+ // fade out labels
+ float alpha = clamp((u_fadezoom - a_labelminzoom) / u_fadedist, 0.0, 1.0);
+
+ if (u_fadedist >= 0.0) {
+ v_alpha = alpha;
+ } else {
+ v_alpha = 1.0 - alpha;
+ }
+ if (u_maxfadezoom < a_labelminzoom) {
+ v_alpha = 0.0;
+ }
+ if (u_minfadezoom >= a_labelminzoom) {
+ v_alpha = 1.0;
+ }
+
+ // if label has been faded out, clip it
+ z += step(v_alpha, 0.0);
+
+ // all the angles are 0..256 representing 0..2PI
+ // hide if (angle >= a_rangeend && angle < rangestart)
+ z += step(a_rangeend, u_angle) * (1.0 - step(a_rangestart, u_angle));
+
+ gl_Position = u_matrix * vec4(a_pos, 0, 1) + u_exmatrix * vec4(a_offset / 64.0, z, 0);
+ v_tex = a_tex / u_texsize;
+
+ v_alpha *= u_opacity;
}
diff --git a/src/shader/icon_shader.cpp b/src/shader/icon_shader.cpp
index b3ac9272ba..6455d870a2 100644
--- a/src/shader/icon_shader.cpp
+++ b/src/shader/icon_shader.cpp
@@ -17,62 +17,138 @@ IconShader::IconShader()
}
a_pos = glGetAttribLocation(program, "a_pos");
+ a_offset = glGetAttribLocation(program, "a_offset");
a_tex = glGetAttribLocation(program, "a_tex");
+ a_angle = glGetAttribLocation(program, "a_angle");
+ a_minzoom = glGetAttribLocation(program, "a_minzoom");
+ a_maxzoom = glGetAttribLocation(program, "a_maxzoom");
+ a_rangeend = glGetAttribLocation(program, "a_rangeend");
+ a_rangestart = glGetAttribLocation(program, "a_rangestart");
+ a_labelminzoom = glGetAttribLocation(program, "a_labelminzoom");
u_matrix = glGetUniformLocation(program, "u_matrix");
- u_color = glGetUniformLocation(program, "u_color");
- u_size = glGetUniformLocation(program, "u_size");
- u_ratio = glGetUniformLocation(program, "u_ratio");
- u_dimension = glGetUniformLocation(program, "u_dimension");
+ u_exmatrix = glGetUniformLocation(program, "u_exmatrix");
+ u_angle = glGetUniformLocation(program, "u_angle");
+ u_zoom = glGetUniformLocation(program, "u_zoom");
+ u_flip = glGetUniformLocation(program, "u_flip");
+ u_fadedist = glGetUniformLocation(program, "u_fadedist");
+ u_minfadezoom = glGetUniformLocation(program, "u_minfadezoom");
+ u_maxfadezoom = glGetUniformLocation(program, "u_maxfadezoom");
+ u_fadezoom = glGetUniformLocation(program, "u_fadezoom");
+ u_opacity = glGetUniformLocation(program, "u_opacity");
+ u_texsize = glGetUniformLocation(program, "u_texsize");
// fprintf(stderr, "IconShader:\n");
// fprintf(stderr, " - u_matrix: %d\n", u_matrix);
- // fprintf(stderr, " - u_color: %d\n", u_color);
- // fprintf(stderr, " - u_size: %d\n", u_size);
- // fprintf(stderr, " - u_ratio: %d\n", u_ratio);
- // fprintf(stderr, " - u_dimension: %d\n", u_dimension);
- // fprintf(stderr, " - u_image: %d\n", u_image);
+ // fprintf(stderr, " - u_exmatrix: %d\n", u_exmatrix);
+ // fprintf(stderr, " - u_angle: %d\n", u_angle);
+ // fprintf(stderr, " - u_zoom: %d\n", u_zoom);
+ // fprintf(stderr, " - u_flip: %d\n", u_flip);
+ // fprintf(stderr, " - u_fadedist: %d\n", u_fadedist);
+ // fprintf(stderr, " - u_minfadezoom: %d\n", u_minfadezoom);
+ // fprintf(stderr, " - u_maxfadezoom: %d\n", u_maxfadezoom);
+ // fprintf(stderr, " - u_fadezoom: %d\n", u_fadezoom);
+ // fprintf(stderr, " - u_opacity: %d\n", u_opacity);
}
void IconShader::bind(char *offset) {
+ const int stride = 20;
+
glEnableVertexAttribArray(a_pos);
- glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 8, offset);
+ glVertexAttribPointer(a_pos, 2, GL_SHORT, false, stride, offset + 0);
+
+ glEnableVertexAttribArray(a_offset);
+ glVertexAttribPointer(a_offset, 2, GL_SHORT, false, stride, offset + 4);
+
+ glEnableVertexAttribArray(a_labelminzoom);
+ glVertexAttribPointer(a_labelminzoom, 1, GL_UNSIGNED_BYTE, false, stride, offset + 8);
+
+ glEnableVertexAttribArray(a_minzoom);
+ glVertexAttribPointer(a_minzoom, 1, GL_UNSIGNED_BYTE, false, stride, offset + 9);
+
+ glEnableVertexAttribArray(a_maxzoom);
+ glVertexAttribPointer(a_maxzoom, 1, GL_UNSIGNED_BYTE, false, stride, offset + 10);
+
+ glEnableVertexAttribArray(a_angle);
+ glVertexAttribPointer(a_angle, 1, GL_UNSIGNED_BYTE, false, stride, offset + 11);
+
+ glEnableVertexAttribArray(a_rangeend);
+ glVertexAttribPointer(a_rangeend, 1, GL_UNSIGNED_BYTE, false, stride, offset + 12);
+
+ glEnableVertexAttribArray(a_rangestart);
+ glVertexAttribPointer(a_rangestart, 1, GL_UNSIGNED_BYTE, false, stride, offset + 13);
glEnableVertexAttribArray(a_tex);
- glVertexAttribPointer(a_tex, 2, GL_UNSIGNED_SHORT, false, 8, offset + 4);
+ glVertexAttribPointer(a_tex, 2, GL_SHORT, false, stride, offset + 16);
+}
+
+void IconShader::setExtrudeMatrix(const std::array<float, 16>& new_exmatrix) {
+ if (exmatrix != new_exmatrix) {
+ glUniformMatrix4fv(u_exmatrix, 1, GL_FALSE, new_exmatrix.data());
+ exmatrix = new_exmatrix;
+ }
+}
+
+void IconShader::setAngle(float new_angle) {
+ if (angle != new_angle) {
+ glUniform1f(u_angle, new_angle);
+ angle = new_angle;
+ }
+}
+
+void IconShader::setZoom(float new_zoom) {
+ if (zoom != new_zoom) {
+ glUniform1f(u_zoom, new_zoom);
+ zoom = new_zoom;
+ }
+}
+
+void IconShader::setFlip(float new_flip) {
+ if (flip != new_flip) {
+ glUniform1f(u_flip, new_flip);
+ flip = new_flip;
+ }
+}
+
+void IconShader::setFadeDist(float new_fadedist) {
+ if (fadedist != new_fadedist) {
+ glUniform1f(u_fadedist, new_fadedist);
+ fadedist = new_fadedist;
+ }
}
-void IconShader::setImage(int32_t new_image) {
- if (image != new_image) {
- glUniform1i(u_image, new_image);
- image = new_image;
+void IconShader::setMinFadeZoom(float new_minfadezoom) {
+ if (minfadezoom != new_minfadezoom) {
+ glUniform1f(u_minfadezoom, new_minfadezoom);
+ minfadezoom = new_minfadezoom;
}
}
-void IconShader::setColor(const std::array<float, 4>& new_color) {
- if (color != new_color) {
- glUniform4fv(u_color, 1, new_color.data());
- color = new_color;
+void IconShader::setMaxFadeZoom(float new_maxfadezoom) {
+ if (maxfadezoom != new_maxfadezoom) {
+ glUniform1f(u_maxfadezoom, new_maxfadezoom);
+ maxfadezoom = new_maxfadezoom;
}
}
-void IconShader::setSize(float new_size) {
- if (size != new_size) {
- glUniform1f(u_size, new_size);
- size = new_size;
+void IconShader::setFadeZoom(float new_fadezoom) {
+ if (fadezoom != new_fadezoom) {
+ glUniform1f(u_fadezoom, new_fadezoom);
+ fadezoom = new_fadezoom;
}
}
-void IconShader::setRatio(float new_ratio) {
- if (ratio != new_ratio) {
- glUniform1f(u_ratio, new_ratio);
- ratio = new_ratio;
+void IconShader::setOpacity(float new_opacity) {
+ if (opacity != new_opacity) {
+ glUniform1f(u_opacity, new_opacity);
+ opacity = new_opacity;
}
}
-void IconShader::setDimension(const std::array<float, 2>& new_dimension) {
- if (dimension != new_dimension) {
- glUniform2fv(u_dimension, 1, new_dimension.data());
- dimension = new_dimension;
+void IconShader::setTextureSize(const std::array<float, 2> &new_texsize) {
+ if (texsize != new_texsize) {
+ glUniform2fv(u_texsize, 1, new_texsize.data());
+ texsize = new_texsize;
}
}
+
diff --git a/src/shader/line.fragment.glsl b/src/shader/line.fragment.glsl
index ca8fed9bb2..f4ac1458b3 100644
--- a/src/shader/line.fragment.glsl
+++ b/src/shader/line.fragment.glsl
@@ -1,5 +1,6 @@
uniform vec2 u_linewidth;
uniform vec4 u_color;
+uniform float u_blur;
uniform vec2 u_dasharray;
@@ -13,7 +14,7 @@ void main() {
// Calculate the antialiasing fade factor. This is either when fading in
// the line in case of an offset line (v_linewidth.t) or when fading out
// (v_linewidth.s)
- float alpha = clamp(min(dist - (u_linewidth.t - 1.0), u_linewidth.s - dist), 0.0, 1.0);
+ float alpha = clamp(min(dist - (u_linewidth.t - u_blur), u_linewidth.s - dist) / u_blur, 0.0, 1.0);
// Calculate the antialiasing fade factor based on distance to the dash.
// Only affects alpha when line is dashed
@@ -21,4 +22,4 @@ void main() {
alpha *= max(step(0.0, -u_dasharray.y), clamp(min(pos, u_dasharray.x - pos), 0.0, 1.0));
gl_FragColor = u_color * alpha;
-} \ No newline at end of file
+}
diff --git a/src/shader/line_shader.cpp b/src/shader/line_shader.cpp
index 1330089896..529ab0d316 100644
--- a/src/shader/line_shader.cpp
+++ b/src/shader/line_shader.cpp
@@ -26,6 +26,7 @@ LineShader::LineShader()
u_color = glGetUniformLocation(program, "u_color");
u_ratio = glGetUniformLocation(program, "u_ratio");
u_dasharray = glGetUniformLocation(program, "u_dasharray");
+ u_blur = glGetUniformLocation(program, "u_blur");
// fprintf(stderr, "LineShader:\n");
// fprintf(stderr, " - u_matrix: %d\n", u_matrix);
@@ -81,3 +82,10 @@ void LineShader::setDashArray(const std::array<float, 2>& new_dasharray) {
dasharray = new_dasharray;
}
}
+
+void LineShader::setBlur(float new_blur) {
+ if (blur != new_blur) {
+ glUniform1f(u_blur, new_blur);
+ blur = new_blur;
+ }
+}
diff --git a/src/shader/text_shader.cpp b/src/shader/text_shader.cpp
index c7cbbf560e..c9e70825ce 100644
--- a/src/shader/text_shader.cpp
+++ b/src/shader/text_shader.cpp
@@ -52,6 +52,7 @@ TextShader::TextShader()
// fprintf(stderr, " - u_maxfadezoom: %d\n", u_maxfadezoom);
// fprintf(stderr, " - u_fadezoom: %d\n", u_fadezoom);
// fprintf(stderr, " - u_texsize: %d\n", u_texsize);
+ // fprintf(stderr, " - u_opacity: %d\n", u_opacity);
}
void TextShader::bind(char *offset) {
diff --git a/src/style/property_fallback.cpp b/src/style/property_fallback.cpp
index 949dc1a5cb..4401c8105a 100644
--- a/src/style/property_fallback.cpp
+++ b/src/style/property_fallback.cpp
@@ -1,48 +1,60 @@
#include <mbgl/style/property_fallback.hpp>
+#include <mbgl/style/style_properties.hpp>
namespace mbgl {
const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = {
- { PropertyKey::FillAntialias, true },
- { PropertyKey::FillOpacity, 1.0f },
- { PropertyKey::FillColor, Color({{ 0, 0, 0, 1 }}) },
- { PropertyKey::FillTranslateX, 0.0f },
- { PropertyKey::FillTranslateY, 0.0f },
- { PropertyKey::FillTranslateAnchor, TranslateAnchorType::Map },
-
- { PropertyKey::LineOpacity, 1.0f },
- { PropertyKey::LineColor, Color({{ 0, 0, 0, 1 }}) },
- { PropertyKey::LineTranslateX, 0.0f },
- { PropertyKey::LineTranslateY, 0.0f },
- { PropertyKey::LineTranslateAnchor, TranslateAnchorType::Map },
- { PropertyKey::LineWidth, 1.0f },
- { PropertyKey::LineOffset, 0.0f },
- { PropertyKey::LineBlur, 1.0f },
- { PropertyKey::LineDashLand, 1.0f },
- { PropertyKey::LineDashGap, -1.0f },
-
- { PropertyKey::IconOpacity, 1.0f },
- { PropertyKey::IconRotate, 0.0f },
- { PropertyKey::IconRotateAnchor, RotateAnchorType::Viewport },
-
- { PropertyKey::TextOpacity, 1.0f },
- { PropertyKey::TextSize, 16.0f },
- { PropertyKey::TextColor, Color({{ 0, 0, 0, 1 }}) },
- { PropertyKey::TextHaloColor, Color({{ 0, 0, 0, 0 }}) },
- { PropertyKey::TextHaloWidth, 0.25f },
- { PropertyKey::TextHaloBlur, 1.0f },
-
- { PropertyKey::CompositeOpacity, 1.0f },
-
- { PropertyKey::RasterOpacity, 1.0f },
- { PropertyKey::RasterSpin, 0.0f },
- { PropertyKey::RasterBrightnessLow, 0.0f },
- { PropertyKey::RasterBrightnessHigh, 1.0f },
- { PropertyKey::RasterSaturation, 0.0f },
- { PropertyKey::RasterContrast, 0.0f },
- { PropertyKey::RasterFade, 0.0f },
-
- { PropertyKey::BackgroundColor, Color({{ 0, 0, 0, 0 }}) },
+ { PropertyKey::FillAntialias, defaultStyleProperties<FillProperties>().antialias },
+ { PropertyKey::FillOpacity, defaultStyleProperties<FillProperties>().opacity },
+ { PropertyKey::FillColor, defaultStyleProperties<FillProperties>().fill_color },
+ // no FillOutlineColor on purpose.
+ { PropertyKey::FillTranslateX, defaultStyleProperties<FillProperties>().translate[0] },
+ { PropertyKey::FillTranslateY, defaultStyleProperties<FillProperties>().translate[1] },
+ { PropertyKey::FillTranslateAnchor, defaultStyleProperties<FillProperties>().translateAnchor },
+
+ { PropertyKey::LineOpacity, defaultStyleProperties<LineProperties>().opacity },
+ { PropertyKey::LineColor, defaultStyleProperties<LineProperties>().color },
+ { PropertyKey::LineTranslateX, defaultStyleProperties<LineProperties>().translate[0] },
+ { PropertyKey::LineTranslateY, defaultStyleProperties<LineProperties>().translate[1] },
+ { PropertyKey::LineTranslateAnchor, defaultStyleProperties<LineProperties>().translateAnchor },
+ { PropertyKey::LineWidth, defaultStyleProperties<LineProperties>().width },
+ { PropertyKey::LineOffset, defaultStyleProperties<LineProperties>().offset },
+ { PropertyKey::LineBlur, defaultStyleProperties<LineProperties>().blur },
+ { PropertyKey::LineDashLand, defaultStyleProperties<LineProperties>().dash_array[0] },
+ { PropertyKey::LineDashGap, defaultStyleProperties<LineProperties>().dash_array[1] },
+
+ { PropertyKey::IconOpacity, defaultStyleProperties<SymbolProperties>().icon.opacity },
+ { PropertyKey::IconRotate, defaultStyleProperties<SymbolProperties>().icon.rotate },
+ { PropertyKey::IconSize, defaultStyleProperties<SymbolProperties>().icon.size },
+ { PropertyKey::IconColor, defaultStyleProperties<SymbolProperties>().icon.color },
+ { PropertyKey::IconHaloColor, defaultStyleProperties<SymbolProperties>().icon.halo_color },
+ { PropertyKey::IconHaloWidth, defaultStyleProperties<SymbolProperties>().icon.halo_width },
+ { PropertyKey::IconHaloBlur, defaultStyleProperties<SymbolProperties>().icon.halo_blur },
+ { PropertyKey::IconTranslateX, defaultStyleProperties<SymbolProperties>().icon.translate[0] },
+ { PropertyKey::IconTranslateY, defaultStyleProperties<SymbolProperties>().icon.translate[1] },
+ { PropertyKey::IconTranslateAnchor, defaultStyleProperties<SymbolProperties>().icon.translate_anchor },
+
+ { PropertyKey::TextOpacity, defaultStyleProperties<SymbolProperties>().text.opacity },
+ { PropertyKey::TextSize, defaultStyleProperties<SymbolProperties>().text.size },
+ { PropertyKey::TextColor, defaultStyleProperties<SymbolProperties>().text.color },
+ { PropertyKey::TextHaloColor, defaultStyleProperties<SymbolProperties>().text.halo_color },
+ { PropertyKey::TextHaloWidth, defaultStyleProperties<SymbolProperties>().text.halo_width },
+ { PropertyKey::TextHaloBlur, defaultStyleProperties<SymbolProperties>().text.halo_blur },
+ { PropertyKey::TextTranslateX, defaultStyleProperties<SymbolProperties>().text.translate[0] },
+ { PropertyKey::TextTranslateY, defaultStyleProperties<SymbolProperties>().text.translate[1] },
+ { PropertyKey::TextTranslateAnchor, defaultStyleProperties<SymbolProperties>().text.translate_anchor },
+
+ { PropertyKey::CompositeOpacity, defaultStyleProperties<CompositeProperties>().opacity },
+
+ { PropertyKey::RasterOpacity, defaultStyleProperties<RasterProperties>().opacity },
+ { PropertyKey::RasterSpin, defaultStyleProperties<RasterProperties>().spin },
+ { PropertyKey::RasterBrightnessLow, defaultStyleProperties<RasterProperties>().brightness[0] },
+ { PropertyKey::RasterBrightnessHigh, defaultStyleProperties<RasterProperties>().brightness[1] },
+ { PropertyKey::RasterSaturation, defaultStyleProperties<RasterProperties>().saturation },
+ { PropertyKey::RasterContrast, defaultStyleProperties<RasterProperties>().contrast },
+ { PropertyKey::RasterFade, defaultStyleProperties<RasterProperties>().fade },
+
+ { PropertyKey::BackgroundColor, defaultStyleProperties<BackgroundProperties>().color },
};
const PropertyValue PropertyFallbackValue::defaultProperty = false;
diff --git a/src/style/style.cpp b/src/style/style.cpp
index f867616970..03881f96a0 100644
--- a/src/style/style.cpp
+++ b/src/style/style.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/style.hpp>
+#include <mbgl/map/sprite.hpp>
#include <mbgl/style/style_layer_group.hpp>
#include <mbgl/style/style_parser.hpp>
#include <mbgl/style/style_bucket.hpp>
@@ -29,6 +30,10 @@ void Style::updateProperties(float z, timestamp now) {
}
}
+const std::string &Style::getSpriteURL() const {
+ return sprite_url;
+}
+
void Style::setDefaultTransitionDuration(uint16_t duration_milliseconds) {
defaultTransition.duration = duration_milliseconds;
}
@@ -93,7 +98,7 @@ void Style::loadJSON(const uint8_t *const data) {
const BackgroundProperties &Style::getBackgroundProperties() const {
if (layers && layers->layers.size()) {
const auto first = layers->layers.front();
- if (first && first->id == "background") {
+ if (first && first->type == StyleLayerType::Background) {
return first->getProperties<BackgroundProperties>();
}
}
diff --git a/src/style/style_bucket.cpp b/src/style/style_bucket.cpp
index afd4bc09f7..9a40c2386b 100644
--- a/src/style/style_bucket.cpp
+++ b/src/style/style_bucket.cpp
@@ -6,8 +6,7 @@ StyleBucket::StyleBucket(StyleLayerType type) {
switch (type) {
case StyleLayerType::Fill: render = StyleBucketFill{}; break;
case StyleLayerType::Line: render = StyleBucketLine{}; break;
- case StyleLayerType::Icon: render = StyleBucketIcon{}; break;
- case StyleLayerType::Text: render = StyleBucketText{}; break;
+ case StyleLayerType::Symbol: render = StyleBucketSymbol{}; break;
case StyleLayerType::Raster: render = StyleBucketRaster{}; break;
default: break;
}
diff --git a/src/style/style_layer.cpp b/src/style/style_layer.cpp
index 69c5a8c8ca..1672ad4a8b 100644
--- a/src/style/style_layer.cpp
+++ b/src/style/style_layer.cpp
@@ -10,7 +10,7 @@ StyleLayer::StyleLayer(const std::string &id, std::map<ClassID, ClassProperties>
: id(id), styles(std::move(styles)), rasterize(std::move(rasterize)) {}
bool StyleLayer::isBackground() const {
- return type == StyleLayerType::Background && id == "background";
+ return type == StyleLayerType::Background;
}
void StyleLayer::setClasses(const std::vector<std::string> &class_names, const timestamp now,
@@ -191,24 +191,30 @@ void StyleLayer::applyStyleProperties<LineProperties>(const float z, const times
}
template <>
-void StyleLayer::applyStyleProperties<IconProperties>(const float z, const timestamp now) {
- properties.set<IconProperties>();
- IconProperties &icon = properties.get<IconProperties>();
- applyStyleProperty(PropertyKey::IconOpacity, icon.opacity, z, now);
- applyStyleProperty(PropertyKey::IconRotate, icon.rotate, z, now);
- applyStyleProperty(PropertyKey::IconRotateAnchor, icon.rotate_anchor, z, now);
-}
+void StyleLayer::applyStyleProperties<SymbolProperties>(const float z, const timestamp now) {
+ properties.set<SymbolProperties>();
+ SymbolProperties &symbol = properties.get<SymbolProperties>();
+ applyStyleProperty(PropertyKey::IconOpacity, symbol.icon.opacity, z, now);
+ applyStyleProperty(PropertyKey::IconRotate, symbol.icon.rotate, z, now);
+ applyStyleProperty(PropertyKey::IconSize, symbol.icon.size, z, now);
+ applyStyleProperty(PropertyKey::IconColor, symbol.icon.color, z, now);
+ applyStyleProperty(PropertyKey::IconHaloColor, symbol.icon.halo_color, z, now);
+ applyStyleProperty(PropertyKey::IconHaloWidth, symbol.icon.halo_width, z, now);
+ applyStyleProperty(PropertyKey::IconHaloBlur, symbol.icon.halo_blur, z, now);
+ applyStyleProperty(PropertyKey::IconTranslateX, symbol.icon.translate[0], z, now);
+ applyStyleProperty(PropertyKey::IconTranslateY, symbol.icon.translate[1], z, now);
+ applyStyleProperty(PropertyKey::IconTranslateAnchor, symbol.icon.translate_anchor, z, now);
+
+ applyStyleProperty(PropertyKey::TextOpacity, symbol.text.opacity, z, now);
+ applyStyleProperty(PropertyKey::TextSize, symbol.text.size, z, now);
+ applyStyleProperty(PropertyKey::TextColor, symbol.text.color, z, now);
+ applyStyleProperty(PropertyKey::TextHaloColor, symbol.text.halo_color, z, now);
+ applyStyleProperty(PropertyKey::TextHaloWidth, symbol.text.halo_width, z, now);
+ applyStyleProperty(PropertyKey::TextHaloBlur, symbol.text.halo_blur, z, now);
+ applyStyleProperty(PropertyKey::TextTranslateX, symbol.text.translate[0], z, now);
+ applyStyleProperty(PropertyKey::TextTranslateY, symbol.text.translate[1], z, now);
+ applyStyleProperty(PropertyKey::TextTranslateAnchor, symbol.text.translate_anchor, z, now);
-template <>
-void StyleLayer::applyStyleProperties<TextProperties>(const float z, const timestamp now) {
- properties.set<TextProperties>();
- TextProperties &text = properties.get<TextProperties>();
- applyStyleProperty(PropertyKey::TextOpacity, text.opacity, z, now);
- applyStyleProperty(PropertyKey::TextSize, text.size, z, now);
- applyStyleProperty(PropertyKey::TextColor, text.color, z, now);
- applyStyleProperty(PropertyKey::TextHaloColor, text.halo_color, z, now);
- applyStyleProperty(PropertyKey::TextHaloWidth, text.halo_width, z, now);
- applyStyleProperty(PropertyKey::TextHaloBlur, text.halo_blur, z, now);
}
template <>
@@ -248,8 +254,7 @@ void StyleLayer::updateProperties(float z, const timestamp now) {
switch (type) {
case StyleLayerType::Fill: applyStyleProperties<FillProperties>(z, now); break;
case StyleLayerType::Line: applyStyleProperties<LineProperties>(z, now); break;
- case StyleLayerType::Icon: applyStyleProperties<IconProperties>(z, now); break;
- case StyleLayerType::Text: applyStyleProperties<TextProperties>(z, now); break;
+ case StyleLayerType::Symbol: applyStyleProperties<SymbolProperties>(z, now); break;
case StyleLayerType::Raster: applyStyleProperties<RasterProperties>(z, now); break;
case StyleLayerType::Composite: applyStyleProperties<CompositeProperties>(z, now); break;
case StyleLayerType::Background: applyStyleProperties<BackgroundProperties>(z, now); break;
diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp
index e5aa3acc15..bc3878144f 100644
--- a/src/style/style_parser.cpp
+++ b/src/style/style_parser.cpp
@@ -63,6 +63,20 @@ JSVal StyleParser::replaceConstant(JSVal value) {
#pragma mark - Parse Render Properties
+template<> bool StyleParser::parseRenderProperty(JSVal value, bool &target, const char *name) {
+ if (value.HasMember(name)) {
+ JSVal property = replaceConstant(value[name]);
+ if (property.IsBool()) {
+ target = property.GetBool();
+ return true;
+ } else {
+ fprintf(stderr, "[WARNING] '%s' must be a boolean\n", name);
+ }
+ }
+ return false;
+}
+
+
template<> bool StyleParser::parseRenderProperty(JSVal value, std::string &target, const char *name) {
if (value.HasMember(name)) {
JSVal property = replaceConstant(value[name]);
@@ -139,12 +153,12 @@ template<> bool StyleParser::parseRenderProperty(JSVal value, vec2<float> &targe
return false;
}
-template<typename T, typename Parser>
-bool StyleParser::parseRenderProperty(JSVal value, T &target, const char *name, Parser &parser) {
+template<typename Parser, typename T>
+bool StyleParser::parseRenderProperty(JSVal value, T &target, const char *name) {
if (value.HasMember(name)) {
JSVal property = replaceConstant(value[name]);
if (property.IsString()) {
- target = parser({ property.GetString(), property.GetStringLength() });
+ target = Parser({ property.GetString(), property.GetStringLength() });
return true;
} else {
Log::Warning(Event::ParseStyle, "%s must have one of the enum values", name);
@@ -167,7 +181,7 @@ void StyleParser::parseSources(JSVal value) {
int32_t min_zoom = 0;
int32_t max_zoom = 22;
- parseRenderProperty(itr->value, type, "type", parseSourceType);
+ parseRenderProperty<SourceTypeClass>(itr->value, type, "type");
parseRenderProperty(itr->value, url, "url");
if (type == SourceType::Raster) {
parseRenderProperty(itr->value, tile_size, "tileSize");
@@ -175,7 +189,7 @@ void StyleParser::parseSources(JSVal value) {
parseRenderProperty(itr->value, min_zoom, "minZoom");
parseRenderProperty(itr->value, max_zoom, "maxZoom");
- sources.emplace(std::move(name), std::make_shared<StyleSource>(type, url, tile_size, min_zoom, max_zoom));
+ sources.emplace(std::move(name), std::make_shared<StyleSource>(SourceInfo { type, url, tile_size, min_zoom, max_zoom }));
}
} else {
Log::Warning(Event::ParseStyle, "sources must be an object");
@@ -348,22 +362,22 @@ template<> std::tuple<bool, std::string> StyleParser::parseProperty(JSVal value,
template<> std::tuple<bool, TranslateAnchorType> StyleParser::parseProperty(JSVal value, const char *property_name) {
if (!value.IsString()) {
Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
- return std::tuple<bool, TranslateAnchorType> { false, TranslateAnchorType::Default };
+ return std::tuple<bool, TranslateAnchorType> { false, TranslateAnchorType::Map };
}
- return std::tuple<bool, TranslateAnchorType> { true, parseTranslateAnchorType({ value.GetString(), value.GetStringLength() }) };
+ return std::tuple<bool, TranslateAnchorType> { true, TranslateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
}
template<> std::tuple<bool, RotateAnchorType> StyleParser::parseProperty<RotateAnchorType>(JSVal value, const char *property_name) {
if (!value.IsString()) {
Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
- return std::tuple<bool, RotateAnchorType> { false, RotateAnchorType::Default };
+ return std::tuple<bool, RotateAnchorType> { false, RotateAnchorType::Map };
}
- return std::tuple<bool, RotateAnchorType> { true, parseRotateAnchorType({ value.GetString(), value.GetStringLength() }) };
+ return std::tuple<bool, RotateAnchorType> { true, RotateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
}
-template<> std::tuple<bool, PropertyTransition> StyleParser::parseProperty(JSVal value, const char *property_name) {
+template<> std::tuple<bool, PropertyTransition> StyleParser::parseProperty(JSVal value, const char */*property_name*/) {
PropertyTransition transition;
if (value.IsObject()) {
if (value.HasMember("duration") && value["duration"].IsNumber()) {
@@ -592,7 +606,18 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) {
parseOptionalProperty<Function<float>>("icon-opacity", Key::IconOpacity, klass, value);
parseOptionalProperty<PropertyTransition>("transition-icon-opacity", Key::IconOpacity, klass, value);
parseOptionalProperty<Function<float>>("icon-rotate", Key::IconRotate, klass, value);
- parseOptionalProperty<RotateAnchorType>("icon-rotate-anchor", Key::IconRotateAnchor, klass, value);
+ parseOptionalProperty<Function<float>>("icon-size", Key::IconSize, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-icon-size", Key::IconSize, klass, value);
+ parseOptionalProperty<Function<Color>>("icon-color", Key::IconColor, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-icon-color", Key::IconColor, klass, value);
+ parseOptionalProperty<Function<Color>>("icon-halo-color", Key::IconHaloColor, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-icon-halo-color", Key::IconHaloColor, klass, value);
+ parseOptionalProperty<Function<float>>("icon-halo-width", Key::IconHaloWidth, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-icon-halo-width", Key::IconHaloWidth, klass, value);
+ parseOptionalProperty<Function<float>>("icon-halo-blur", Key::IconHaloBlur, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-icon-halo-blur", Key::IconHaloBlur, klass, value);
+ parseOptionalProperty<Function<float>>("icon-translate", { Key::IconTranslateX, Key::IconTranslateY }, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-icon-translate", Key::IconTranslate, klass, value);
parseOptionalProperty<Function<float>>("text-opacity", Key::TextOpacity, klass, value);
parseOptionalProperty<PropertyTransition>("transition-text-opacity", Key::TextOpacity, klass, value);
@@ -606,6 +631,8 @@ void StyleParser::parseStyle(JSVal value, ClassProperties &klass) {
parseOptionalProperty<PropertyTransition>("transition-text-halo-width", Key::TextHaloWidth, klass, value);
parseOptionalProperty<Function<float>>("text-halo-blur", Key::TextHaloBlur, klass, value);
parseOptionalProperty<PropertyTransition>("transition-text-halo-blur", Key::TextHaloBlur, klass, value);
+ parseOptionalProperty<Function<float>>("text-translate", { Key::TextTranslateX, Key::TextTranslateY }, klass, value);
+ parseOptionalProperty<PropertyTransition>("transition-text-translate", Key::TextTranslate, klass, value);
parseOptionalProperty<Function<float>>("composite-opacity", Key::CompositeOpacity, klass, value);
parseOptionalProperty<PropertyTransition>("transition-composite-opacity", Key::CompositeOpacity, klass, value);
@@ -714,6 +741,24 @@ void StyleParser::parseBucket(JSVal value, std::shared_ptr<StyleLayer> &layer) {
JSVal value_render = replaceConstant(value["render"]);
parseRender(value_render, layer);
}
+
+ if (value.HasMember("min-zoom")) {
+ JSVal min_zoom = value["min-zoom"];
+ if (min_zoom.IsNumber()) {
+ layer->bucket->min_zoom = min_zoom.GetDouble();
+ } else {
+ Log::Warning(Event::ParseStyle, "min-zoom of layer %s must be numeric", layer->id.c_str());
+ }
+ }
+
+ if (value.HasMember("max-zoom")) {
+ JSVal max_zoom = value["max-zoom"];
+ if (max_zoom.IsNumber()) {
+ layer->bucket->min_zoom = max_zoom.GetDouble();
+ } else {
+ Log::Warning(Event::ParseStyle, "max-zoom of layer %s must be numeric", layer->id.c_str());
+ }
+ }
}
FilterExpression StyleParser::parseFilter(JSVal value) {
@@ -815,61 +860,70 @@ void StyleParser::parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer) {
case StyleLayerType::Fill: {
StyleBucketFill &render = bucket.render.get<StyleBucketFill>();
- parseRenderProperty(value, render.winding, "fill-winding", parseWindingType);
+ parseRenderProperty<WindingTypeClass>(value, render.winding, "fill-winding");
} break;
case StyleLayerType::Line: {
StyleBucketLine &render = bucket.render.get<StyleBucketLine>();
- parseRenderProperty(value, render.cap, "line-cap", parseCapType);
- parseRenderProperty(value, render.join, "line-join", parseJoinType);
+ parseRenderProperty<CapTypeClass>(value, render.cap, "line-cap");
+ parseRenderProperty<JoinTypeClass>(value, render.join, "line-join");
parseRenderProperty(value, render.miter_limit, "line-miter-limit");
parseRenderProperty(value, render.round_limit, "line-round-limit");
} break;
- case StyleLayerType::Icon: {
- StyleBucketIcon &render = bucket.render.get<StyleBucketIcon>();
-
- parseRenderProperty(value, render.size, "icon-size");
- parseRenderProperty(value, render.icon, "icon-image");
- parseRenderProperty(value, render.spacing, "icon-spacing");
- parseRenderProperty(value, render.padding, "icon-padding");
- if (parseRenderProperty(value, render.translate, "icon-translate")) {
- render.translate.x *= 24;
- render.translate.y *= -24;
- }
- parseRenderProperty(value, render.translate_anchor, "icon-translate-anchor", parseTranslateAnchorType);
- } break;
-
- case StyleLayerType::Text: {
- StyleBucketText &render = bucket.render.get<StyleBucketText>();
-
- parseRenderProperty(value, render.field, "text-field");
- parseRenderProperty(value, render.path, "text-path", parseTextPathType);
- parseRenderProperty(value, render.transform, "text-transform", parseTextTransformType);
- parseRenderProperty(value, render.font, "text-font");
- parseRenderProperty(value, render.max_size, "text-max-size");
- if (parseRenderProperty(value, render.max_width, "text-max-width")) {
- render.max_width *= 24; // em
- }
- if (parseRenderProperty(value, render.line_height, "text-line-height")) {
- render.line_height *= 24; // em
- }
- if (parseRenderProperty(value, render.letter_spacing, "text-letter-spacing")) {
- render.letter_spacing *= 24; // em
- }
- parseRenderProperty(value, render.alignment, "text-alignment", parseAlignmentType);
- parseRenderProperty(value, render.vertical_alignment, "text-vertical-alignment", parseVerticalAlignmentType);
- parseRenderProperty(value, render.max_angle_delta, "text-max-angle");
- parseRenderProperty(value, render.min_distance, "text-min-distance");
- parseRenderProperty(value, render.rotate, "text-rotate");
- parseRenderProperty(value, render.slant, "text-slant");
- parseRenderProperty(value, render.padding, "text-padding");
- if (parseRenderProperty(value, render.translate, "text-translate")) {
- render.translate.x *= 24;
- render.translate.y *= -24;
- }
- parseRenderProperty(value, render.translate_anchor, "text-translate-anchor", parseTranslateAnchorType);
+ case StyleLayerType::Symbol: {
+ StyleBucketSymbol &render = bucket.render.get<StyleBucketSymbol>();
+
+ parseRenderProperty<PlacementTypeClass>(value, render.placement, "symbol-placement");
+ if (render.placement == PlacementType::Line) {
+ // Change the default value in case of line placement.
+ render.text.rotation_alignment = RotationAlignmentType::Map;
+ render.icon.rotation_alignment = RotationAlignmentType::Map;
+ }
+
+ parseRenderProperty(value, render.min_distance, "symbol-min-distance");
+
+ parseRenderProperty(value, render.icon.allow_overlap, "icon-allow-overlap");
+ parseRenderProperty(value, render.icon.ignore_placement, "icon-ignore-placement");
+ parseRenderProperty(value, render.icon.optional, "icon-optional");
+ parseRenderProperty<RotationAlignmentTypeClass>(value, render.icon.rotation_alignment, "icon-rotation-alignment");
+ parseRenderProperty(value, render.icon.max_size, "icon-max-size");
+ parseRenderProperty(value, render.icon.image, "icon-image");
+ parseRenderProperty(value, render.icon.rotate, "icon-rotate");
+ parseRenderProperty(value, render.icon.padding, "icon-padding");
+ parseRenderProperty(value, render.icon.keep_upright, "icon-keep-upright");
+ parseRenderProperty(value, render.icon.offset, "icon-offset");
+ parseRenderProperty<TranslateAnchorTypeClass>(value, render.icon.translate_anchor, "icon-translate-anchor");
+
+
+ parseRenderProperty<RotationAlignmentTypeClass>(value, render.text.rotation_alignment, "text-rotation-alignment");
+ parseRenderProperty(value, render.text.field, "text-field");
+ parseRenderProperty(value, render.text.font, "text-font");
+ parseRenderProperty(value, render.text.max_size, "text-max-size");
+ if (parseRenderProperty(value, render.text.max_width, "text-max-width")) {
+ render.text.max_width *= 24; // em
+ }
+ if (parseRenderProperty(value, render.text.line_height, "text-line-height")) {
+ render.text.line_height *= 24; // em
+ }
+ if (parseRenderProperty(value, render.text.letter_spacing, "text-letter-spacing")) {
+ render.text.letter_spacing *= 24; // em
+ }
+ parseRenderProperty<TextJustifyTypeClass>(value, render.text.justify, "text-justify");
+ parseRenderProperty<TextHorizontalAlignTypeClass>(value, render.text.horizontal_align, "text-horizontal-align");
+ parseRenderProperty<TextVerticalAlignTypeClass>(value, render.text.vertical_align, "text-vertical-align");
+ parseRenderProperty(value, render.text.max_angle, "text-max-angle");
+ parseRenderProperty(value, render.text.rotate, "text-rotate");
+ parseRenderProperty(value, render.text.slant, "text-slant");
+ parseRenderProperty(value, render.text.padding, "text-padding");
+ parseRenderProperty(value, render.text.keep_upright, "text-keep-upright");
+ parseRenderProperty<TextTransformTypeClass>(value, render.text.transform, "text-transform");
+ parseRenderProperty(value, render.text.offset, "text-offset");
+ parseRenderProperty<TranslateAnchorTypeClass>(value, render.text.translate_anchor, "text-translate-anchor");
+ parseRenderProperty(value, render.text.allow_overlap, "text-allow-overlap");
+ parseRenderProperty(value, render.text.ignore_placement, "text-ignore-placement");
+ parseRenderProperty(value, render.text.optional, "text-optional");
} break;
default:
// There are no render properties for these layer types.
diff --git a/src/style/style_properties.cpp b/src/style/style_properties.cpp
index 3d6bc41b81..1b05528d2f 100644
--- a/src/style/style_properties.cpp
+++ b/src/style/style_properties.cpp
@@ -4,8 +4,7 @@ namespace mbgl {
template<> const FillProperties &defaultStyleProperties() { static const FillProperties p; return p; }
template<> const LineProperties &defaultStyleProperties() { static const LineProperties p; return p; }
-template<> const IconProperties &defaultStyleProperties() { static const IconProperties p; return p; }
-template<> const TextProperties &defaultStyleProperties() { static const TextProperties p; return p; }
+template<> const SymbolProperties &defaultStyleProperties() { static const SymbolProperties p; return p; }
template<> const CompositeProperties &defaultStyleProperties() { static const CompositeProperties p; return p; }
template<> const RasterProperties &defaultStyleProperties() { static const RasterProperties p; return p; }
template<> const BackgroundProperties &defaultStyleProperties() { static const BackgroundProperties p; return p; }
diff --git a/src/text/collision.cpp b/src/text/collision.cpp
index 54b47e438b..4621423569 100644
--- a/src/text/collision.cpp
+++ b/src/text/collision.cpp
@@ -31,37 +31,59 @@ Collision::~Collision() {
delete ((Tree *)hTree);
}
-Collision::Collision() : cTree(new Tree()), hTree(new Tree()) {
+Collision::Collision(float zoom, float tileExtent, float tileSize, float placementDepth)
+ : hTree(new Tree()), // tree for horizontal labels
+ cTree(new Tree()), // tree for glyphs from curved labels
+
+ // tile pixels per screen pixels at the tile's zoom level
+ tilePixelRatio(tileExtent / tileSize),
+
+ zoom(zoom),
+
+ // Calculate the maximum scale we can go down in our fake-3d rtree so that
+ // placement still makes sense. This is calculated so that the minimum
+ // placement zoom can be at most 25.5 (we use an unsigned integer x10 to
+ // store the minimum zoom).
+ //
+ // We don't want to place labels all the way to 25.5. This lets too many
+ // glyphs be placed, slowing down collision checking. Only place labels if
+ // they will show up within the intended zoom range of the tile.
+ maxPlacementScale(std::exp(std::log(2) * util::min(3.0f, placementDepth, 25.5f - zoom))) {
const float m = 4096;
+ const float edge = m * tilePixelRatio * 2;
// Hack to prevent cross-tile labels
insert(
- {{GlyphBox{
- CollisionRect{CollisionPoint{0, 0}, CollisionPoint{0, m * 8}},
- CollisionRect{CollisionPoint{0, 0}, CollisionPoint{0, m * 8}}, 0},
- GlyphBox{
- CollisionRect{CollisionPoint{0, 0}, CollisionPoint{m * 8, 0}},
- CollisionRect{CollisionPoint{0, 0}, CollisionPoint{m * 8, 0}},
- 0}}},
- CollisionAnchor(0, 0), 1, {{M_PI * 2, 0}}, false, 2);
-
- insert({{GlyphBox{
- CollisionRect{CollisionPoint{-m * 8, 0}, CollisionPoint{0, 0}},
- CollisionRect{CollisionPoint{-m * 8, 0}, CollisionPoint{0, 0}},
- 0},
- GlyphBox{
- CollisionRect{CollisionPoint{0, -m * 8}, CollisionPoint{0, 0}},
- CollisionRect{CollisionPoint{0, -m * 8}, CollisionPoint{0, 0}},
- 0}}},
- CollisionAnchor{m, m}, 1, {{M_PI * 2, 0}}, false, 2);
+ /* glyphs */ {
+ GlyphBox{/* box */ CollisionRect{CollisionPoint{-edge, -edge}, CollisionPoint{0, edge}},
+ /* minScale */ 0,
+ /* padding */ 2},
+ GlyphBox{/* box */ CollisionRect{CollisionPoint{-edge, -edge}, CollisionPoint{edge, 0}},
+ /* minScale */ 0,
+ /* padding */ 2}},
+ /* anchor */ CollisionAnchor(0, 0),
+ /* placementScale */ 1,
+ /* placementRange */ {{M_PI * 2, 0}},
+ /* horizontal */ false);
+
+ insert(
+ /* glyphs */ {
+ GlyphBox{/* box*/ CollisionRect{CollisionPoint{-edge, 0}, CollisionPoint{edge, edge}},
+ /* minScale */ 0,
+ /* padding */ 2},
+ GlyphBox{/* box */ CollisionRect{CollisionPoint{0, -edge}, CollisionPoint{edge, edge}},
+ /* minScale */ 0,
+ /* padding */ 2}},
+ /* anchor */ CollisionAnchor(m, m),
+ /* placementScale */ 1,
+ /* placementRange */ {{M_PI * 2, 0}},
+ /* horizontal */ false);
}
-GlyphBox getMergedGlyphs(const GlyphBoxes &boxes, bool horizontal,
- const CollisionAnchor &anchor) {
+GlyphBox getMergedGlyphs(const GlyphBoxes &boxes, const CollisionAnchor &anchor) {
GlyphBox mergedGlyphs;
const float inf = std::numeric_limits<float>::infinity();
mergedGlyphs.box = CollisionRect{{inf, inf}, {-inf, -inf}};
- mergedGlyphs.rotate = horizontal;
mergedGlyphs.anchor = anchor;
CollisionRect &box = mergedGlyphs.box;
@@ -71,105 +93,51 @@ GlyphBox getMergedGlyphs(const GlyphBoxes &boxes, bool horizontal,
box.tl.y = util::min(box.tl.y, gbox.tl.y);
box.br.x = util::max(box.br.x, gbox.br.x);
box.br.y = util::max(box.br.y, gbox.br.y);
- mergedGlyphs.minScale =
- util::max(mergedGlyphs.minScale, glyph.minScale);
+ mergedGlyphs.minScale = util::max(mergedGlyphs.minScale, glyph.minScale);
}
return mergedGlyphs;
}
-PlacementProperty Collision::place(const GlyphBoxes &boxes,
- const CollisionAnchor &anchor,
- float minPlacementScale,
- float maxPlacementScale, float padding,
- bool horizontal, bool alwaysVisible) {
-
- float minScale = std::numeric_limits<float>::infinity();
- for (const GlyphBox &glyphBox : boxes) {
- minScale = util::min(minScale, glyphBox.minScale);
- }
- minPlacementScale = util::max(minPlacementScale, minScale);
-
- // Collision checks between rotating and fixed labels are
- // relatively expensive, so we use one box per label, not per glyph
- // for horizontal labels.
- GlyphBoxes glyphs;
- if (horizontal) {
- glyphs.push_back(getMergedGlyphs(boxes, horizontal, anchor));
- } else {
- glyphs = boxes;
- }
-
- // Calculate bboxes for all the glyphs
- for (GlyphBox &glyph : glyphs) {
- if (horizontal) {
- const CollisionRect &box = glyph.box;
- float x12 = box.tl.x * box.tl.x, y12 = box.tl.y * box.tl.y,
- x22 = box.br.x * box.br.x, y22 = box.br.y * box.br.y,
- diag = std::sqrt(
- util::max(x12 + y12, x12 + y22, x22 + y12, x22 + y22));
-
- glyph.bbox = CollisionRect{{-diag, -diag}, {diag, diag}};
- } else {
- glyph.bbox = glyph.box;
- }
- }
-
- // Calculate the minimum scale the entire label can be shown without
- // collisions
- float scale = alwaysVisible ? minPlacementScale
- : getPlacementScale(glyphs, minPlacementScale,
- maxPlacementScale, padding);
-
- // Return if the label can never be placed without collision
- if (scale < 0 || scale == std::numeric_limits<float>::infinity()) {
- return PlacementProperty{};
- }
-
- // Calculate the range it is safe to rotate all glyphs
- PlacementRange rotationRange = getPlacementRange(glyphs, scale, horizontal);
- insert(glyphs, anchor, scale, rotationRange, horizontal, padding);
-
- float zoom = log(scale) / log(2);
-
- return PlacementProperty{zoom, rotationRange};
-}
+Box getBox(const CollisionAnchor &anchor, const CollisionRect &bbox, float minScale,
+ float maxScale) {
+ return Box{
+ Point{
+ anchor.x + util::min(bbox.tl.x / minScale, bbox.tl.x / maxScale),
+ anchor.y + util::min(bbox.tl.y / minScale, bbox.tl.y / maxScale),
+ },
+ Point{
+ anchor.x + util::max(bbox.br.x / minScale, bbox.br.x / maxScale),
+ anchor.y + util::max(bbox.br.y / minScale, bbox.br.y / maxScale),
+ },
+ };
+};
-float Collision::getPlacementScale(const GlyphBoxes &glyphs,
- float minPlacementScale,
- float maxPlacementScale, float pad) {
+float Collision::getPlacementScale(const GlyphBoxes &glyphs, float minPlacementScale) {
for (const GlyphBox &glyph : glyphs) {
- const CollisionRect &bbox = glyph.bbox;
const CollisionRect &box = glyph.box;
+ const CollisionRect &bbox = glyph.hBox ? glyph.hBox.get() : glyph.box;
const CollisionAnchor &anchor = glyph.anchor;
+ const float pad = glyph.padding;
- if (anchor.x < 0 || anchor.x > 4096 || anchor.y < 0 ||
- anchor.y > 4096) {
- return -1;
+ if (anchor.x < 0 || anchor.x > 4096 || anchor.y < 0 || anchor.y > 4096) {
+ return 0;
}
float minScale = std::fmax(minPlacementScale, glyph.minScale);
- float maxScale = glyph.maxScale;
+ float maxScale = glyph.maxScale != 0 ? glyph.maxScale : std::numeric_limits<float>::infinity();
if (minScale >= maxScale) {
continue;
}
// Compute the scaled bounding box of the unrotated glyph
- float minPlacedX = anchor.x + bbox.tl.x / minScale;
- float minPlacedY = anchor.y + bbox.tl.y / minScale;
- float maxPlacedX = anchor.x + bbox.br.x / minScale;
- float maxPlacedY = anchor.y + bbox.br.y / minScale;
-
- Box query_box{Point{minPlacedX, minPlacedY},
- Point{maxPlacedX, maxPlacedY}};
+ const Box searchBox = getBox(anchor, bbox, minScale, maxScale);
std::vector<PlacementValue> blocking;
- ((Tree *)cTree)
- ->query(bgi::intersects(query_box), std::back_inserter(blocking));
- ((Tree *)hTree)
- ->query(bgi::intersects(query_box), std::back_inserter(blocking));
+ ((Tree *)hTree)->query(bgi::intersects(searchBox), std::back_inserter(blocking));
+ ((Tree *)cTree)->query(bgi::intersects(searchBox), std::back_inserter(blocking));
if (blocking.size()) {
const CollisionAnchor &na = anchor; // new anchor
@@ -184,7 +152,7 @@ float Collision::getPlacementScale(const GlyphBoxes &glyphs,
// NOTE: this isn't right because there can be glyphs with
// the same anchor but differing box offsets.
if (na == oa) {
- return -1;
+ return 0;
}
// todo: unhardcode the 8 = tileExtent/tileSize
@@ -192,17 +160,13 @@ float Collision::getPlacementScale(const GlyphBoxes &glyphs,
// Original algorithm:
float s1 = (ob.tl.x - nb.br.x - padding) /
- (na.x - oa.x); // scale at which new box is to the
- // left of old box
+ (na.x - oa.x); // scale at which new box is to the left of old box
float s2 = (ob.br.x - nb.tl.x + padding) /
- (na.x - oa.x); // scale at which new box is to the
- // right of old box
+ (na.x - oa.x); // scale at which new box is to the right of old box
float s3 = (ob.tl.y - nb.br.y - padding) /
- (na.y - oa.y); // scale at which new box is to the
- // top of old box
+ (na.y - oa.y); // scale at which new box is to the top of old box
float s4 = (ob.br.y - nb.tl.y + padding) /
- (na.y - oa.y); // scale at which new box is to the
- // bottom of old box
+ (na.y - oa.y); // scale at which new box is to the bottom of old box
if (isnan(s1) || isnan(s2)) {
s1 = s2 = 1;
@@ -211,7 +175,7 @@ float Collision::getPlacementScale(const GlyphBoxes &glyphs,
s3 = s4 = 1;
}
- float collisionFreeScale = std::fmin(std::fmax(s1, s2), std::fmax(s3, s4));
+ const float collisionFreeScale = std::fmin(std::fmax(s1, s2), std::fmax(s3, s4));
// Only update label's min scale if the glyph was
// restricted by a collision
@@ -223,7 +187,7 @@ float Collision::getPlacementScale(const GlyphBoxes &glyphs,
}
if (minPlacementScale > maxPlacementScale) {
- return -1;
+ return 0;
}
}
}
@@ -232,13 +196,12 @@ float Collision::getPlacementScale(const GlyphBoxes &glyphs,
return minPlacementScale;
}
-PlacementRange Collision::getPlacementRange(const GlyphBoxes &glyphs,
- float placementScale,
+PlacementRange Collision::getPlacementRange(const GlyphBoxes &glyphs, float placementScale,
bool horizontal) {
PlacementRange placementRange = {{2.0f * M_PI, 0}};
for (const GlyphBox &glyph : glyphs) {
- const CollisionRect &bbox = glyph.bbox;
+ const CollisionRect &bbox = glyph.hBox ? glyph.hBox.get() : glyph.box;
const CollisionAnchor &anchor = glyph.anchor;
float minPlacedX = anchor.x + bbox.tl.x / placementScale;
@@ -246,30 +209,28 @@ PlacementRange Collision::getPlacementRange(const GlyphBoxes &glyphs,
float maxPlacedX = anchor.x + bbox.br.x / placementScale;
float maxPlacedY = anchor.y + bbox.br.y / placementScale;
- Box query_box{Point{minPlacedX, minPlacedY},
- Point{maxPlacedX, maxPlacedY}};
+ Box query_box{Point{minPlacedX, minPlacedY}, Point{maxPlacedX, maxPlacedY}};
std::vector<PlacementValue> blocking;
- ((Tree *)hTree)
- ->query(bgi::intersects(query_box), std::back_inserter(blocking));
+ ((Tree *)hTree)->query(bgi::intersects(query_box), std::back_inserter(blocking));
if (horizontal) {
- ((Tree *)cTree)
- ->query(bgi::intersects(query_box), std::back_inserter(blocking));
+ ((Tree *)cTree)->query(bgi::intersects(query_box), std::back_inserter(blocking));
}
for (const PlacementValue &value : blocking) {
const Box &s = std::get<0>(value);
const PlacementBox &b = std::get<1>(value);
+ const CollisionRect &bbox2 = b.hBox ? b.hBox.get() : b.box;
float x1, x2, y1, y2, intersectX, intersectY;
// Adjust and compare bboxes to see if the glyphs might intersect
if (placementScale > b.placementScale) {
- x1 = b.anchor.x + b.bbox.tl.x / placementScale;
- y1 = b.anchor.y + b.bbox.tl.y / placementScale;
- x2 = b.anchor.x + b.bbox.br.x / placementScale;
- y2 = b.anchor.y + b.bbox.br.y / placementScale;
+ x1 = b.anchor.x + bbox2.tl.x / placementScale;
+ y1 = b.anchor.y + bbox2.tl.y / placementScale;
+ x2 = b.anchor.x + bbox2.br.x / placementScale;
+ y2 = b.anchor.y + bbox2.br.y / placementScale;
intersectX = x1 < maxPlacedX && x2 > minPlacedX;
intersectY = y1 < maxPlacedY && y2 > minPlacedY;
} else {
@@ -278,10 +239,8 @@ PlacementRange Collision::getPlacementRange(const GlyphBoxes &glyphs,
x2 = anchor.x + bbox.br.x / b.placementScale;
y2 = anchor.y + bbox.br.y / b.placementScale;
- intersectX = x1 < s.max_corner().get<0>() &&
- x2 > s.min_corner().get<0>();
- intersectY = y1 < s.max_corner().get<1>() &&
- y2 > s.min_corner().get<1>();
+ intersectX = x1 < s.max_corner().get<0>() && x2 > s.min_corner().get<0>();
+ intersectY = y1 < s.max_corner().get<1>() && y2 > s.min_corner().get<1>();
}
// If they can't intersect, skip more expensive rotation calculation
@@ -301,45 +260,40 @@ PlacementRange Collision::getPlacementRange(const GlyphBoxes &glyphs,
};
void Collision::insert(const GlyphBoxes &glyphs, const CollisionAnchor &anchor,
- float placementScale,
- const PlacementRange &placementRange, bool horizontal,
- float padding) {
+ float placementScale, const PlacementRange &placementRange,
+ bool horizontal) {
assert(placementScale != std::numeric_limits<float>::infinity());
- std::vector<PlacementValue> result;
- result.reserve(glyphs.size());
+ std::vector<PlacementValue> allBounds;
+ allBounds.reserve(glyphs.size());
for (const GlyphBox &glyph : glyphs) {
- const CollisionRect &bbox = glyph.bbox;
const CollisionRect &box = glyph.box;
+ const CollisionRect &bbox = glyph.hBox ? glyph.hBox.get() : glyph.box;
- float minScale = std::fmax(placementScale, glyph.minScale);
+ const float minScale = util::max(placementScale, glyph.minScale);
+ const float maxScale = glyph.maxScale != 0 ? glyph.maxScale : std::numeric_limits<float>::infinity();
- Box bounds{Point{anchor.x + bbox.tl.x / minScale,
- anchor.y + bbox.tl.y / minScale},
- Point{anchor.x + bbox.br.x / minScale,
- anchor.y + bbox.br.y / minScale}};
+ const Box bounds = getBox(anchor, bbox, minScale, maxScale);
PlacementBox placement;
placement.anchor = anchor;
placement.box = box;
- placement.bbox = bbox;
- placement.rotate = horizontal;
+ if (glyph.hBox) {
+ placement.hBox = bbox;
+ }
placement.placementRange = placementRange;
placement.placementScale = minScale;
- placement.maxScale = glyph.maxScale;
- placement.padding = padding;
-
- assert(!isnan(bounds.min_corner().get<0>()) && !isnan(bounds.min_corner().get<1>()));
- assert(!isnan(bounds.max_corner().get<0>()) && !isnan(bounds.max_corner().get<1>()));
+ placement.maxScale = maxScale;
+ placement.padding = glyph.padding;
- result.emplace_back(bounds, placement);
+ allBounds.emplace_back(bounds, placement);
}
// Bulk-insert all glyph boxes
if (horizontal) {
- ((Tree *)hTree)->insert(result.begin(), result.end());
+ ((Tree *)hTree)->insert(allBounds.begin(), allBounds.end());
} else {
- ((Tree *)cTree)->insert(result.begin(), result.end());
+ ((Tree *)cTree)->insert(allBounds.begin(), allBounds.end());
}
}
diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp
index edcecde7ff..4b90b51c24 100644
--- a/src/text/glyph_store.cpp
+++ b/src/text/glyph_store.cpp
@@ -6,6 +6,8 @@
#include <mbgl/util/pbf.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/token.hpp>
+#include <mbgl/util/math.hpp>
+#include <mbgl/util/filesource.hpp>
#include <mbgl/platform/platform.hpp>
#include <uv.h>
#include <algorithm>
@@ -30,93 +32,111 @@ const std::map<uint32_t, SDFGlyph> &FontStack::getSDFs() const {
return sdfs;
}
-const Shaping FontStack::getShaping(const std::u32string &string, const float &maxWidth,
- const float &lineHeight, const float &alignment, const float &verticalAlignment,
- const float &letterSpacing) const {
-
+const Shaping FontStack::getShaping(const std::u32string &string, const float maxWidth,
+ const float lineHeight, const float horizontalAlign,
+ const float verticalAlign, const float justify,
+ const float spacing, const vec2<float> &translate) const {
std::lock_guard<std::mutex> lock(mtx);
- uint32_t i = 0;
- uint32_t x = 0;
+
Shaping shaping;
+
+ int32_t x = std::round(translate.x * 24); // one em
+ const int32_t y = std::round(translate.y * 24); // one em
+
// Loop through all characters of this label and shape.
for (uint32_t chr : string) {
- shaping.emplace_back(0, chr, x, 0);
- i++;
+ shaping.emplace_back(chr, x, y);
auto metric = metrics.find(chr);
if (metric != metrics.end()) {
- x += metric->second.advance + letterSpacing;
+ x += metric->second.advance + spacing;
}
}
- lineWrap(shaping, lineHeight, maxWidth, alignment, verticalAlignment);
+ if (!shaping.size())
+ return shaping;
+
+ lineWrap(shaping, lineHeight, maxWidth, horizontalAlign, verticalAlign, justify);
return shaping;
}
-void alignVertically(Shaping &shaping, const uint32_t &lines, const float &lineHeight, const float &verticalAlign) {
- const float dy = -(lineHeight * (lines - 1) + 24) * verticalAlign - 5;
- for (GlyphPlacement &shape : shaping) {
- shape.y += dy;
+void align(Shaping &shaping, const float justify, const float horizontalAlign,
+ const float verticalAlign, const uint32_t maxLineLength, const float lineHeight,
+ const uint32_t line) {
+ const float shiftX = (justify - horizontalAlign) * maxLineLength;
+ const float shiftY = (-verticalAlign * (line + 1) + 0.5) * lineHeight;
+
+ for (PositionedGlyph &glyph : shaping) {
+ glyph.x += shiftX;
+ glyph.y += shiftY;
}
}
-void alignHorizontally(Shaping &shaping, const std::map<uint32_t, GlyphMetrics> &metrics,
- const uint32_t &start, const uint32_t &end, const float &alignment) {
- auto & shape = shaping.at(end);
- auto metric = metrics.find(shape.glyph);
+void justifyLine(Shaping &shaping, const std::map<uint32_t, GlyphMetrics> &metrics, uint32_t start,
+ uint32_t end, float justify) {
+ PositionedGlyph &glyph = shaping[end];
+ auto metric = metrics.find(glyph.glyph);
if (metric != metrics.end()) {
- uint32_t lastAdvance = metric->second.advance;
- int32_t lineIndent = (shape.x + lastAdvance) * alignment;
+ const uint32_t lastAdvance = metric->second.advance;
+ const float lineIndent = float(glyph.x + lastAdvance) * justify;
+
for (uint32_t j = start; j <= end; j++) {
shaping[j].x -= lineIndent;
}
}
}
-void FontStack::lineWrap(Shaping &shaping, const float &lineHeight, const float &maxWidth,
- const float &alignment, const float &verticalAlignment) const {
-
- std::size_t num_shapes = shaping.size();
- if (!num_shapes) {
- return;
- }
+void FontStack::lineWrap(Shaping &shaping, const float lineHeight, const float maxWidth,
+ const float horizontalAlign, const float verticalAlign,
+ const float justify) const {
uint32_t lastSafeBreak = 0;
+
uint32_t lengthBeforeCurrentLine = 0;
uint32_t lineStartIndex = 0;
uint32_t line = 0;
- for (uint32_t i = 0; i < shaping.size(); i++) {
- GlyphPlacement &shape = shaping[i];
- shape.x -= lengthBeforeCurrentLine;
- shape.y += lineHeight * line;
+ uint32_t maxLineLength = 0;
- if (shape.x > maxWidth && lastSafeBreak > 0) {
+ if (maxWidth) {
+ for (uint32_t i = 0; i < shaping.size(); i++) {
+ PositionedGlyph &shape = shaping[i];
- uint32_t lineLength = shaping[lastSafeBreak + 1].x;
+ shape.x -= lengthBeforeCurrentLine;
+ shape.y += lineHeight * line;
- for (uint32_t k = lastSafeBreak + 1; k <= i; k++) {
- shaping[k].y += lineHeight;
- shaping[k].x -= lineLength;
- }
+ if (shape.x > maxWidth && lastSafeBreak > 0) {
+
+ uint32_t lineLength = shaping[lastSafeBreak + 1].x;
+ maxLineLength = util::max(lineLength, maxLineLength);
- if (alignment) {
- alignHorizontally(shaping, metrics, lineStartIndex, lastSafeBreak - 1, alignment);
+ for (uint32_t k = lastSafeBreak + 1; k <= i; k++) {
+ shaping[k].y += lineHeight;
+ shaping[k].x -= lineLength;
+ }
+
+ if (justify) {
+ justifyLine(shaping, metrics, lineStartIndex, lastSafeBreak - 1, justify);
+ }
+
+ lineStartIndex = lastSafeBreak + 1;
+ lastSafeBreak = 0;
+ lengthBeforeCurrentLine += lineLength;
+ line++;
}
- lineStartIndex = lastSafeBreak + 1;
- lastSafeBreak = 0;
- lengthBeforeCurrentLine += lineLength;
- line++;
- }
- if (shape.glyph == 32) {
- lastSafeBreak = i;
+ if (shape.glyph == 32) {
+ lastSafeBreak = i;
+ }
}
}
- alignHorizontally(shaping, metrics, lineStartIndex, shaping.size() - 1, alignment);
- alignVertically(shaping, line + 1, lineHeight, verticalAlignment);
+
+ maxLineLength = maxLineLength || shaping.back().x;
+
+ justifyLine(shaping, metrics, lineStartIndex, shaping.size() - 1, justify);
+ align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line);
}
-GlyphPBF::GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange)
+GlyphPBF::GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange, const std::shared_ptr<FileSource> &fileSource)
: future(promise.get_future().share())
{
// Load the glyph set URL
@@ -133,7 +153,7 @@ GlyphPBF::GlyphPBF(const std::string &glyphURL, const std::string &fontStack, Gl
fprintf(stderr, "%s\n", url.c_str());
#endif
- platform::request_http(url, [&](platform::Response *res) {
+ fileSource->load(ResourceType::Glyphs, url, [&](platform::Response *res) {
if (res->code != 200) {
// Something went wrong with loading the glyph pbf. Pass on the error to the future listeners.
const std::string msg = util::sprintf<255>("[ERROR] failed to load glyphs (%d): %s\n", res->code, res->error_message.c_str());
@@ -207,12 +227,19 @@ void GlyphPBF::parse(FontStack &stack) {
data.clear();
}
-GlyphStore::GlyphStore(const std::string &glyphURL)
- : glyphURL(glyphURL) {}
+GlyphStore::GlyphStore(const std::shared_ptr<FileSource> &fileSource) : fileSource(fileSource) {}
+
+void GlyphStore::setURL(const std::string &url) {
+ glyphURL = url;
+}
+
void GlyphStore::waitForGlyphRanges(const std::string &fontStack, const std::set<GlyphRange> &glyphRanges) {
// We are implementing a blocking wait with futures: Every GlyphSet has a future that we are
// waiting for until it is loaded.
+ if (glyphRanges.empty()) {
+ return;
+ }
FontStack *stack = nullptr;
@@ -243,7 +270,7 @@ std::shared_future<GlyphPBF &> GlyphStore::loadGlyphRange(const std::string &fon
auto range_it = rangeSets.find(range);
if (range_it == rangeSets.end()) {
// We don't have this glyph set yet for this font stack.
- range_it = rangeSets.emplace(range, std::make_unique<GlyphPBF>(glyphURL, fontStack, range)).first;
+ range_it = rangeSets.emplace(range, std::make_unique<GlyphPBF>(glyphURL, fontStack, range, fileSource)).first;
}
return range_it->second->getFuture();
diff --git a/src/text/placement.cpp b/src/text/placement.cpp
index e33a4bdec6..26cc9f70f7 100644
--- a/src/text/placement.cpp
+++ b/src/text/placement.cpp
@@ -1,73 +1,34 @@
#include <mbgl/text/placement.hpp>
-#include <mbgl/map/vector_tile.hpp>
-#include <mbgl/geometry/interpolate.hpp>
-#include <mbgl/renderer/text_bucket.hpp>
+#include <mbgl/geometry/anchor.hpp>
+#include <mbgl/text/glyph.hpp>
+#include <mbgl/text/placement.hpp>
+#include <mbgl/text/glyph_store.hpp>
+#include <mbgl/style/style_bucket.hpp>
+
#include <mbgl/util/math.hpp>
-#include <mbgl/util/constants.hpp>
-
-#include <algorithm>
-
-using namespace mbgl;
-
-const int Placement::tileExtent = 4096;
-const int Placement::glyphSize =
- 24; // size in pixels of this glyphs in the tile
-const float Placement::minScale = 0.5; // underscale by 1 zoom level
-
-Placement::Placement(int8_t zoom)
- : zoom(zoom),
- zOffset(log(256.0 / util::tileSize) / log(2)),
-
- // Calculate the maximum scale we can go down in our fake-3d rtree so that
- // placement still makes sense. This is calculated so that the minimum
- // placement zoom can be at most 25.5 (we use an unsigned integer x10 to
- // store the minimum zoom).
- //
- // We don't want to place labels all the way to 25.5. This lets too many
- // glyphs be placed, slowing down collision checking. Only place labels if
- // they will show up within the intended zoom range of the tile.
- // TODO make this not hardcoded to 3
- maxPlacementScale(std::exp(log(2) * util::min((25.5 - zoom), 3.0))) {}
-
-bool byScale(const Anchor &a, const Anchor &b) { return a.scale < b.scale; }
-
-static const Glyph null_glyph;
-
-inline const Glyph &getGlyph(const GlyphPlacement &placed,
- const GlyphPositions &face) {
- auto it = face.find(placed.glyph);
- if (it != face.end()) {
- return it->second;
- } else {
- fprintf(stderr, "glyph %d does not exist\n", placed.glyph);
- }
- return null_glyph;
-}
+namespace mbgl {
+
+const float Placement::globalMinScale = 0.5; // underscale by 1 zoom level
struct GlyphInstance {
explicit GlyphInstance(const vec2<float> &anchor) : anchor(anchor) {}
- explicit GlyphInstance(const vec2<float> &anchor, float offset,
- float minScale, float maxScale, float angle)
- : anchor(anchor),
- offset(offset),
- minScale(minScale),
- maxScale(maxScale),
- angle(angle) {}
+ explicit GlyphInstance(const vec2<float> &anchor, float offset, float minScale, float maxScale,
+ float angle)
+ : anchor(anchor), offset(offset), minScale(minScale), maxScale(maxScale), angle(angle) {}
const vec2<float> anchor;
const float offset = 0.0f;
- const float minScale = Placement::minScale;
+ const float minScale = Placement::globalMinScale;
const float maxScale = std::numeric_limits<float>::infinity();
const float angle = 0.0f;
};
typedef std::vector<GlyphInstance> GlyphInstances;
-void getSegmentGlyphs(std::back_insert_iterator<GlyphInstances> glyphs,
- Anchor &anchor, float offset,
- const std::vector<Coordinate> &line, int segment,
- int8_t direction, float maxAngleDelta) {
+void getSegmentGlyphs(std::back_insert_iterator<GlyphInstances> glyphs, Anchor &anchor,
+ float offset, const std::vector<Coordinate> &line, int segment,
+ int8_t direction, float maxAngle) {
const bool upsideDown = direction < 0;
if (offset < 0)
@@ -92,14 +53,14 @@ void getSegmentGlyphs(std::back_insert_iterator<GlyphInstances> glyphs,
while (true) {
const float dist = util::dist<float>(newAnchor, end);
const float scale = offset / dist;
- float angle = -std::atan2(end.x - newAnchor.x, end.y - newAnchor.y) +
- direction * M_PI / 2.0f;
+ float angle =
+ -std::atan2(end.x - newAnchor.x, end.y - newAnchor.y) + direction * M_PI / 2.0f;
if (upsideDown)
angle += M_PI;
// Don't place around sharp corners
float angleDiff = std::fmod((angle - prevAngle), (2.0f * M_PI));
- if (prevAngle && std::fabs(angleDiff) > maxAngleDelta) {
+ if (prevAngle && std::fabs(angleDiff) > maxAngle) {
anchor.scale = prevscale;
break;
}
@@ -109,8 +70,7 @@ void getSegmentGlyphs(std::back_insert_iterator<GlyphInstances> glyphs,
/* offset */ static_cast<float>(upsideDown ? M_PI : 0.0),
/* minScale */ scale,
/* maxScale */ prevscale,
- /* angle */ static_cast<float>(
- std::fmod((angle + 2.0 * M_PI), (2.0 * M_PI)))};
+ /* angle */ static_cast<float>(std::fmod((angle + 2.0 * M_PI), (2.0 * M_PI)))};
if (scale <= placementScale)
break;
@@ -135,49 +95,152 @@ void getSegmentGlyphs(std::back_insert_iterator<GlyphInstances> glyphs,
}
}
-void getGlyphs(PlacedGlyphs &glyphs, GlyphBoxes &boxes,
- Anchor &anchor, vec2<float> origin, const Shaping &shaping,
- const GlyphPositions &face, float fontScale,
- bool horizontal, const std::vector<Coordinate> &line,
- float maxAngleDelta, float rotate) {
- // The total text advance is the width of this label.
-
- // TODO: allow setting an alignment
- // var alignment = 'center';
- // if (alignment == 'center') {
- // origin.x -= advance / 2;
- // } else if (alignment == 'right') {
- // origin.x -= advance;
- // }
+GlyphBox getMergedBoxes(const GlyphBoxes &glyphs, const Anchor &anchor) {
+ // Collision checks between rotating and fixed labels are relatively expensive,
+ // so we use one box per label, not per glyph for horizontal labels.
+
+ const float inf = std::numeric_limits<float>::infinity();
+
+ GlyphBox mergedglyphs{/* box */ CollisionRect{inf, inf, -inf, -inf},
+ /* anchor */ anchor,
+ /* minScale */ 0,
+ /* maxScale */ inf,
+ /* padding */ -inf};
+
+ CollisionRect &box = mergedglyphs.box;
+
+ for (const GlyphBox &glyph : glyphs) {
+ const CollisionRect &gbox = glyph.box;
+ box.tl.x = util::min(box.tl.x, gbox.tl.x);
+ box.tl.y = util::min(box.tl.y, gbox.tl.y);
+ box.br.x = util::max(box.br.x, gbox.br.x);
+ box.br.y = util::max(box.br.y, gbox.br.y);
+ mergedglyphs.minScale = util::max(mergedglyphs.minScale, glyph.minScale);
+ mergedglyphs.padding = util::max(mergedglyphs.padding, glyph.padding);
+ }
+ // for all horizontal labels, calculate bbox covering all rotated positions
+ float x12 = box.tl.x * box.tl.x, y12 = box.tl.y * box.tl.y, x22 = box.br.x * box.br.x,
+ y22 = box.br.y * box.br.y,
+ diag = std::sqrt(util::max(x12 + y12, x12 + y22, x22 + y12, x22 + y22));
+
+ mergedglyphs.hBox = CollisionRect{-diag, -diag, diag, diag};
+
+ return mergedglyphs;
+}
+
+Placement Placement::getIcon(Anchor &anchor, const Rect<uint16_t> &image, float boxScale,
+ const std::vector<Coordinate> &line, const StyleBucketSymbol &props) {
+ const float x = image.w / 2.0f; // No need to divide by image.pixelRatio here?
+ const float y = image.h / 2.0f; // image.pixelRatio;
+
+ const float dx = props.icon.offset.x;
+ const float dy = props.icon.offset.y;
+ float x1 = (dx - x);
+ float x2 = (dx + x);
+ float y1 = (dy - y);
+ float y2 = (dy + y);
+
+ vec2<float> tl{x1, y1};
+ vec2<float> tr{x2, y1};
+ vec2<float> br{x2, y2};
+ vec2<float> bl{x1, y2};
+
+ float angle = props.icon.rotate * M_PI / 180.0f;
+ if (anchor.segment >= 0 && props.icon.rotation_alignment != RotationAlignmentType::Viewport) {
+ const Coordinate &next = line[anchor.segment];
+ angle += -std::atan2(next.x - anchor.x, next.y - anchor.y) + M_PI / 2;
+ }
+
+ if (angle) {
+ // Compute the transformation matrix.
+ float angle_sin = std::sin(angle);
+ float angle_cos = std::cos(angle);
+ std::array<float, 4> matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}};
+
+ tl = tl.matMul(matrix);
+ tr = tr.matMul(matrix);
+ bl = bl.matMul(matrix);
+ br = br.matMul(matrix);
+
+ x1 = util::min(tl.x, tr.x, bl.x, br.x);
+ x2 = util::max(tl.x, tr.x, bl.x, br.x);
+ y1 = util::min(tl.y, tr.y, bl.y, br.y);
+ y2 = util::max(tl.y, tr.y, bl.y, br.y);
+ }
+
+ const CollisionRect box{/* x1 */ x1 * boxScale,
+ /* y1 */ y1 * boxScale,
+ /* x2 */ x2 * boxScale,
+ /* y2 */ y2 * boxScale};
+
+ Placement placement;
+
+ placement.boxes.emplace_back(
+ /* box */ box,
+ /* anchor */ anchor,
+ /* minScale */ Placement::globalMinScale,
+ /* maxScale */ std::numeric_limits<float>::infinity(),
+ /* padding */ props.icon.padding);
+
+ placement.shapes.emplace_back(
+ /* tl */ tl,
+ /* tr */ tr,
+ /* bl */ bl,
+ /* br */ br,
+ /* image */ image,
+ /* angle */ 0,
+ /* anchors */ anchor,
+ /* minScale */ Placement::globalMinScale,
+ /* maxScale */ std::numeric_limits<float>::infinity());
+
+ placement.minScale = anchor.scale;
+
+ return placement;
+}
+
+Placement Placement::getGlyphs(Anchor &anchor, const vec2<float> &origin, const Shaping &shaping,
+ const GlyphPositions &face, float boxScale, bool horizontal,
+ const std::vector<Coordinate> &line,
+ const StyleBucketSymbol &props) {
+ const float maxAngle = props.text.max_angle * M_PI / 180;
+ const float rotate = props.text.rotate * M_PI / 180;
+ const float padding = props.text.padding;
+ const bool alongLine = props.text.rotation_alignment != RotationAlignmentType::Viewport;
+ const bool keepUpright = props.text.keep_upright;
+
+ Placement placement;
const uint32_t buffer = 3;
- for (const GlyphPlacement &placed : shaping) {
- const Glyph &glyph = getGlyph(placed, face);
- if (!glyph) {
- // This glyph is empty and doesn't have any pixels that we'd need to
- // show.
+ for (const PositionedGlyph &shape : shaping) {
+ auto face_it = face.find(shape.glyph);
+ if (face_it == face.end())
continue;
- }
+ const Glyph &glyph = face_it->second;
+ const Rect<uint16_t> &rect = glyph.rect;
- float x =
- (origin.x + placed.x + glyph.metrics.left - buffer + glyph.rect.w / 2) *
- fontScale;
+ if (!glyph)
+ continue;
+
+ if (!rect)
+ continue;
+
+ const float x = (origin.x + shape.x + glyph.metrics.left - buffer + rect.w / 2) * boxScale;
GlyphInstances glyphInstances;
- if (anchor.segment >= 0) {
- getSegmentGlyphs(std::back_inserter(glyphInstances), anchor, x,
- line, anchor.segment, 1, maxAngleDelta);
- getSegmentGlyphs(std::back_inserter(glyphInstances), anchor, x,
- line, anchor.segment, -1, maxAngleDelta);
+ if (anchor.segment >= 0 && alongLine) {
+ getSegmentGlyphs(std::back_inserter(glyphInstances), anchor, x, line, anchor.segment, 1,
+ maxAngle);
+ if (keepUpright)
+ getSegmentGlyphs(std::back_inserter(glyphInstances), anchor, x, line,
+ anchor.segment, -1, maxAngle);
} else {
-
glyphInstances.emplace_back(GlyphInstance{anchor});
}
- const float x1 = origin.x + placed.x + glyph.metrics.left - buffer;
- const float y1 = origin.y + placed.y - glyph.metrics.top - buffer;
+ const float x1 = origin.x + shape.x + glyph.metrics.left - buffer;
+ const float y1 = origin.y + shape.y - glyph.metrics.top - buffer;
const float x2 = x1 + glyph.rect.w;
const float y2 = y1 + glyph.rect.h;
@@ -186,8 +249,7 @@ void getGlyphs(PlacedGlyphs &glyphs, GlyphBoxes &boxes,
const vec2<float> obl{x1, y2};
const vec2<float> obr{x2, y2};
- const CollisionRect obox{fontScale *x1, fontScale *y1,
- fontScale *x2, fontScale *y2};
+ const CollisionRect obox{boxScale * x1, boxScale * y1, boxScale * x2, boxScale * y2};
for (const GlyphInstance &instance : glyphInstances) {
vec2<float> tl = otl;
@@ -204,78 +266,47 @@ void getGlyphs(PlacedGlyphs &glyphs, GlyphBoxes &boxes,
// Compute the transformation matrix.
float angle_sin = std::sin(angle);
float angle_cos = std::cos(angle);
- std::array<float, 4> matrix = {
- {angle_cos, -angle_sin, angle_sin, angle_cos}};
+ std::array<float, 4> matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}};
tl = tl.matMul(matrix);
tr = tr.matMul(matrix);
bl = bl.matMul(matrix);
br = br.matMul(matrix);
-
- // Calculate the rotated glyph's bounding box offsets from the
- // anchor point.
- box = CollisionRect{
- fontScale * util::min(tl.x, tr.x, bl.x, br.x),
- fontScale * util::min(tl.y, tr.y, bl.y, br.y),
- fontScale * util::max(tl.x, tr.x, bl.x, br.x),
- fontScale * util::max(tl.y, tr.y, bl.y, br.y)};
}
- GlyphBox glyphBox = GlyphBox{
- box,
- // Prevent label from extending past the end of the line
- util::max(instance.minScale, anchor.scale),
- instance.maxScale,
- instance.anchor,
- horizontal};
+ // Prevent label from extending past the end of the line
+ const float glyphMinScale = std::max(instance.minScale, anchor.scale);
// Remember the glyph for later insertion.
- glyphs.emplace_back(PlacedGlyph{
- tl, tr, bl, br, glyph.rect,
- static_cast<float>(
- std::fmod((anchor.angle + rotate + instance.offset + 2 * M_PI), (2 * M_PI))),
- glyphBox});
-
- if (instance.offset == 0.0f) {
- boxes.emplace_back(glyphBox);
+ placement.shapes.emplace_back(
+ tl, tr, bl, br, rect,
+ float(std::fmod((anchor.angle + rotate + instance.offset + 2 * M_PI), (2 * M_PI))),
+ instance.anchor, glyphMinScale, instance.maxScale);
+
+ if (!instance.offset) { // not a flipped glyph
+ if (angle) {
+ // Calculate the rotated glyph's bounding box offsets from the anchor point.
+ box = CollisionRect{boxScale * util::min(tl.x, tr.x, bl.x, br.x),
+ boxScale * util::min(tl.y, tr.y, bl.y, br.y),
+ boxScale * util::max(tl.x, tr.x, bl.x, br.x),
+ boxScale * util::max(tl.y, tr.y, bl.y, br.y)};
+ }
+ placement.boxes.emplace_back(box, instance.anchor, glyphMinScale, instance.maxScale, padding);
}
}
}
-}
-
-void Placement::addFeature(TextBucket &bucket, const std::vector<Coordinate> &line,
- const StyleBucketText &info, const GlyphPositions &face,
- const Shaping &shaping) {
- const bool horizontal = info.path == TextPathType::Horizontal;
- const float fontScale = (tileExtent / util::tileSize) / (glyphSize / info.max_size);
-
- Anchors anchors;
-
- if (line.size() == 1) {
- // Point labels
- anchors = Anchors{{Anchor{
- static_cast<float>(line[0].x), static_cast<float>(line[0].y),
- 0, minScale}}};
- } else {
- // Line labels
- anchors = interpolate(line, info.min_distance, minScale);
+ // TODO avoid creating the boxes in the first place?
+ if (horizontal)
+ placement.boxes = {getMergedBoxes(placement.boxes, anchor)};
- // Sort anchors by segment so that we can start placement with
- // the anchors that can be shown at the lowest zoom levels.
- std::sort(anchors.begin(), anchors.end(), byScale);
+ const float minPlacementScale = anchor.scale;
+ placement.minScale = std::numeric_limits<float>::infinity();
+ for (const GlyphBox &box : placement.boxes) {
+ placement.minScale = util::min(placement.minScale, box.minScale);
}
+ placement.minScale = util::max(minPlacementScale, Placement::globalMinScale);
- for (Anchor anchor : anchors) {
- PlacedGlyphs glyphs;
- GlyphBoxes boxes;
-
- getGlyphs(glyphs, boxes, anchor, info.translate, shaping, face, fontScale, horizontal, line,
- info.max_angle_delta, info.rotate);
- PlacementProperty place = collision.place(boxes, anchor, anchor.scale, maxPlacementScale,
- info.padding, horizontal, info.always_visible);
- if (place) {
- bucket.addGlyphs(glyphs, place.zoom, place.rotationRange, zoom - zOffset);
- }
- }
+ return placement;
+}
}
diff --git a/src/text/rotation_range.cpp b/src/text/rotation_range.cpp
index 943253a3da..2596cf1bb6 100644
--- a/src/text/rotation_range.cpp
+++ b/src/text/rotation_range.cpp
@@ -239,14 +239,14 @@ CollisionRange rotationRange(const GlyphBox &inserting,
static_cast<float>((b.anchor.y - a.anchor.y) * scale)};
// Generate a list of collision interval
- if (a.rotate && b.rotate) {
+ if (a.hBox && b.hBox) {
collisions = rotatingRotatingCollisions(a.box, b.box, relativeAnchor);
- } else if (a.rotate) {
+ } else if (a.hBox) {
const CollisionRect box {
b.box.tl.x + relativeAnchor.x, b.box.tl.y + relativeAnchor.y,
b.box.br.x + relativeAnchor.x, b.box.br.y + relativeAnchor.y};
collisions = rotatingFixedCollisions(a.box, box);
- } else if (b.rotate) {
+ } else if (b.hBox) {
const CollisionRect box {
a.box.tl.x - relativeAnchor.x, a.box.tl.y - relativeAnchor.y,
a.box.br.x - relativeAnchor.x, a.box.br.y - relativeAnchor.y};
diff --git a/src/util/filesource.cpp b/src/util/filesource.cpp
new file mode 100644
index 0000000000..2bbf146b0c
--- /dev/null
+++ b/src/util/filesource.cpp
@@ -0,0 +1,58 @@
+#include <mbgl/util/filesource.hpp>
+#include <mbgl/platform/platform.hpp>
+
+#include <fstream>
+#include <sstream>
+
+namespace mbgl {
+
+FileSource::FileSource() {}
+
+
+void FileSource::setBase(const std::string &value) {
+ base = value;
+}
+
+const std::string &FileSource::getBase() const {
+ return base;
+}
+
+void FileSource::load(ResourceType type, const std::string &url, std::function<void(platform::Response *)> callback, const std::shared_ptr<uv::loop> loop) {
+ // convert relative URLs to absolute URLs
+
+ const std::string absoluteURL = [&]() -> std::string {
+ const size_t separator = url.find("://");
+ if (separator == std::string::npos) {
+ // Relative URL.
+ return base + url;
+ } else {
+ return url;
+ }
+ }();
+
+ const size_t separator = absoluteURL.find("://");
+ const std::string protocol = separator != std::string::npos ? absoluteURL.substr(0, separator) : "";
+
+ if (protocol == "file") {
+ // load from disk
+ const std::string path = absoluteURL.substr(separator + 3);
+ std::ifstream file(path);
+
+ platform::Response response(callback);
+ if (!file.good()) {
+ response.error_message = "file not found (" + path + ")";
+ } else {
+ std::stringstream data;
+ data << file.rdbuf();
+ response.code = 200;
+ response.body = data.str();
+ }
+
+ callback(&response);
+ } else {
+ // load from the internet
+ platform::request_http(absoluteURL, callback, loop);
+ }
+}
+
+} \ No newline at end of file
diff --git a/styles/bright/img/sprite.json b/styles/bright/img/sprite.json
new file mode 100644
index 0000000000..d8fd539f42
--- /dev/null
+++ b/styles/bright/img/sprite.json
@@ -0,0 +1,2818 @@
+{
+ "marker-24": {
+ "x": 0,
+ "y": 0,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "zoo-24": {
+ "x": 26,
+ "y": 0,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "-24": {
+ "x": 0,
+ "y": 26,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "wetland-24": {
+ "x": 26,
+ "y": 26,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "water-24": {
+ "x": 52,
+ "y": 0,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "airfield-24": {
+ "x": 52,
+ "y": 26,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "waste-basket-24": {
+ "x": 0,
+ "y": 52,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "warehouse-24": {
+ "x": 26,
+ "y": 52,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "airport-24": {
+ "x": 52,
+ "y": 52,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "village-24": {
+ "x": 78,
+ "y": 0,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "triangle-stroked-24": {
+ "x": 78,
+ "y": 26,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "alcohol-shop-24": {
+ "x": 78,
+ "y": 52,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "triangle-24": {
+ "x": 0,
+ "y": 78,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "town-hall-24": {
+ "x": 26,
+ "y": 78,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "america-football-24": {
+ "x": 52,
+ "y": 78,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "town-24": {
+ "x": 78,
+ "y": 78,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "toilets-24": {
+ "x": 104,
+ "y": 0,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "art-gallery-24": {
+ "x": 104,
+ "y": 26,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "theatre-24": {
+ "x": 104,
+ "y": 52,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "tennis-24": {
+ "x": 104,
+ "y": 78,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bakery-24": {
+ "x": 0,
+ "y": 104,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "telephone-24": {
+ "x": 26,
+ "y": 104,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "swimming-24": {
+ "x": 52,
+ "y": 104,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bank-24": {
+ "x": 78,
+ "y": 104,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "suitcase-24": {
+ "x": 104,
+ "y": 104,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "star-stroked-24": {
+ "x": 130,
+ "y": 0,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bar-24": {
+ "x": 130,
+ "y": 26,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "star-24": {
+ "x": 130,
+ "y": 52,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "square-stroked-24": {
+ "x": 130,
+ "y": 78,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "baseball-24": {
+ "x": 130,
+ "y": 104,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "square-24": {
+ "x": 0,
+ "y": 130,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "soccer-24": {
+ "x": 26,
+ "y": 130,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "basketball-24": {
+ "x": 52,
+ "y": 130,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "slaughterhouse-24": {
+ "x": 78,
+ "y": 130,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "skiing-24": {
+ "x": 104,
+ "y": 130,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "beer-24": {
+ "x": 130,
+ "y": 130,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "shop-24": {
+ "x": 156,
+ "y": 0,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "scooter-24": {
+ "x": 156,
+ "y": 26,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bicycle-24": {
+ "x": 156,
+ "y": 52,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "school-24": {
+ "x": 156,
+ "y": 78,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rocket-24": {
+ "x": 156,
+ "y": 104,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "building-24": {
+ "x": 156,
+ "y": 130,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "roadblock-24": {
+ "x": 0,
+ "y": 156,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "restaurant-24": {
+ "x": 26,
+ "y": 156,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bus-24": {
+ "x": 52,
+ "y": 156,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "religious-muslim-24": {
+ "x": 78,
+ "y": 156,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "religious-jewish-24": {
+ "x": 104,
+ "y": 156,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cafe-24": {
+ "x": 130,
+ "y": 156,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "religious-christian-24": {
+ "x": 156,
+ "y": 156,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-underground-24": {
+ "x": 182,
+ "y": 0,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "camera-24": {
+ "x": 182,
+ "y": 26,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-metro-24": {
+ "x": 182,
+ "y": 52,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-light-24": {
+ "x": 182,
+ "y": 78,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "campsite-24": {
+ "x": 182,
+ "y": 104,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-above-24": {
+ "x": 182,
+ "y": 130,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-24": {
+ "x": 182,
+ "y": 156,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "car-24": {
+ "x": 0,
+ "y": 182,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "prison-24": {
+ "x": 26,
+ "y": 182,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "post-24": {
+ "x": 52,
+ "y": 182,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cemetery-24": {
+ "x": 78,
+ "y": 182,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "polling-place-24": {
+ "x": 104,
+ "y": 182,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "police-24": {
+ "x": 130,
+ "y": 182,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "chemist-24": {
+ "x": 156,
+ "y": 182,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "playground-24": {
+ "x": 182,
+ "y": 182,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "place-of-worship-24": {
+ "x": 208,
+ "y": 0,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cinema-24": {
+ "x": 208,
+ "y": 26,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "pitch-24": {
+ "x": 208,
+ "y": 52,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "pharmacy-24": {
+ "x": 208,
+ "y": 78,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "circle-24": {
+ "x": 208,
+ "y": 104,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "parking-garage-24": {
+ "x": 208,
+ "y": 130,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "parking-24": {
+ "x": 208,
+ "y": 156,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "circle-stroked-24": {
+ "x": 208,
+ "y": 182,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "park2-24": {
+ "x": 0,
+ "y": 208,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "park-24": {
+ "x": 26,
+ "y": 208,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "city-24": {
+ "x": 52,
+ "y": 208,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "oil-well-24": {
+ "x": 78,
+ "y": 208,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "music-24": {
+ "x": 104,
+ "y": 208,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "clothing-store-24": {
+ "x": 130,
+ "y": 208,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "museum-24": {
+ "x": 156,
+ "y": 208,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "monument-24": {
+ "x": 182,
+ "y": 208,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "college-24": {
+ "x": 208,
+ "y": 208,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "mobilephone-24": {
+ "x": 234,
+ "y": 0,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "minefield-24": {
+ "x": 234,
+ "y": 26,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "commercial-24": {
+ "x": 234,
+ "y": 52,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "marker-stroked-24": {
+ "x": 234,
+ "y": 78,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "london-underground-24": {
+ "x": 234,
+ "y": 104,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cricket-24": {
+ "x": 234,
+ "y": 130,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "logging-24": {
+ "x": 234,
+ "y": 156,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "lodging-24": {
+ "x": 234,
+ "y": 182,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cross-24": {
+ "x": 234,
+ "y": 208,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "lighthouse-24": {
+ "x": 0,
+ "y": 234,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "library-24": {
+ "x": 26,
+ "y": 234,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "dam-24": {
+ "x": 52,
+ "y": 234,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "laundry-24": {
+ "x": 78,
+ "y": 234,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "land-use-24": {
+ "x": 104,
+ "y": 234,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "danger-24": {
+ "x": 130,
+ "y": 234,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "industrial-24": {
+ "x": 156,
+ "y": 234,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "hospital-24": {
+ "x": 182,
+ "y": 234,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "disability-24": {
+ "x": 208,
+ "y": 234,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "heliport-24": {
+ "x": 234,
+ "y": 234,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "heart-24": {
+ "x": 260,
+ "y": 0,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "dog-park-24": {
+ "x": 260,
+ "y": 26,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "harbor-24": {
+ "x": 260,
+ "y": 52,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "hairdresser-24": {
+ "x": 260,
+ "y": 78,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "embassy-24": {
+ "x": 260,
+ "y": 104,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "grocery-24": {
+ "x": 260,
+ "y": 130,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "golf-24": {
+ "x": 260,
+ "y": 156,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "emergency-telephone-24": {
+ "x": 260,
+ "y": 182,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "garden-24": {
+ "x": 260,
+ "y": 208,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "fuel-24": {
+ "x": 260,
+ "y": 234,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "entrance-24": {
+ "x": 0,
+ "y": 260,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "fire-station-24": {
+ "x": 26,
+ "y": 260,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "ferry-24": {
+ "x": 52,
+ "y": 260,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "farm-24": {
+ "x": 78,
+ "y": 260,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "fast-food-24": {
+ "x": 104,
+ "y": 260,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "police-18": {
+ "x": 130,
+ "y": 260,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "fast-food-18": {
+ "x": 150,
+ "y": 260,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "farm-18": {
+ "x": 170,
+ "y": 260,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "fire-station-18": {
+ "x": 190,
+ "y": 260,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "fuel-18": {
+ "x": 210,
+ "y": 260,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "entrance-18": {
+ "x": 230,
+ "y": 260,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "garden-18": {
+ "x": 250,
+ "y": 260,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "golf-18": {
+ "x": 286,
+ "y": 0,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "emergency-telephone-18": {
+ "x": 286,
+ "y": 20,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "grocery-18": {
+ "x": 286,
+ "y": 40,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "hairdresser-18": {
+ "x": 286,
+ "y": 60,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "embassy-18": {
+ "x": 286,
+ "y": 80,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "harbor-18": {
+ "x": 286,
+ "y": 100,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "heart-18": {
+ "x": 286,
+ "y": 120,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "dog-park-18": {
+ "x": 286,
+ "y": 140,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "heliport-18": {
+ "x": 286,
+ "y": 160,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "hospital-18": {
+ "x": 286,
+ "y": 180,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "disability-18": {
+ "x": 286,
+ "y": 200,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "industrial-18": {
+ "x": 286,
+ "y": 220,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "land-use-18": {
+ "x": 286,
+ "y": 240,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "danger-18": {
+ "x": 286,
+ "y": 260,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "laundry-18": {
+ "x": 0,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "library-18": {
+ "x": 20,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "dam-18": {
+ "x": 40,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "lighthouse-18": {
+ "x": 60,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "lodging-18": {
+ "x": 80,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cross-18": {
+ "x": 100,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "logging-18": {
+ "x": 120,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "london-underground-18": {
+ "x": 140,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cricket-18": {
+ "x": 160,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "marker-18": {
+ "x": 180,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "-18": {
+ "x": 200,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "marker-stroked-18": {
+ "x": 220,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "minefield-18": {
+ "x": 240,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "commercial-18": {
+ "x": 260,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "mobilephone-18": {
+ "x": 280,
+ "y": 286,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "monument-18": {
+ "x": 306,
+ "y": 0,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "college-18": {
+ "x": 306,
+ "y": 20,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "motorway_1": {
+ "x": 0,
+ "y": 306,
+ "width": 19,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "motorway_2": {
+ "x": 21,
+ "y": 306,
+ "width": 24,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "motorway_3": {
+ "x": 47,
+ "y": 306,
+ "width": 29,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "motorway_4": {
+ "x": 78,
+ "y": 306,
+ "width": 34,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "motorway_5": {
+ "x": 114,
+ "y": 306,
+ "width": 39,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "motorway_6": {
+ "x": 155,
+ "y": 306,
+ "width": 44,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "museum-18": {
+ "x": 306,
+ "y": 40,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "music-18": {
+ "x": 306,
+ "y": 60,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "clothing-store-18": {
+ "x": 306,
+ "y": 80,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "oil-well-18": {
+ "x": 306,
+ "y": 100,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "park-18": {
+ "x": 306,
+ "y": 120,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "city-18": {
+ "x": 306,
+ "y": 140,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "park2-18": {
+ "x": 306,
+ "y": 160,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "parking-18": {
+ "x": 306,
+ "y": 180,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "circle-stroked-18": {
+ "x": 306,
+ "y": 200,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "parking-garage-18": {
+ "x": 306,
+ "y": 220,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "pharmacy-18": {
+ "x": 306,
+ "y": 240,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "circle-18": {
+ "x": 306,
+ "y": 260,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "pitch-18": {
+ "x": 306,
+ "y": 280,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "place-of-worship-18": {
+ "x": 201,
+ "y": 306,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cinema-18": {
+ "x": 221,
+ "y": 306,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "playground-18": {
+ "x": 241,
+ "y": 306,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "ferry-18": {
+ "x": 261,
+ "y": 306,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "chemist-18": {
+ "x": 281,
+ "y": 306,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "polling-place-18": {
+ "x": 301,
+ "y": 306,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "post-18": {
+ "x": 326,
+ "y": 0,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cemetery-18": {
+ "x": 326,
+ "y": 20,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "prison-18": {
+ "x": 326,
+ "y": 40,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-18": {
+ "x": 326,
+ "y": 60,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "car-18": {
+ "x": 326,
+ "y": 80,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-above-18": {
+ "x": 326,
+ "y": 100,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-light-18": {
+ "x": 326,
+ "y": 120,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "campsite-18": {
+ "x": 326,
+ "y": 140,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-metro-18": {
+ "x": 326,
+ "y": 160,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-underground-18": {
+ "x": 326,
+ "y": 180,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "camera-18": {
+ "x": 326,
+ "y": 200,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "religious-christian-18": {
+ "x": 326,
+ "y": 220,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "religious-jewish-18": {
+ "x": 326,
+ "y": 240,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cafe-18": {
+ "x": 326,
+ "y": 260,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "religious-muslim-18": {
+ "x": 326,
+ "y": 280,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "restaurant-18": {
+ "x": 326,
+ "y": 300,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bus-18": {
+ "x": 0,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "roadblock-18": {
+ "x": 20,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rocket-18": {
+ "x": 40,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "building-18": {
+ "x": 60,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "school-18": {
+ "x": 80,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "scooter-18": {
+ "x": 100,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bicycle-18": {
+ "x": 120,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "shop-18": {
+ "x": 140,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "skiing-18": {
+ "x": 160,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "beer-18": {
+ "x": 180,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "slaughterhouse-18": {
+ "x": 200,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "soccer-18": {
+ "x": 220,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "basketball-18": {
+ "x": 240,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "square-18": {
+ "x": 260,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "square-stroked-18": {
+ "x": 280,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "baseball-18": {
+ "x": 300,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "star-18": {
+ "x": 320,
+ "y": 326,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "star-stroked-18": {
+ "x": 346,
+ "y": 0,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bar-18": {
+ "x": 346,
+ "y": 20,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "suitcase-18": {
+ "x": 346,
+ "y": 40,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "swimming-18": {
+ "x": 346,
+ "y": 60,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bank-18": {
+ "x": 346,
+ "y": 80,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "telephone-18": {
+ "x": 346,
+ "y": 100,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "tennis-18": {
+ "x": 346,
+ "y": 120,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bakery-18": {
+ "x": 346,
+ "y": 140,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "theatre-18": {
+ "x": 346,
+ "y": 160,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "toilets-18": {
+ "x": 346,
+ "y": 180,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "art-gallery-18": {
+ "x": 346,
+ "y": 200,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "town-18": {
+ "x": 346,
+ "y": 220,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "town-hall-18": {
+ "x": 346,
+ "y": 240,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "america-football-18": {
+ "x": 346,
+ "y": 260,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "triangle-18": {
+ "x": 346,
+ "y": 280,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "triangle-stroked-18": {
+ "x": 346,
+ "y": 300,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "alcohol-shop-18": {
+ "x": 346,
+ "y": 320,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "village-18": {
+ "x": 0,
+ "y": 346,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "warehouse-18": {
+ "x": 20,
+ "y": 346,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "airport-18": {
+ "x": 40,
+ "y": 346,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "waste-basket-18": {
+ "x": 60,
+ "y": 346,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "water-18": {
+ "x": 80,
+ "y": 346,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "airfield-18": {
+ "x": 100,
+ "y": 346,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "zoo-18": {
+ "x": 120,
+ "y": 346,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "wetland-18": {
+ "x": 140,
+ "y": 346,
+ "width": 18,
+ "height": 18,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cricket-12": {
+ "x": 270,
+ "y": 260,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "prison-12": {
+ "x": 160,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "minefield-12": {
+ "x": 174,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cemetery-12": {
+ "x": 188,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-12": {
+ "x": 202,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "fuel-12": {
+ "x": 216,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "grocery-12": {
+ "x": 230,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-above-12": {
+ "x": 244,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "mobilephone-12": {
+ "x": 258,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "car-12": {
+ "x": 272,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-light-12": {
+ "x": 286,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "industrial-12": {
+ "x": 300,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "commercial-12": {
+ "x": 314,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-metro-12": {
+ "x": 328,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "monument-12": {
+ "x": 342,
+ "y": 346,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "campsite-12": {
+ "x": 366,
+ "y": 0,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rail-underground-12": {
+ "x": 366,
+ "y": 14,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "ferry-12": {
+ "x": 366,
+ "y": 28,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "disability-12": {
+ "x": 366,
+ "y": 42,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "religious-christian-12": {
+ "x": 366,
+ "y": 56,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "land-use-12": {
+ "x": 366,
+ "y": 70,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "camera-12": {
+ "x": 366,
+ "y": 84,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "religious-jewish-12": {
+ "x": 366,
+ "y": 98,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "emergency-telephone-12": {
+ "x": 366,
+ "y": 112,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "hairdresser-12": {
+ "x": 366,
+ "y": 126,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "religious-muslim-12": {
+ "x": 366,
+ "y": 140,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "laundry-12": {
+ "x": 366,
+ "y": 154,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cafe-12": {
+ "x": 366,
+ "y": 168,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "restaurant-12": {
+ "x": 366,
+ "y": 182,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "fire-station-12": {
+ "x": 366,
+ "y": 196,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "danger-12": {
+ "x": 366,
+ "y": 210,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "roadblock-12": {
+ "x": 366,
+ "y": 224,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "museum-12": {
+ "x": 366,
+ "y": 238,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bus-12": {
+ "x": 366,
+ "y": 252,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "rocket-12": {
+ "x": 366,
+ "y": 266,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "library-12": {
+ "x": 366,
+ "y": 280,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "college-12": {
+ "x": 366,
+ "y": 294,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "school-12": {
+ "x": 366,
+ "y": 308,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "music-12": {
+ "x": 366,
+ "y": 322,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "building-12": {
+ "x": 366,
+ "y": 336,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "scooter-12": {
+ "x": 366,
+ "y": 350,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "garden-12": {
+ "x": 0,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "harbor-12": {
+ "x": 14,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "shop-12": {
+ "x": 28,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "oil-well-12": {
+ "x": 42,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bicycle-12": {
+ "x": 56,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "skiing-12": {
+ "x": 70,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "lighthouse-12": {
+ "x": 84,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "clothing-store-12": {
+ "x": 98,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "slaughterhouse-12": {
+ "x": 112,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "park-12": {
+ "x": 126,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "beer-12": {
+ "x": 140,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "soccer-12": {
+ "x": 154,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "-12": {
+ "x": 168,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "dam-12": {
+ "x": 182,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "square-12": {
+ "x": 196,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "park2-12": {
+ "x": 210,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "basketball-12": {
+ "x": 224,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "square-stroked-12": {
+ "x": 238,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "lodging-12": {
+ "x": 252,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "city-12": {
+ "x": 266,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "star-12": {
+ "x": 280,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "parking-12": {
+ "x": 294,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "baseball-12": {
+ "x": 308,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "star-stroked-12": {
+ "x": 322,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "embassy-12": {
+ "x": 336,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "heart-12": {
+ "x": 350,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "suitcase-12": {
+ "x": 364,
+ "y": 366,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "parking-garage-12": {
+ "x": 380,
+ "y": 0,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bar-12": {
+ "x": 380,
+ "y": 14,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "swimming-12": {
+ "x": 380,
+ "y": 28,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "logging-12": {
+ "x": 380,
+ "y": 42,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "circle-stroked-12": {
+ "x": 380,
+ "y": 56,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "telephone-12": {
+ "x": 380,
+ "y": 70,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "pharmacy-12": {
+ "x": 380,
+ "y": 84,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bank-12": {
+ "x": 380,
+ "y": 98,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "tennis-12": {
+ "x": 380,
+ "y": 112,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "entrance-12": {
+ "x": 380,
+ "y": 126,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cross-12": {
+ "x": 380,
+ "y": 140,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "theatre-12": {
+ "x": 380,
+ "y": 154,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "pitch-12": {
+ "x": 380,
+ "y": 168,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "bakery-12": {
+ "x": 380,
+ "y": 182,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "toilets-12": {
+ "x": 380,
+ "y": 196,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "london-underground-12": {
+ "x": 380,
+ "y": 210,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "circle-12": {
+ "x": 380,
+ "y": 224,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "town-12": {
+ "x": 380,
+ "y": 238,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "place-of-worship-12": {
+ "x": 380,
+ "y": 252,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "art-gallery-12": {
+ "x": 380,
+ "y": 266,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "town-hall-12": {
+ "x": 380,
+ "y": 280,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "golf-12": {
+ "x": 380,
+ "y": 294,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "heliport-12": {
+ "x": 380,
+ "y": 308,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "triangle-12": {
+ "x": 380,
+ "y": 322,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "playground-12": {
+ "x": 380,
+ "y": 336,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "america-football-12": {
+ "x": 380,
+ "y": 350,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "triangle-stroked-12": {
+ "x": 380,
+ "y": 364,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "marker-12": {
+ "x": 0,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "cinema-12": {
+ "x": 14,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "village-12": {
+ "x": 28,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "police-12": {
+ "x": 42,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "alcohol-shop-12": {
+ "x": 56,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "warehouse-12": {
+ "x": 70,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "farm-12": {
+ "x": 84,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "dog-park-12": {
+ "x": 98,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "waste-basket-12": {
+ "x": 112,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "polling-place-12": {
+ "x": 126,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "airport-12": {
+ "x": 140,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "water-12": {
+ "x": 154,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "marker-stroked-12": {
+ "x": 168,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "fast-food-12": {
+ "x": 182,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "post-12": {
+ "x": 196,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "wetland-12": {
+ "x": 210,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "hospital-12": {
+ "x": 224,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "airfield-12": {
+ "x": 238,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "zoo-12": {
+ "x": 252,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "chemist-12": {
+ "x": 266,
+ "y": 380,
+ "width": 12,
+ "height": 12,
+ "pixelRatio": 1,
+ "sdf": false
+ },
+ "wave": {
+ "x": 280,
+ "y": 380,
+ "width": 16,
+ "height": 8,
+ "pixelRatio": 1,
+ "sdf": false
+ }
+} \ No newline at end of file
diff --git a/styles/bright/img/sprite.png b/styles/bright/img/sprite.png
new file mode 100644
index 0000000000..34ef6124b8
--- /dev/null
+++ b/styles/bright/img/sprite.png
Binary files differ
diff --git a/styles/bright/img/sprite@2x.json b/styles/bright/img/sprite@2x.json
new file mode 100644
index 0000000000..b15134a6a8
--- /dev/null
+++ b/styles/bright/img/sprite@2x.json
@@ -0,0 +1,2818 @@
+{
+ "marker-24": {
+ "x": 0,
+ "y": 0,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "zoo-24": {
+ "x": 50,
+ "y": 0,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "-24": {
+ "x": 0,
+ "y": 50,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "wetland-24": {
+ "x": 50,
+ "y": 50,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "water-24": {
+ "x": 100,
+ "y": 0,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "airfield-24": {
+ "x": 100,
+ "y": 50,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "waste-basket-24": {
+ "x": 0,
+ "y": 100,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "warehouse-24": {
+ "x": 50,
+ "y": 100,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "airport-24": {
+ "x": 100,
+ "y": 100,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "village-24": {
+ "x": 150,
+ "y": 0,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "triangle-stroked-24": {
+ "x": 150,
+ "y": 50,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "alcohol-shop-24": {
+ "x": 150,
+ "y": 100,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "triangle-24": {
+ "x": 0,
+ "y": 150,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "town-hall-24": {
+ "x": 50,
+ "y": 150,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "america-football-24": {
+ "x": 100,
+ "y": 150,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "town-24": {
+ "x": 150,
+ "y": 150,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "toilets-24": {
+ "x": 200,
+ "y": 0,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "art-gallery-24": {
+ "x": 200,
+ "y": 50,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "theatre-24": {
+ "x": 200,
+ "y": 100,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "tennis-24": {
+ "x": 200,
+ "y": 150,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bakery-24": {
+ "x": 0,
+ "y": 200,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "telephone-24": {
+ "x": 50,
+ "y": 200,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "swimming-24": {
+ "x": 100,
+ "y": 200,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bank-24": {
+ "x": 150,
+ "y": 200,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "suitcase-24": {
+ "x": 200,
+ "y": 200,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "star-stroked-24": {
+ "x": 250,
+ "y": 0,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bar-24": {
+ "x": 250,
+ "y": 50,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "star-24": {
+ "x": 250,
+ "y": 100,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "square-stroked-24": {
+ "x": 250,
+ "y": 150,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "baseball-24": {
+ "x": 250,
+ "y": 200,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "square-24": {
+ "x": 0,
+ "y": 250,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "soccer-24": {
+ "x": 50,
+ "y": 250,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "basketball-24": {
+ "x": 100,
+ "y": 250,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "slaughterhouse-24": {
+ "x": 150,
+ "y": 250,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "skiing-24": {
+ "x": 200,
+ "y": 250,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "beer-24": {
+ "x": 250,
+ "y": 250,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "shop-24": {
+ "x": 300,
+ "y": 0,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "scooter-24": {
+ "x": 300,
+ "y": 50,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bicycle-24": {
+ "x": 300,
+ "y": 100,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "school-24": {
+ "x": 300,
+ "y": 150,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rocket-24": {
+ "x": 300,
+ "y": 200,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "building-24": {
+ "x": 300,
+ "y": 250,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "roadblock-24": {
+ "x": 0,
+ "y": 300,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "restaurant-24": {
+ "x": 50,
+ "y": 300,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bus-24": {
+ "x": 100,
+ "y": 300,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "religious-muslim-24": {
+ "x": 150,
+ "y": 300,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "religious-jewish-24": {
+ "x": 200,
+ "y": 300,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cafe-24": {
+ "x": 250,
+ "y": 300,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "religious-christian-24": {
+ "x": 300,
+ "y": 300,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-underground-24": {
+ "x": 350,
+ "y": 0,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "camera-24": {
+ "x": 350,
+ "y": 50,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-metro-24": {
+ "x": 350,
+ "y": 100,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-light-24": {
+ "x": 350,
+ "y": 150,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "campsite-24": {
+ "x": 350,
+ "y": 200,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-above-24": {
+ "x": 350,
+ "y": 250,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-24": {
+ "x": 350,
+ "y": 300,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "car-24": {
+ "x": 0,
+ "y": 350,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "prison-24": {
+ "x": 50,
+ "y": 350,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "post-24": {
+ "x": 100,
+ "y": 350,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cemetery-24": {
+ "x": 150,
+ "y": 350,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "polling-place-24": {
+ "x": 200,
+ "y": 350,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "police-24": {
+ "x": 250,
+ "y": 350,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "chemist-24": {
+ "x": 300,
+ "y": 350,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "playground-24": {
+ "x": 350,
+ "y": 350,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "place-of-worship-24": {
+ "x": 400,
+ "y": 0,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cinema-24": {
+ "x": 400,
+ "y": 50,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "pitch-24": {
+ "x": 400,
+ "y": 100,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "pharmacy-24": {
+ "x": 400,
+ "y": 150,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "circle-24": {
+ "x": 400,
+ "y": 200,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "parking-garage-24": {
+ "x": 400,
+ "y": 250,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "parking-24": {
+ "x": 400,
+ "y": 300,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "circle-stroked-24": {
+ "x": 400,
+ "y": 350,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "park2-24": {
+ "x": 0,
+ "y": 400,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "park-24": {
+ "x": 50,
+ "y": 400,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "city-24": {
+ "x": 100,
+ "y": 400,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "oil-well-24": {
+ "x": 150,
+ "y": 400,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "music-24": {
+ "x": 200,
+ "y": 400,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "clothing-store-24": {
+ "x": 250,
+ "y": 400,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "museum-24": {
+ "x": 300,
+ "y": 400,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "monument-24": {
+ "x": 350,
+ "y": 400,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "college-24": {
+ "x": 400,
+ "y": 400,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "mobilephone-24": {
+ "x": 450,
+ "y": 0,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "minefield-24": {
+ "x": 450,
+ "y": 50,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "commercial-24": {
+ "x": 450,
+ "y": 100,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "marker-stroked-24": {
+ "x": 450,
+ "y": 150,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "london-underground-24": {
+ "x": 450,
+ "y": 200,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cricket-24": {
+ "x": 450,
+ "y": 250,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "logging-24": {
+ "x": 450,
+ "y": 300,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "lodging-24": {
+ "x": 450,
+ "y": 350,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cross-24": {
+ "x": 450,
+ "y": 400,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "lighthouse-24": {
+ "x": 0,
+ "y": 450,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "library-24": {
+ "x": 50,
+ "y": 450,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "dam-24": {
+ "x": 100,
+ "y": 450,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "laundry-24": {
+ "x": 150,
+ "y": 450,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "land-use-24": {
+ "x": 200,
+ "y": 450,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "danger-24": {
+ "x": 250,
+ "y": 450,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "industrial-24": {
+ "x": 300,
+ "y": 450,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "hospital-24": {
+ "x": 350,
+ "y": 450,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "disability-24": {
+ "x": 400,
+ "y": 450,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "heliport-24": {
+ "x": 450,
+ "y": 450,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "heart-24": {
+ "x": 500,
+ "y": 0,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "dog-park-24": {
+ "x": 500,
+ "y": 50,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "harbor-24": {
+ "x": 500,
+ "y": 100,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "hairdresser-24": {
+ "x": 500,
+ "y": 150,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "embassy-24": {
+ "x": 500,
+ "y": 200,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "grocery-24": {
+ "x": 500,
+ "y": 250,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "golf-24": {
+ "x": 500,
+ "y": 300,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "emergency-telephone-24": {
+ "x": 500,
+ "y": 350,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "garden-24": {
+ "x": 500,
+ "y": 400,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "fuel-24": {
+ "x": 500,
+ "y": 450,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "entrance-24": {
+ "x": 0,
+ "y": 500,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "fire-station-24": {
+ "x": 50,
+ "y": 500,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "ferry-24": {
+ "x": 100,
+ "y": 500,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "farm-24": {
+ "x": 150,
+ "y": 500,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "fast-food-24": {
+ "x": 200,
+ "y": 500,
+ "width": 48,
+ "height": 48,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "police-18": {
+ "x": 250,
+ "y": 500,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "fast-food-18": {
+ "x": 288,
+ "y": 500,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "farm-18": {
+ "x": 326,
+ "y": 500,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "fire-station-18": {
+ "x": 364,
+ "y": 500,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "fuel-18": {
+ "x": 402,
+ "y": 500,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "entrance-18": {
+ "x": 440,
+ "y": 500,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "garden-18": {
+ "x": 478,
+ "y": 500,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "golf-18": {
+ "x": 550,
+ "y": 0,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "emergency-telephone-18": {
+ "x": 550,
+ "y": 38,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "grocery-18": {
+ "x": 550,
+ "y": 76,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "hairdresser-18": {
+ "x": 550,
+ "y": 114,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "embassy-18": {
+ "x": 550,
+ "y": 152,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "harbor-18": {
+ "x": 550,
+ "y": 190,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "heart-18": {
+ "x": 550,
+ "y": 228,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "dog-park-18": {
+ "x": 550,
+ "y": 266,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "heliport-18": {
+ "x": 550,
+ "y": 304,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "hospital-18": {
+ "x": 550,
+ "y": 342,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "disability-18": {
+ "x": 550,
+ "y": 380,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "industrial-18": {
+ "x": 550,
+ "y": 418,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "land-use-18": {
+ "x": 550,
+ "y": 456,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "danger-18": {
+ "x": 550,
+ "y": 494,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "laundry-18": {
+ "x": 0,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "library-18": {
+ "x": 38,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "dam-18": {
+ "x": 76,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "lighthouse-18": {
+ "x": 114,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "lodging-18": {
+ "x": 152,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cross-18": {
+ "x": 190,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "logging-18": {
+ "x": 228,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "london-underground-18": {
+ "x": 266,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cricket-18": {
+ "x": 304,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "marker-18": {
+ "x": 342,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "-18": {
+ "x": 380,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "marker-stroked-18": {
+ "x": 418,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "minefield-18": {
+ "x": 456,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "commercial-18": {
+ "x": 494,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "mobilephone-18": {
+ "x": 532,
+ "y": 550,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "monument-18": {
+ "x": 588,
+ "y": 0,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "college-18": {
+ "x": 588,
+ "y": 38,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "motorway_1": {
+ "x": 0,
+ "y": 588,
+ "width": 38,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "motorway_2": {
+ "x": 40,
+ "y": 588,
+ "width": 48,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "motorway_3": {
+ "x": 90,
+ "y": 588,
+ "width": 58,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "motorway_4": {
+ "x": 150,
+ "y": 588,
+ "width": 68,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "motorway_5": {
+ "x": 220,
+ "y": 588,
+ "width": 78,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "motorway_6": {
+ "x": 300,
+ "y": 588,
+ "width": 88,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "museum-18": {
+ "x": 588,
+ "y": 76,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "music-18": {
+ "x": 588,
+ "y": 114,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "clothing-store-18": {
+ "x": 588,
+ "y": 152,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "oil-well-18": {
+ "x": 588,
+ "y": 190,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "park-18": {
+ "x": 588,
+ "y": 228,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "city-18": {
+ "x": 588,
+ "y": 266,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "park2-18": {
+ "x": 588,
+ "y": 304,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "parking-18": {
+ "x": 588,
+ "y": 342,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "circle-stroked-18": {
+ "x": 588,
+ "y": 380,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "parking-garage-18": {
+ "x": 588,
+ "y": 418,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "pharmacy-18": {
+ "x": 588,
+ "y": 456,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "circle-18": {
+ "x": 588,
+ "y": 494,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "pitch-18": {
+ "x": 588,
+ "y": 532,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "place-of-worship-18": {
+ "x": 390,
+ "y": 588,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cinema-18": {
+ "x": 428,
+ "y": 588,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "playground-18": {
+ "x": 466,
+ "y": 588,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "ferry-18": {
+ "x": 504,
+ "y": 588,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "chemist-18": {
+ "x": 542,
+ "y": 588,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "polling-place-18": {
+ "x": 580,
+ "y": 588,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "post-18": {
+ "x": 626,
+ "y": 0,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cemetery-18": {
+ "x": 626,
+ "y": 38,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "prison-18": {
+ "x": 626,
+ "y": 76,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-18": {
+ "x": 626,
+ "y": 114,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "car-18": {
+ "x": 626,
+ "y": 152,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-above-18": {
+ "x": 626,
+ "y": 190,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-light-18": {
+ "x": 626,
+ "y": 228,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "campsite-18": {
+ "x": 626,
+ "y": 266,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-metro-18": {
+ "x": 626,
+ "y": 304,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-underground-18": {
+ "x": 626,
+ "y": 342,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "camera-18": {
+ "x": 626,
+ "y": 380,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "religious-christian-18": {
+ "x": 626,
+ "y": 418,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "religious-jewish-18": {
+ "x": 626,
+ "y": 456,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cafe-18": {
+ "x": 626,
+ "y": 494,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "religious-muslim-18": {
+ "x": 626,
+ "y": 532,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "restaurant-18": {
+ "x": 626,
+ "y": 570,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bus-18": {
+ "x": 0,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "roadblock-18": {
+ "x": 38,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rocket-18": {
+ "x": 76,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "building-18": {
+ "x": 114,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "school-18": {
+ "x": 152,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "scooter-18": {
+ "x": 190,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bicycle-18": {
+ "x": 228,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "shop-18": {
+ "x": 266,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "skiing-18": {
+ "x": 304,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "beer-18": {
+ "x": 342,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "slaughterhouse-18": {
+ "x": 380,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "soccer-18": {
+ "x": 418,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "basketball-18": {
+ "x": 456,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "square-18": {
+ "x": 494,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "square-stroked-18": {
+ "x": 532,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "baseball-18": {
+ "x": 570,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "star-18": {
+ "x": 608,
+ "y": 626,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "star-stroked-18": {
+ "x": 664,
+ "y": 0,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bar-18": {
+ "x": 664,
+ "y": 38,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "suitcase-18": {
+ "x": 664,
+ "y": 76,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "swimming-18": {
+ "x": 664,
+ "y": 114,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bank-18": {
+ "x": 664,
+ "y": 152,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "telephone-18": {
+ "x": 664,
+ "y": 190,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "tennis-18": {
+ "x": 664,
+ "y": 228,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bakery-18": {
+ "x": 664,
+ "y": 266,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "theatre-18": {
+ "x": 664,
+ "y": 304,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "toilets-18": {
+ "x": 664,
+ "y": 342,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "art-gallery-18": {
+ "x": 664,
+ "y": 380,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "town-18": {
+ "x": 664,
+ "y": 418,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "town-hall-18": {
+ "x": 664,
+ "y": 456,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "america-football-18": {
+ "x": 664,
+ "y": 494,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "triangle-18": {
+ "x": 664,
+ "y": 532,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "triangle-stroked-18": {
+ "x": 664,
+ "y": 570,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "alcohol-shop-18": {
+ "x": 664,
+ "y": 608,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "village-18": {
+ "x": 0,
+ "y": 664,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "warehouse-18": {
+ "x": 38,
+ "y": 664,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "airport-18": {
+ "x": 76,
+ "y": 664,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "waste-basket-18": {
+ "x": 114,
+ "y": 664,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "water-18": {
+ "x": 152,
+ "y": 664,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "airfield-18": {
+ "x": 190,
+ "y": 664,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "zoo-18": {
+ "x": 228,
+ "y": 664,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "wetland-18": {
+ "x": 266,
+ "y": 664,
+ "width": 36,
+ "height": 36,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cricket-12": {
+ "x": 516,
+ "y": 500,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "prison-12": {
+ "x": 304,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "minefield-12": {
+ "x": 330,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cemetery-12": {
+ "x": 356,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-12": {
+ "x": 382,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "fuel-12": {
+ "x": 408,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "grocery-12": {
+ "x": 434,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-above-12": {
+ "x": 460,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "mobilephone-12": {
+ "x": 486,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "car-12": {
+ "x": 512,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-light-12": {
+ "x": 538,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "industrial-12": {
+ "x": 564,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "commercial-12": {
+ "x": 590,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-metro-12": {
+ "x": 616,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "monument-12": {
+ "x": 642,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "campsite-12": {
+ "x": 668,
+ "y": 664,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rail-underground-12": {
+ "x": 702,
+ "y": 0,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "ferry-12": {
+ "x": 702,
+ "y": 26,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "disability-12": {
+ "x": 702,
+ "y": 52,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "religious-christian-12": {
+ "x": 702,
+ "y": 78,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "land-use-12": {
+ "x": 702,
+ "y": 104,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "camera-12": {
+ "x": 702,
+ "y": 130,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "religious-jewish-12": {
+ "x": 702,
+ "y": 156,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "emergency-telephone-12": {
+ "x": 702,
+ "y": 182,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "hairdresser-12": {
+ "x": 702,
+ "y": 208,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "religious-muslim-12": {
+ "x": 702,
+ "y": 234,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "laundry-12": {
+ "x": 702,
+ "y": 260,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cafe-12": {
+ "x": 702,
+ "y": 286,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "restaurant-12": {
+ "x": 702,
+ "y": 312,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "fire-station-12": {
+ "x": 702,
+ "y": 338,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "danger-12": {
+ "x": 702,
+ "y": 364,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "roadblock-12": {
+ "x": 702,
+ "y": 390,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "museum-12": {
+ "x": 702,
+ "y": 416,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bus-12": {
+ "x": 702,
+ "y": 442,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "rocket-12": {
+ "x": 702,
+ "y": 468,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "library-12": {
+ "x": 702,
+ "y": 494,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "college-12": {
+ "x": 702,
+ "y": 520,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "school-12": {
+ "x": 702,
+ "y": 546,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "music-12": {
+ "x": 702,
+ "y": 572,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "building-12": {
+ "x": 702,
+ "y": 598,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "scooter-12": {
+ "x": 702,
+ "y": 624,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "garden-12": {
+ "x": 702,
+ "y": 650,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "harbor-12": {
+ "x": 702,
+ "y": 676,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "shop-12": {
+ "x": 0,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "oil-well-12": {
+ "x": 26,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bicycle-12": {
+ "x": 52,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "skiing-12": {
+ "x": 78,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "lighthouse-12": {
+ "x": 104,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "clothing-store-12": {
+ "x": 130,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "slaughterhouse-12": {
+ "x": 156,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "park-12": {
+ "x": 182,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "beer-12": {
+ "x": 208,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "soccer-12": {
+ "x": 234,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "-12": {
+ "x": 260,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "dam-12": {
+ "x": 286,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "square-12": {
+ "x": 312,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "park2-12": {
+ "x": 338,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "basketball-12": {
+ "x": 364,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "square-stroked-12": {
+ "x": 390,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "lodging-12": {
+ "x": 416,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "city-12": {
+ "x": 442,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "star-12": {
+ "x": 468,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "parking-12": {
+ "x": 494,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "baseball-12": {
+ "x": 520,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "star-stroked-12": {
+ "x": 546,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "embassy-12": {
+ "x": 572,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "heart-12": {
+ "x": 598,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "suitcase-12": {
+ "x": 624,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "parking-garage-12": {
+ "x": 650,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bar-12": {
+ "x": 676,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "swimming-12": {
+ "x": 702,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "logging-12": {
+ "x": 728,
+ "y": 0,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "circle-stroked-12": {
+ "x": 728,
+ "y": 26,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "telephone-12": {
+ "x": 728,
+ "y": 52,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "pharmacy-12": {
+ "x": 728,
+ "y": 78,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bank-12": {
+ "x": 728,
+ "y": 104,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "tennis-12": {
+ "x": 728,
+ "y": 130,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "entrance-12": {
+ "x": 728,
+ "y": 156,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cross-12": {
+ "x": 728,
+ "y": 182,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "theatre-12": {
+ "x": 728,
+ "y": 208,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "pitch-12": {
+ "x": 728,
+ "y": 234,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "bakery-12": {
+ "x": 728,
+ "y": 260,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "toilets-12": {
+ "x": 728,
+ "y": 286,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "london-underground-12": {
+ "x": 728,
+ "y": 312,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "circle-12": {
+ "x": 728,
+ "y": 338,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "town-12": {
+ "x": 728,
+ "y": 364,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "place-of-worship-12": {
+ "x": 728,
+ "y": 390,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "art-gallery-12": {
+ "x": 728,
+ "y": 416,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "town-hall-12": {
+ "x": 728,
+ "y": 442,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "golf-12": {
+ "x": 728,
+ "y": 468,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "heliport-12": {
+ "x": 728,
+ "y": 494,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "triangle-12": {
+ "x": 728,
+ "y": 520,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "playground-12": {
+ "x": 728,
+ "y": 546,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "america-football-12": {
+ "x": 728,
+ "y": 572,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "triangle-stroked-12": {
+ "x": 728,
+ "y": 598,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "marker-12": {
+ "x": 728,
+ "y": 624,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "cinema-12": {
+ "x": 728,
+ "y": 650,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "village-12": {
+ "x": 728,
+ "y": 676,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "police-12": {
+ "x": 728,
+ "y": 702,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "alcohol-shop-12": {
+ "x": 0,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "warehouse-12": {
+ "x": 26,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "farm-12": {
+ "x": 52,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "dog-park-12": {
+ "x": 78,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "waste-basket-12": {
+ "x": 104,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "polling-place-12": {
+ "x": 130,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "airport-12": {
+ "x": 156,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "water-12": {
+ "x": 182,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "marker-stroked-12": {
+ "x": 208,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "fast-food-12": {
+ "x": 234,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "post-12": {
+ "x": 260,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "wetland-12": {
+ "x": 286,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "hospital-12": {
+ "x": 312,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "airfield-12": {
+ "x": 338,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "zoo-12": {
+ "x": 364,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "chemist-12": {
+ "x": 390,
+ "y": 728,
+ "width": 24,
+ "height": 24,
+ "pixelRatio": 2,
+ "sdf": false
+ },
+ "wave": {
+ "x": 664,
+ "y": 646,
+ "width": 32,
+ "height": 16,
+ "pixelRatio": 2,
+ "sdf": false
+ }
+} \ No newline at end of file
diff --git a/styles/bright/img/sprite@2x.png b/styles/bright/img/sprite@2x.png
new file mode 100644
index 0000000000..ef7c1f45d1
--- /dev/null
+++ b/styles/bright/img/sprite@2x.png
Binary files differ
diff --git a/styles/bright/style.json b/styles/bright/style.json
new file mode 100644
index 0000000000..1ee81a499b
--- /dev/null
+++ b/styles/bright/style.json
@@ -0,0 +1,1336 @@
+{
+ "version": 4,
+ "sprite": "img/sprite",
+ "glyphs": "https://mapbox.s3.amazonaws.com/gl-glyphs-256/{fontstack}/{range}.pbf",
+ "constants": {
+ "@name": "{name_en}",
+ "@sans": "Open Sans Regular, Arial Unicode MS Regular",
+ "@sans_it": "Open Sans Italic, Arial Unicode MS Regular",
+ "@sans_md": "Open Sans Semibold, Arial Unicode MS Bold",
+ "@sans_bd": "Open Sans Bold, Arial Unicode MS Bold",
+ "@land": "#f8f4f0",
+ "@water": "#a0c8f0",
+ "@admin": "#446",
+ "@park": "#d8e8c8",
+ "@cemetary": "#e0e4dd",
+ "@hospital": "#fde",
+ "@school": "#f0e8f8",
+ "@wood": "#6a4",
+ "@building": "#f2eae2",
+ "@building_shadow": "#dfdbd7",
+ "@building_color_transition": {
+ "base": 1,
+ "stops": [[15.5, "#f2eae2"], [16, "#dfdbd7"]]
+ },
+ "@building_opacity": {"base": 1, "stops": [[15, 0], [16, 1]]},
+ "@aeroway": "#f0ede9",
+ "@motorway": "#fc8",
+ "@motorway_casing": "#e9ac77",
+ "@motorway_tunnel": "#ffdaa6",
+ "@main": "#fea",
+ "@main_tunnel": "#fff4c6",
+ "@street": "#fff",
+ "@street_limited": "#f3f3f3",
+ "@street_casing": "#cfcdca",
+ "@path": "#cba",
+ "@rail": "#bbb",
+ "@text": "#334",
+ "@text_halo": "rgba(255,255,255,0.8)",
+ "@marine_text": "#74aee9",
+ "@marine_text_halo": "rgba(255,255,255,0.7)",
+ "@poi_text": "#666",
+ "@poi_text_halo": "#ffffff",
+ "@maki": "#666",
+ "@point_translate": [0, -30],
+ "@tunnel_line_dasharray": [{
+ "base": 1.5, "stops": [[12, 6], [20, 9]]
+ }, {
+ "base": 1.5, "stops": [[12, 2], [20, 3]]
+ }],
+ "@motorway_width": {"base": 1.2, "stops": [[6.5, 0], [7, 0.5], [20, 18]]},
+ "@motorway_casing_width": {"base": 1.2, "stops": [[5, 0.4], [6, 0.6], [7, 1.5], [20, 22]]},
+ "@motorway_link_width": {"base": 1.2, "stops": [[12.5, 0], [13, 1.5], [20, 10]]},
+ "@motorway_link_casing_width": {"base": 1.2, "stops": [[12, 1], [13, 3], [20, 13]]},
+ "@main_width": {"base": 1.2, "stops": [[6.5, 0], [7, 0.5], [20, 14]]},
+ "@main_casing_width": {"base": 1.2, "stops": [[5, 0.1], [6, 0.2], [7, 1.5], [20, 18]]},
+ "@street_width": {"base": 1.2, "stops": [[13.5, 0], [14, 2.5], [20, 11.5]]},
+ "@street_casing_width": {"base": 1.2, "stops": [[12, 0.5], [13, 1], [14, 4], [20, 15]]},
+ "@street_casing_opacity": {"stops": [[12, 0], [12.5, 1]]},
+ "@service_casing_width": {"base": 1.2, "stops": [[15, 1], [16, 4], [20, 11]]},
+ "@service_width": {"base": 1.2, "stops": [[15.5, 0], [16, 2], [20, 7.5]]},
+ "@path_width": {"base": 1.2, "stops": [[15, 1.2], [20, 4]]},
+ "@path_line_dasharray": [{
+ "base": 1.2, "stops": [[15, 2], [20, 4]]
+ },{
+ "base": 1.2, "stops": [[15, 1], [20, 2]]
+ }],
+ "@rail_width": {"base": 1.4, "stops": [[14, 0.4], [15, 0.75], [20, 2]]},
+ "@rail_hatch_width": {"base": 1.4, "stops": [[14.5, 0], [15, 3], [20, 8]]},
+ "@rail_hatch_line_dasharray": [2, 30],
+ "@admin_level_3_width": {
+ "base": 1,
+ "stops": [[4, 0.4], [5, 1], [12, 3]]
+ },
+ "@admin_level_2_width": {
+ "base": 1,
+ "stops": [[4, 1.4], [5, 2], [12, 8]]
+ }
+ },
+ "sources": {
+ "mapbox": {
+ "type": "vector",
+ "url": "mapbox://mapbox.mapbox-streets-v6-dev",
+ "maxZoom": 15
+ }
+ },
+ "layers": [{
+ "id": "background",
+ "style": {
+ "background-color": "@land"
+ },
+ "type": "background"
+ }, {
+ "id": "landuse_park",
+ "source": "mapbox",
+ "source-layer": "landuse",
+ "filter": { "class": "park" },
+ "style": {
+ "fill-color": "@park"
+ },
+ "type": "fill"
+ }, {
+ "id": "landuse_cemetary",
+ "source": "mapbox",
+ "source-layer": "landuse",
+ "filter": { "class": "cemetary" },
+ "style": {
+ "fill-color": "@cemetary"
+ },
+ "type": "fill"
+ }, {
+ "id": "landuse_hospital",
+ "source": "mapbox",
+ "source-layer": "landuse",
+ "filter": { "class": "hospital" },
+ "style": {
+ "fill-color": "@hospital"
+ },
+ "type": "fill"
+ }, {
+ "id": "landuse_school",
+ "source": "mapbox",
+ "source-layer": "landuse",
+ "filter": { "class": "school" },
+ "style": {
+ "fill-color": "@school"
+ },
+ "type": "fill"
+ }, {
+ "id": "landuse_wood",
+ "source": "mapbox",
+ "source-layer": "landuse",
+ "filter": { "class": "wood" },
+ "style": {
+ "fill-color": "@wood",
+ "fill-opacity": 0.1
+ },
+ "type": "fill"
+ }, {
+ "id": "waterway",
+ "source": "mapbox",
+ "source-layer": "waterway",
+ "filter": {
+ "class": {
+ "!=": ["river", "stream", "canal"]
+ }
+ },
+ "render": {
+ "line-cap": "round"
+ },
+ "style": {
+ "line-color": "@water",
+ "line-width": {
+ "base": 1.3,
+ "stops": [[13, 0.5], [20, 2]]
+ }
+ },
+ "type": "line"
+ }, {
+ "id": "waterway_river",
+ "source": "mapbox",
+ "source-layer": "waterway",
+ "filter": { "class": "river" },
+ "render": {
+ "line-cap": "round"
+ },
+ "style": {
+ "line-color": "@water",
+ "line-width": {
+ "base": 1.2,
+ "stops": [[11, 0.5], [20, 6]]
+ }
+ },
+ "type": "line"
+ }, {
+ "id": "waterway_stream_canal",
+ "source": "mapbox",
+ "source-layer": "waterway",
+ "filter": { "class": ["stream", "canal"] },
+ "render": {
+ "line-cap": "round"
+ },
+ "style": {
+ "line-color": "@water",
+ "line-width": {
+ "base": 1.3,
+ "stops": [[13, 0.5], [20, 6]]
+ }
+ },
+ "type": "line"
+ }, {
+ "id": "water",
+ "source": "mapbox",
+ "source-layer": "water",
+ "style": {
+ "fill-color": "@water"
+ },
+ "type": "fill"
+ }, {
+ "id": "water_offset",
+ "source": "mapbox",
+ "source-layer": "water",
+ "type": "fill",
+ "style": {
+ "fill-color": "white",
+ "fill-opacity": 0.3,
+ "fill-translate": [0, 2.5]
+ }
+ }, {
+ "id": "water_pattern",
+ "ref": "water",
+ "style": {
+ "fill-image": "wave",
+ "fill-translate": [0, 2.5]
+ }
+ }, {
+ "id": "aeroway_fill",
+ "source": "mapbox",
+ "source-layer": "aeroway",
+ "min-zoom": 11,
+ "filter": {
+ "$type": "Polygon"
+ },
+ "style": {
+ "fill-color": "@aeroway",
+ "fill-opacity": 0.7
+ },
+ "type": "fill"
+ }, {
+ "id": "aeroway_runway",
+ "source": "mapbox",
+ "source-layer": "aeroway",
+ "min-zoom": 11,
+ "filter": {
+ "$type": "LineString",
+ "type": "runway" },
+ "style": {
+ "line-color": "@aeroway",
+ "line-width": {
+ "base": 1.2,
+ "stops": [[11, 3], [20, 16]]
+ }
+ },
+ "type": "line"
+ }, {
+ "id": "aeroway_taxiway",
+ "source": "mapbox",
+ "source-layer": "aeroway",
+ "min-zoom": 11,
+ "filter": {
+ "$type": "LineString",
+ "type": "taxiway" },
+ "style": {
+ "line-color": "@aeroway",
+ "line-width": {
+ "base": 1.2,
+ "stops": [[11, 0.5], [20, 6]]
+ }
+ },
+ "type": "line"
+ }, {
+ "id": "building",
+ "source": "mapbox",
+ "source-layer": "building",
+ "style": {
+ "fill-color": "@building_color_transition"
+ },
+ "type": "fill"
+ }, {
+ "id": "building_top",
+ "ref": "building",
+ "style": {
+ "fill-color": "@building",
+ "fill-opacity": "@building_opacity",
+ "fill-translate": [{
+ "base": 1,
+ "stops": [[15, 0], [16, -2] ]
+ }, {
+ "base": 1,
+ "stops": [[15, 0], [16, -2] ]
+ }],
+ "fill-outline-color": "@building_shadow"
+ }
+ }, {
+ "id": "tunnel_motorway_link_casing",
+ "source": "mapbox",
+ "source-layer": "tunnel",
+ "filter": { "class": "motorway_link" },
+ "render": {
+ "line-cap": "round",
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@motorway_casing",
+ "line-dasharray": "@tunnel_line_dasharray",
+ "line-width": "@motorway_link_casing_width"
+ },
+ "type": "line"
+ }, {
+ "id": "tunnel_service_casing",
+ "source": "mapbox",
+ "source-layer": "tunnel",
+ "filter": { "class": "service" },
+ "render": {
+ "line-cap": "round",
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@street_casing",
+ "line-dasharray": "@tunnel_line_dasharray",
+ "line-width": "@service_casing_width"
+ },
+ "type": "line"
+ }, {
+ "id": "tunnel_street_casing",
+ "source": "mapbox",
+ "source-layer": "tunnel",
+ "filter": { "class": ["street", "street_limited"] },
+ "render": {
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@street_casing",
+ "line-dasharray": [7, 2],
+ "line-width": "@street_casing_width",
+ "line-opacity": "@street_casing_opacity"
+ },
+ "type": "line"
+ }, {
+ "id": "tunnel_main_casing",
+ "source": "mapbox",
+ "source-layer": "tunnel",
+ "filter": { "class": "main" },
+ "render": {
+ "line-cap": "round",
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@motorway_casing",
+ "line-dasharray": "@tunnel_line_dasharray",
+ "line-width": "@main_casing_width"
+ },
+ "type": "line"
+ }, {
+ "id": "tunnel_motorway_casing",
+ "source": "mapbox",
+ "source-layer": "tunnel",
+ "filter": { "class": "motorway" },
+ "render": {
+ "line-cap": "round",
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@motorway_casing",
+ "line-dasharray": "@tunnel_line_dasharray",
+ "line-width": "@motorway_casing_width"
+ },
+ "type": "line"
+ }, {
+ "id": "tunnel_path",
+ "source": "mapbox",
+ "source-layer": "tunnel",
+ "filter": { "class": "path" },
+ "type": "line",
+ "style": {
+ "line-color": "@path",
+ "line-dasharray": "@path_line_dasharray",
+ "line-width": "@path_width"
+ }
+ }, {
+ "id": "tunnel_motorway_link",
+ "ref": "tunnel_motorway_link_casing",
+ "style": {
+ "line-color": "@motorway",
+ "line-width": "@motorway_link_width"
+ }
+ }, {
+ "id": "tunnel_service",
+ "ref": "tunnel_service_casing",
+ "style": {
+ "line-color": "@street",
+ "line-width": "@service_width"
+ }
+ }, {
+ "id": "tunnel_street",
+ "ref": "tunnel_street_casing",
+ "style": {
+ "line-color": "@street",
+ "line-width": "@street_width"
+ }
+ }, {
+ "id": "tunnel_main",
+ "ref": "tunnel_main_casing",
+ "style": {
+ "line-color": "@main_tunnel",
+ "line-width": "@main_width"
+ }
+ }, {
+ "id": "tunnel_motorway",
+ "ref": "tunnel_motorway_casing",
+ "style": {
+ "line-color": "@motorway_tunnel",
+ "line-width": "@motorway_width"
+ }
+ }, {
+ "id": "tunnel_major_rail",
+ "source": "mapbox",
+ "source-layer": "tunnel",
+ "filter": { "class": "major_rail" },
+ "style": {
+ "line-color": "@rail",
+ "line-width": "@rail_width"
+ },
+ "type": "line"
+ }, {
+ "id": "tunnel_major_rail_hatching",
+ "ref": "tunnel_major_rail",
+ "style": {
+ "line-color": "@rail",
+ "line-dasharray": "@rail_hatch_line_dasharray",
+ "line-width": "@rail_hatch_width"
+ }
+ }, {
+ "id": "road_motorway_link_casing",
+ "source": "mapbox",
+ "source-layer": "road",
+ "min-zoom": 12,
+ "filter": { "class": "motorway_link" },
+ "render": {
+ "line-cap": "round",
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@motorway_casing",
+ "line-width": "@motorway_link_casing_width"
+ },
+ "type": "line"
+ }, {
+ "id": "road_service_casing",
+ "source": "mapbox",
+ "source-layer": "road",
+ "filter": { "class": "service" },
+ "render": {
+ "line-cap": "round",
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@street_casing",
+ "line-width": "@service_casing_width"
+ },
+ "type": "line"
+ }, {
+ "id": "road_street_casing",
+ "source": "mapbox",
+ "source-layer": "road",
+ "filter": { "class": ["street", "street_limited"], "$type": "LineString" },
+ "render": {
+ "line-cap": "round",
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@street_casing",
+ "line-width": "@street_casing_width",
+ "line-opacity": "@street_casing_opacity"
+ },
+ "type": "line"
+ }, {
+ "id": "road_main_casing",
+ "source": "mapbox",
+ "source-layer": "road",
+ "filter": { "class": "main" },
+ "render": {
+ "line-cap": "round",
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@motorway_casing",
+ "line-width": "@main_casing_width"
+ },
+ "type": "line"
+ }, {
+ "id": "road_motorway_casing",
+ "source": "mapbox",
+ "source-layer": "road",
+ "min-zoom": 5,
+ "filter": { "class": "motorway" },
+ "render": {
+ "line-cap": "round",
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@motorway_casing",
+ "line-width": "@motorway_casing_width"
+ },
+ "type": "line"
+ }, {
+ "id": "road_path",
+ "source": "mapbox",
+ "source-layer": "road",
+ "filter": { "class": "path" },
+ "style": {
+ "line-color": "@path",
+ "line-dasharray": "@path_line_dasharray",
+ "line-width": "@path_width"
+ },
+ "type": "line"
+ }, {
+ "id": "road_motorway_link",
+ "ref": "road_motorway_link_casing",
+ "style": {
+ "line-color": "@motorway",
+ "line-width": "@motorway_link_width"
+ }
+ }, {
+ "id": "road_service",
+ "ref": "road_service_casing",
+ "style": {
+ "line-color": "@street",
+ "line-width": "@service_width"
+ }
+ }, {
+ "id": "road_street",
+ "ref": "road_street_casing",
+ "style": {
+ "line-color": "@street",
+ "line-width": "@street_width"
+ }
+ }, {
+ "id": "road_main",
+ "ref": "road_main_casing",
+ "style": {
+ "line-color": "@main",
+ "line-width": "@main_width"
+ }
+ }, {
+ "id": "road_motorway",
+ "ref": "road_motorway_casing",
+ "style": {
+ "line-color": "@motorway",
+ "line-width": "@motorway_width"
+ },
+ "type": "line"
+ }, {
+ "id": "road_major_rail",
+ "source": "mapbox",
+ "source-layer": "road",
+ "filter": { "class": "major_rail" },
+ "style": {
+ "line-color": "@rail",
+ "line-width": "@rail_width"
+ },
+ "type": "line"
+ }, {
+ "id": "road_major_rail_hatching",
+ "ref": "road_major_rail",
+ "style": {
+ "line-color": "@rail",
+ "line-dasharray": "@rail_hatch_line_dasharray",
+ "line-width": "@rail_hatch_width"
+ }
+ }, {
+ "id": "bridge_motorway_link_casing",
+ "source": "mapbox",
+ "source-layer": "bridge",
+ "filter": { "class": "motorway_link" },
+ "render": {
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@motorway_casing",
+ "line-width": "@motorway_link_casing_width"
+ },
+ "type": "line"
+ }, {
+ "id": "bridge_motorway_casing",
+ "source": "mapbox",
+ "source-layer": "bridge",
+ "filter": { "class": "motorway" },
+ "render": {
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@motorway_casing",
+ "line-width": "@motorway_casing_width"
+ },
+ "type": "line"
+ }, {
+ "id": "bridge_service_casing",
+ "source": "mapbox",
+ "source-layer": "bridge",
+ "filter": { "class": "service" },
+ "render": {
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@street_casing",
+ "line-width": "@service_casing_width"
+ },
+ "type": "line"
+ }, {
+ "id": "bridge_street_casing",
+ "source": "mapbox",
+ "source-layer": "bridge",
+ "filter": { "class": ["street", "street_limited"] },
+ "render": {
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@street_casing",
+ "line-width": "@street_casing_width",
+ "line-opacity": "@street_casing_opacity"
+ },
+ "type": "line"
+ }, {
+ "id": "bridge_main_casing",
+ "source": "mapbox",
+ "source-layer": "bridge",
+ "filter": { "class": "main" },
+ "render": {
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@motorway_casing",
+ "line-width": "@main_casing_width"
+ },
+ "type": "line"
+ }, {
+ "id": "bridge_path",
+ "source": "mapbox",
+ "source-layer": "bridge",
+ "filter": { "class": "path" },
+ "style": {
+ "line-color": "@path",
+ "line-dasharray": "@path_line_dasharray",
+ "line-width": "@path_width"
+ },
+ "type": "line"
+ }, {
+ "id": "bridge_motorway_link",
+ "ref": "bridge_motorway_link_casing",
+ "style": {
+ "line-color": "@motorway",
+ "line-width": "@motorway_link_width"
+ }
+ }, {
+ "id": "bridge_service",
+ "ref": "bridge_service_casing",
+ "style": {
+ "line-color": "@street",
+ "line-width": "@service_width"
+ }
+ }, {
+ "id": "bridge_street",
+ "ref": "bridge_street_casing",
+ "style": {
+ "line-color": "@street",
+ "line-width": "@street_width"
+ }
+ }, {
+ "id": "bridge_main",
+ "ref": "bridge_main_casing",
+ "style": {
+ "line-color": "@main",
+ "line-width": "@main_width"
+ }
+ }, {
+ "id": "bridge_motorway",
+ "ref": "bridge_motorway_casing",
+ "style": {
+ "line-color": "@motorway",
+ "line-width": "@motorway_width"
+ }
+ }, {
+ "id": "bridge_major_rail",
+ "source": "mapbox",
+ "source-layer": "bridge",
+ "filter": { "class": "major_rail" },
+ "style": {
+ "line-color": "@rail",
+ "line-width": "@rail_width"
+ },
+ "type": "line"
+ }, {
+ "id": "bridge_major_rail_hatching",
+ "ref": "bridge_major_rail",
+ "style": {
+ "line-color": "@rail",
+ "line-dasharray": "@rail_hatch_line_dasharray",
+ "line-width": "@rail_hatch_width"
+ }
+ }, {
+ "id": "admin",
+ "type": "composite",
+ "style": {
+ "composite-opacity": 0.5
+ },
+ "layers": [{
+ "id": "admin_level_3",
+ "source": "mapbox",
+ "source-layer": "admin",
+ "filter": {
+ "admin_level": {">=": 3},
+ "maritime": 0
+ },
+ "render": {
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@admin",
+ "line-dasharray": [10, 3],
+ "line-width": "@admin_level_3_width"
+ },
+ "type": "line"
+ }, {
+ "id": "admin_level_2",
+ "source": "mapbox",
+ "source-layer": "admin",
+ "filter": {
+ "admin_level": 2,
+ "disputed": 0,
+ "maritime": 0
+ },
+ "render": {
+ "line-cap": "round"
+ },
+ "style": {
+ "line-color": "@admin",
+ "line-width": "@admin_level_2_width"
+ },
+ "type": "line"
+ }, {
+ "id": "admin_level_2_disputed",
+ "source": "mapbox",
+ "source-layer": "admin",
+ "filter": {
+ "admin_level": 2,
+ "disputed": 1,
+ "maritime": 0
+ },
+ "render": {
+ "line-cap": "round"
+ },
+ "style": {
+ "line-color": "@admin",
+ "line-dasharray": [4, 4],
+ "line-width": "@admin_level_2_width"
+ },
+ "type": "line"
+ }, {
+ "id": "admin_level_3_maritime",
+ "source": "mapbox",
+ "source-layer": "admin",
+ "filter": {
+ "admin_level": {">=": 3},
+ "maritime": 1
+ },
+ "render": {
+ "line-join": "round"
+ },
+ "style": {
+ "line-color": "@water",
+ "line-dasharray": [10, 3],
+ "line-width": "@admin_level_3_width"
+ },
+ "type": "line"
+ }, {
+ "id": "admin_level_2_maritime",
+ "source": "mapbox",
+ "source-layer": "admin",
+ "filter": {
+ "admin_level": 2,
+ "maritime": 1
+ },
+ "render": {
+ "line-cap": "round"
+ },
+ "style": {
+ "line-color": "@water",
+ "line-width": "@admin_level_2_width"
+ },
+ "type": "line"
+ }]
+ }, {
+ "id": "country_label_line",
+ "source": "mapbox",
+ "source-layer": "country_label_line",
+ "style": {
+ "line-color": "@text",
+ "line-opacity": 0.5
+ },
+ "type": "line"
+ }, {
+ "id": "country_label_1",
+ "source": "mapbox",
+ "source-layer": "country_label",
+ "filter": {
+ "scalerank": 1
+ },
+ "render": {
+ "text-font": "@sans_bd",
+ "text-field": "@name",
+ "text-max-width": 6.25,
+ "text-transform": "uppercase",
+ "text-max-size": 17
+ },
+ "style": {
+ "text-color": "@text",
+ "text-halo-color": "@text_halo",
+ "text-halo-width": 2,
+ "text-halo-blur": 1,
+ "text-size": {
+ "stops": [[2, 13], [4, 17]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "country_label_2",
+ "source": "mapbox",
+ "source-layer": "country_label",
+ "filter": {
+ "scalerank": 2
+ },
+ "render": {
+ "text-font": "@sans_bd",
+ "text-field": "{name_en}",
+ "text-max-width": 6.25,
+ "text-transform": "uppercase",
+ "text-max-size": 17
+ },
+ "style": {
+ "text-color": "@text",
+ "text-halo-color": "@text_halo",
+ "text-halo-width": 2,
+ "text-halo-blur": 1,
+ "text-size": {
+ "stops": [[3, 13], [5, 17]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "country_label_3",
+ "source": "mapbox",
+ "source-layer": "country_label",
+ "filter": {
+ "scalerank": 3
+ },
+ "render": {
+ "text-font": "@sans_bd",
+ "text-field": "@name",
+ "text-max-width": 6.25,
+ "text-transform": "uppercase",
+ "text-max-size": 17
+ },
+ "style": {
+ "text-color": "@text",
+ "text-halo-color": "@text_halo",
+ "text-halo-width": 2,
+ "text-halo-blur": 1,
+ "text-size": {
+ "stops": [[4, 13], [7, 17]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "country_label_4",
+ "source": "mapbox",
+ "source-layer": "country_label",
+ "filter": {
+ "scalerank": {">=": 4}
+ },
+ "render": {
+ "text-font": "@sans_bd",
+ "text-field": "@name",
+ "text-max-width": 6.25,
+ "text-transform": "uppercase",
+ "text-max-size": 15
+ },
+ "style": {
+ "text-color": "@text",
+ "text-halo-color": "@text_halo",
+ "text-halo-width": 2,
+ "text-halo-blur": 1,
+ "text-size": {
+ "stops": [[5, 13], [6, 15]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "marine_label_point_1",
+ "source": "mapbox",
+ "source-layer": "marine_label",
+ "filter": {"labelrank": 1, "$type": "Point"},
+ "render": {
+ "text-font": "@sans_it",
+ "text-field": "@name",
+ "text-max-size": 22,
+ "text-max-width": 5,
+ "text-letter-spacing": 0.2,
+ "text-line-height": 1.6,
+ "symbol-placement": "point",
+ "text-offset": [0, 2.4]
+ },
+ "style": {
+ "text-color": "@marine_text",
+ "text-halo-color": "@marine_text_halo",
+ "text-halo-width": 0.75,
+ "text-halo-blur": 0.75,
+ "text-size": {
+ "stops": [[3, 18], [4, 22]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "marine_label_line_1",
+ "source": "mapbox",
+ "source-layer": "marine_label",
+ "filter": {"labelrank": 1, "$type": "LineString"},
+ "render": {
+ "text-font": "@sans_it",
+ "text-field": "@name",
+ "text-max-size": 14,
+ "text-letter-spacing": 0.2,
+ "symbol-placement": "line"
+ },
+ "style": {
+ "text-color": "@marine_text",
+ "text-halo-color": "@marine_text_halo",
+ "text-halo-width": 0.75,
+ "text-halo-blur": 0.75,
+ "text-size": {
+ "stops": [[3, 18], [4, 22]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "marine_label_point_2",
+ "source": "mapbox",
+ "source-layer": "marine_label",
+ "filter": {"labelrank": 2, "$type": "Point"},
+ "render": {
+ "text-font": "@sans_it",
+ "text-field": "@name",
+ "text-max-size": 16,
+ "text-max-width": 5,
+ "text-letter-spacing": 0.2,
+ "symbol-placement": "point"
+ },
+ "style": {
+ "text-color": "@marine_text",
+ "text-halo-color": "@marine_text_halo",
+ "text-halo-width": 0.75,
+ "text-halo-blur": 0.75,
+ "text-size": {
+ "stops": [[3, 14], [4, 16]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "marine_label_line_2",
+ "source": "mapbox",
+ "source-layer": "marine_label",
+ "filter": {"labelrank": 2, "$type": "LineString"},
+ "render": {
+ "text-font": "@sans_it",
+ "text-field": "@name",
+ "text-max-size": 16,
+ "text-letter-spacing": 0.2,
+ "symbol-placement": "line"
+ },
+ "style": {
+ "text-color": "@marine_text",
+ "text-halo-color": "@marine_text_halo",
+ "text-halo-width": 0.75,
+ "text-halo-blur": 0.75,
+ "text-size": {
+ "stops": [[3, 14], [4, 16]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "marine_label_3",
+ "source": "mapbox",
+ "source-layer": "marine_label",
+ "filter": {"labelrank": 3, "$type": "Point"},
+ "render": {
+ "text-font": "@sans_it",
+ "text-field": "@name",
+ "text-max-size": 14,
+ "text-max-width": 5,
+ "text-letter-spacing": 0.2,
+ "symbol-placement": "point"
+ },
+ "style": {
+ "text-color": "@marine_text",
+ "text-halo-color": "@marine_text_halo",
+ "text-halo-width": 0.75,
+ "text-halo-blur": 0.75,
+ "text-size": {
+ "stops": [[3, 11], [4, 14]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "marine_label_line_3",
+ "source": "mapbox",
+ "source-layer": "marine_label",
+ "filter": {"labelrank": 3, "$type": "LineString"},
+ "render": {
+ "text-font": "@sans_it",
+ "text-field": "@name",
+ "text-max-size": 14,
+ "text-letter-spacing": 0.2,
+ "symbol-placement": "line"
+ },
+ "style": {
+ "text-color": "@marine_text",
+ "text-halo-color": "@marine_text_halo",
+ "text-halo-width": 0.75,
+ "text-halo-blur": 0.75,
+ "text-size": {
+ "stops": [[3, 11], [4, 14]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "marine_label_4",
+ "source": "mapbox",
+ "source-layer": "marine_label",
+ "filter": {"labelrank": {">=": 4}, "$type": "Point"},
+ "render": {
+ "text-font": "@sans_it",
+ "text-field": "@name",
+ "text-max-size": 12,
+ "text-max-width": 6,
+ "text-letter-spacing": 0.2,
+ "symbol-placement": "point"
+ },
+ "style": {
+ "text-color": "@marine_text",
+ "text-halo-color": "@marine_text_halo",
+ "text-halo-width": 0.75,
+ "text-halo-blur": 0.75,
+ "text-size": {
+ "stops": [[3, 11], [4, 12]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "marine_label_line_4",
+ "source": "mapbox",
+ "source-layer": "marine_label",
+ "filter": {"labelrank": {">=": 4}, "$type": "LineString"},
+ "render": {
+ "text-font": "@sans_it",
+ "text-field": "@name",
+ "text-max-size": 12,
+ "text-letter-spacing": 0.2,
+ "symbol-placement": "line"
+ },
+ "style": {
+ "text-color": "@marine_text",
+ "text-halo-color": "@marine_text_halo",
+ "text-halo-width": 0.75,
+ "text-halo-blur": 0.75,
+ "text-size": {
+ "stops": [[3, 11], [4, 12]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "place_label_city",
+ "source": "mapbox",
+ "source-layer": "place_label",
+ "filter": { "type": "city" },
+ "render": {
+ "text-font": "@sans_md",
+ "text-field": "@name",
+ "text-max-size": 24,
+ "text-max-width": 8
+ },
+ "style": {
+ "text-color": "#333",
+ "text-halo-color": "@text_halo",
+ "text-halo-width": 1.2,
+ "text-size": {
+ "base": 1.2,
+ "stops": [[7, 14], [11, 24]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "place_label_town",
+ "source": "mapbox",
+ "source-layer": "place_label",
+ "filter": { "type": "town" },
+ "render": {
+ "text-font": "@sans",
+ "text-field": "@name",
+ "text-max-size": 24,
+ "text-max-width": 8
+ },
+ "style": {
+ "text-color": "#333",
+ "text-halo-color": "@text_halo",
+ "text-halo-width": 1.2,
+ "text-size": {
+ "base": 1.2,
+ "stops": [[10, 14], [15, 24]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "place_label_village",
+ "source": "mapbox",
+ "source-layer": "place_label",
+ "filter": { "type": "village" },
+ "render": {
+ "text-font": "@sans",
+ "text-field": "@name",
+ "text-max-size": 22,
+ "text-max-width": 8
+ },
+ "style": {
+ "text-color": "#333",
+ "text-halo-color": "@text_halo",
+ "text-halo-width": 1.2,
+ "text-size": {
+ "base": 1.2,
+ "stops": [[10, 12], [15, 22]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "road_label_highway_shields",
+ "source": "mapbox",
+ "source-layer": "road_label",
+ "filter": {"class": "motorway", "reflen": [1,2,3,4,5,6]},
+ "render": {
+ "symbol-placement": "line",
+ "symbol-min-distance": 500,
+ "icon-image": "motorway_{reflen}",
+ "icon-max-size": 1,
+ "text-field": "{ref}",
+ "text-font": "@sans_bd",
+ "text-max-size": 11,
+ "text-rotation-alignment": "viewport",
+ "icon-rotation-alignment": "viewport"
+ },
+ "style": {
+ "text-color": "#765",
+ "text-size": 11
+ },
+ "type": "symbol"
+ }, {
+ "id": "road_label",
+ "source": "mapbox",
+ "source-layer": "road_label",
+ "filter": { "$type": "LineString" },
+ "render": {
+ "text-font": "@sans",
+ "text-field": "@name",
+ "text-max-size": 13,
+ "symbol-placement": "line"
+ },
+ "style": {
+ "text-color": "#765",
+ "text-halo-color": "#fff",
+ "text-halo-width": 1,
+ "text-halo-blur": 0.5,
+ "text-size": {
+ "stops": [[13, 12], [14, 13]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "place_label_other",
+ "source": "mapbox",
+ "source-layer": "place_label",
+ "filter": { "type": ["hamlet", "suburb", "neighbourhood"] },
+ "render": {
+ "text-font": "@sans_bd",
+ "text-transform": "uppercase",
+ "text-letter-spacing": 0.1,
+ "text-field": "@name",
+ "text-max-size": 14,
+ "text-max-width": 9
+ },
+ "style": {
+ "text-color": "#633",
+ "text-halo-color": "@text_halo",
+ "text-halo-width": 1.2,
+ "text-size": {
+ "base": 1.2,
+ "stops": [[12, 10], [15, 14]]
+ }
+ },
+ "type": "symbol"
+ }, {
+ "id": "poi_label_1",
+ "source": "mapbox",
+ "source-layer": "poi_label",
+ "filter": { "$type": "Point", "scalerank": 1 },
+ "render": {
+ "icon-image": "{maki}-12",
+ "text-font": "@sans_md",
+ "text-field": "@name",
+ "text-max-size": 12,
+ "text-max-width": 9,
+ "text-padding": 2,
+ "text-offset": [0, 0.6],
+ "text-vertical-align": "top"
+ },
+ "style": {
+ "text-color": "@poi_text",
+ "text-size": 12,
+ "text-halo-color": "@poi_text_halo",
+ "text-halo-width": 1,
+ "text-halo-blur": 0.5
+ },
+ "min-zoom": 13,
+ "type": "symbol"
+ }, {
+ "id": "poi_label_2",
+ "source": "mapbox",
+ "source-layer": "poi_label",
+ "filter": { "$type": "Point", "scalerank": 2 },
+ "render": {
+ "icon-image": "{maki}-12",
+ "text-font": "@sans_md",
+ "text-field": "@name",
+ "text-max-size": 12,
+ "text-max-width": 9,
+ "text-padding": 2,
+ "text-offset": [0, 0.6],
+ "text-vertical-align": "top"
+ },
+ "style": {
+ "text-color": "@poi_text",
+ "text-size": 12,
+ "text-halo-color": "@poi_text_halo",
+ "text-halo-width": 1,
+ "text-halo-blur": 0.5
+ },
+ "min-zoom": 14,
+ "type": "symbol"
+ }, {
+ "id": "poi_label_3",
+ "source": "mapbox",
+ "source-layer": "poi_label",
+ "filter": { "$type": "Point", "scalerank": 3 },
+ "render": {
+ "icon-image": "{maki}-12",
+ "text-font": "@sans_md",
+ "text-field": "@name",
+ "text-max-size": 12,
+ "text-max-width": 9,
+ "text-padding": 2,
+ "text-offset": [0, 0.6],
+ "text-vertical-align": "top"
+ },
+ "style": {
+ "text-color": "@poi_text",
+ "text-size": 12,
+ "text-halo-color": "@poi_text_halo",
+ "text-halo-width": 1,
+ "text-halo-blur": 0.5
+ },
+ "min-zoom": 15,
+ "type": "symbol"
+ }, {
+ "id": "poi_label_4",
+ "source": "mapbox",
+ "source-layer": "poi_label",
+ "filter": { "$type": "Point", "scalerank": 4 },
+ "render": {
+ "icon-image": "{maki}-12",
+ "text-font": "@sans_md",
+ "text-field": "@name",
+ "text-max-size": 12,
+ "text-max-width": 9,
+ "text-padding": 2,
+ "text-offset": [0, 0.6],
+ "text-vertical-align": "top"
+ },
+ "style": {
+ "text-color": "@poi_text",
+ "text-size": 12,
+ "text-halo-color": "@poi_text_halo",
+ "text-halo-width": 1,
+ "text-halo-blur": 0.5
+ },
+ "min-zoom": 16,
+ "type": "symbol"
+ }, {
+ "id": "poi_label_other",
+ "source": "mapbox",
+ "source-layer": "poi_label",
+ "filter": { "$type": "Point", "scalerank": {">=": 5} },
+ "render": {
+ "icon-image": "{maki}-12",
+ "text-font": "@sans_md",
+ "text-field": "@name",
+ "text-max-size": 12,
+ "text-max-width": 9,
+ "text-padding": 2,
+ "text-offset": [0, 0.6],
+ "text-vertical-align": "top"
+ },
+ "style": {
+ "text-color": "@poi_text",
+ "text-size": 12,
+ "text-halo-color": "@poi_text_halo",
+ "text-halo-width": 1,
+ "text-halo-blur": 0.5
+ },
+ "min-zoom": 17,
+ "type": "symbol"
+ }, {
+ "id": "water_label",
+ "source": "mapbox",
+ "source-layer": "water_label",
+ "filter": { "$type": "Point" },
+ "render": {
+ "text-font": "@sans_it",
+ "text-field": "@name",
+ "text-max-size": 12,
+ "text-max-width": 5
+ },
+ "style": {
+ "text-size": 12,
+ "text-color": "@marine_text",
+ "text-halo-width": 1.5,
+ "text-halo-color": "@marine_text_halo"
+ },
+ "type": "symbol"
+ }]
+} \ No newline at end of file
diff --git a/test/enums.cpp b/test/enums.cpp
index e959994a57..f909631e3e 100644
--- a/test/enums.cpp
+++ b/test/enums.cpp
@@ -13,8 +13,7 @@ TEST(Enums, StyleLayerType) {
ASSERT_EQ(StyleLayerType::Unknown, StyleLayerTypeClass("unknown"));
ASSERT_EQ(StyleLayerType::Fill, StyleLayerTypeClass("fill"));
ASSERT_EQ(StyleLayerType::Line, StyleLayerTypeClass("line"));
- ASSERT_EQ(StyleLayerType::Icon, StyleLayerTypeClass("icon"));
- ASSERT_EQ(StyleLayerType::Text, StyleLayerTypeClass("text"));
+ ASSERT_EQ(StyleLayerType::Symbol, StyleLayerTypeClass("symbol"));
ASSERT_EQ(StyleLayerType::Raster, StyleLayerTypeClass("raster"));
ASSERT_EQ(StyleLayerType::Composite, StyleLayerTypeClass("composite"));
ASSERT_EQ(StyleLayerType::Background, StyleLayerTypeClass("background"));
@@ -22,8 +21,7 @@ TEST(Enums, StyleLayerType) {
ASSERT_EQ(StyleLayerType::Unknown, StyleLayerTypeClass(StyleLayerType::Unknown));
ASSERT_EQ(StyleLayerType::Fill, StyleLayerTypeClass(StyleLayerType::Fill));
ASSERT_EQ(StyleLayerType::Line, StyleLayerTypeClass(StyleLayerType::Line));
- ASSERT_EQ(StyleLayerType::Icon, StyleLayerTypeClass(StyleLayerType::Icon));
- ASSERT_EQ(StyleLayerType::Text, StyleLayerTypeClass(StyleLayerType::Text));
+ ASSERT_EQ(StyleLayerType::Symbol, StyleLayerTypeClass(StyleLayerType::Symbol));
ASSERT_EQ(StyleLayerType::Raster, StyleLayerTypeClass(StyleLayerType::Raster));
ASSERT_EQ(StyleLayerType::Composite, StyleLayerTypeClass(StyleLayerType::Composite));
ASSERT_EQ(StyleLayerType::Background, StyleLayerTypeClass(StyleLayerType::Background));
@@ -31,8 +29,7 @@ TEST(Enums, StyleLayerType) {
ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Unknown), StyleLayerTypeClass(StyleLayerType::Unknown));
ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Fill), StyleLayerTypeClass(StyleLayerType::Fill));
ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Line), StyleLayerTypeClass(StyleLayerType::Line));
- ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Icon), StyleLayerTypeClass(StyleLayerType::Icon));
- ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Text), StyleLayerTypeClass(StyleLayerType::Text));
+ ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Symbol), StyleLayerTypeClass(StyleLayerType::Symbol));
ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Raster), StyleLayerTypeClass(StyleLayerType::Raster));
ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Composite), StyleLayerTypeClass(StyleLayerType::Composite));
ASSERT_EQ(StyleLayerTypeClass(StyleLayerType::Background), StyleLayerTypeClass(StyleLayerType::Background));
diff --git a/test/fixtures/glyphs/Open Sans Semibold, Arial Unicode MS Bold/0-255.pbf b/test/fixtures/glyphs/Open Sans Semibold, Arial Unicode MS Bold/0-255.pbf
deleted file mode 100644
index cea1c094d6..0000000000
--- a/test/fixtures/glyphs/Open Sans Semibold, Arial Unicode MS Bold/0-255.pbf
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/sprites/outdoors.json b/test/fixtures/sprites/outdoors.json
deleted file mode 100644
index b2a7ddf53a..0000000000
--- a/test/fixtures/sprites/outdoors.json
+++ /dev/null
@@ -1 +0,0 @@
-{"wetland_noveg_64":{"x":0,"y":0,"width":64,"height":32,"pixelRatio":1},"wetland_64":{"x":66,"y":0,"width":64,"height":32,"pixelRatio":1},"airport-24":{"x":0,"y":34,"width":24,"height":24,"pixelRatio":1},"wetland_32":{"x":26,"y":34,"width":32,"height":16,"pixelRatio":1},"wetland_noveg_32":{"x":60,"y":34,"width":32,"height":16,"pixelRatio":1},"night-library-12":{"x":94,"y":34,"width":12,"height":12,"pixelRatio":1},"bakery-12":{"x":108,"y":34,"width":12,"height":12,"pixelRatio":1},"bank-12":{"x":0,"y":60,"width":12,"height":12,"pixelRatio":1},"bar-12":{"x":14,"y":60,"width":12,"height":12,"pixelRatio":1},"baseball-12":{"x":28,"y":60,"width":12,"height":12,"pixelRatio":1},"basketball-12":{"x":42,"y":60,"width":12,"height":12,"pixelRatio":1},"beer-12":{"x":56,"y":60,"width":12,"height":12,"pixelRatio":1},"bicycle-12":{"x":70,"y":60,"width":12,"height":12,"pixelRatio":1},"building-12":{"x":84,"y":60,"width":12,"height":12,"pixelRatio":1},"bus-12":{"x":98,"y":60,"width":12,"height":12,"pixelRatio":1},"cafe-12":{"x":112,"y":60,"width":12,"height":12,"pixelRatio":1},"camera-12":{"x":0,"y":74,"width":12,"height":12,"pixelRatio":1},"campsite-12":{"x":14,"y":74,"width":12,"height":12,"pixelRatio":1},"car-12":{"x":28,"y":74,"width":12,"height":12,"pixelRatio":1},"cemetery-12":{"x":42,"y":74,"width":12,"height":12,"pixelRatio":1},"chemist-12":{"x":56,"y":74,"width":12,"height":12,"pixelRatio":1},"cinema-12":{"x":70,"y":74,"width":12,"height":12,"pixelRatio":1},"circle-12":{"x":84,"y":74,"width":12,"height":12,"pixelRatio":1},"circle-stroked-12":{"x":98,"y":74,"width":12,"height":12,"pixelRatio":1},"city-12":{"x":112,"y":74,"width":12,"height":12,"pixelRatio":1},"clothing-store-12":{"x":0,"y":88,"width":12,"height":12,"pixelRatio":1},"college-12":{"x":14,"y":88,"width":12,"height":12,"pixelRatio":1},"commercial-12":{"x":28,"y":88,"width":12,"height":12,"pixelRatio":1},"cricket-12":{"x":42,"y":88,"width":12,"height":12,"pixelRatio":1},"cross-12":{"x":56,"y":88,"width":12,"height":12,"pixelRatio":1},"dam-12":{"x":70,"y":88,"width":12,"height":12,"pixelRatio":1},"danger-12":{"x":84,"y":88,"width":12,"height":12,"pixelRatio":1},"disability-12":{"x":98,"y":88,"width":12,"height":12,"pixelRatio":1},"dog-park-12":{"x":112,"y":88,"width":12,"height":12,"pixelRatio":1},"embassy-12":{"x":0,"y":102,"width":12,"height":12,"pixelRatio":1},"emergency-telephone-12":{"x":14,"y":102,"width":12,"height":12,"pixelRatio":1},"entrance-12":{"x":28,"y":102,"width":12,"height":12,"pixelRatio":1},"farm-12":{"x":42,"y":102,"width":12,"height":12,"pixelRatio":1},"fast-food-12":{"x":56,"y":102,"width":12,"height":12,"pixelRatio":1},"ferry-12":{"x":70,"y":102,"width":12,"height":12,"pixelRatio":1},"fire-station-12":{"x":84,"y":102,"width":12,"height":12,"pixelRatio":1},"fuel-12":{"x":98,"y":102,"width":12,"height":12,"pixelRatio":1},"garden-12":{"x":112,"y":102,"width":12,"height":12,"pixelRatio":1},"golf-12":{"x":0,"y":116,"width":12,"height":12,"pixelRatio":1},"grocery-12":{"x":14,"y":116,"width":12,"height":12,"pixelRatio":1},"hairdresser-12":{"x":28,"y":116,"width":12,"height":12,"pixelRatio":1},"harbor-12":{"x":42,"y":116,"width":12,"height":12,"pixelRatio":1},"heart-12":{"x":56,"y":116,"width":12,"height":12,"pixelRatio":1},"heliport-12":{"x":70,"y":116,"width":12,"height":12,"pixelRatio":1},"hospital-12":{"x":84,"y":116,"width":12,"height":12,"pixelRatio":1},"industrial-12":{"x":98,"y":116,"width":12,"height":12,"pixelRatio":1},"land-use-12":{"x":112,"y":116,"width":12,"height":12,"pixelRatio":1},"laundry-12":{"x":132,"y":0,"width":12,"height":12,"pixelRatio":1},"library-12":{"x":132,"y":14,"width":12,"height":12,"pixelRatio":1},"lighthouse-12":{"x":132,"y":28,"width":12,"height":12,"pixelRatio":1},"lodging-12":{"x":132,"y":42,"width":12,"height":12,"pixelRatio":1},"logging-12":{"x":132,"y":56,"width":12,"height":12,"pixelRatio":1},"london-underground-12":{"x":132,"y":70,"width":12,"height":12,"pixelRatio":1},"marker-12":{"x":132,"y":84,"width":12,"height":12,"pixelRatio":1},"marker-stroked-12":{"x":132,"y":98,"width":12,"height":12,"pixelRatio":1},"minefield-12":{"x":132,"y":112,"width":12,"height":12,"pixelRatio":1},"mobilephone-12":{"x":0,"y":130,"width":12,"height":12,"pixelRatio":1},"monument-12":{"x":14,"y":130,"width":12,"height":12,"pixelRatio":1},"museum-12":{"x":28,"y":130,"width":12,"height":12,"pixelRatio":1},"music-12":{"x":42,"y":130,"width":12,"height":12,"pixelRatio":1},"night-airfield-12":{"x":56,"y":130,"width":12,"height":12,"pixelRatio":1},"night-airport-12":{"x":70,"y":130,"width":12,"height":12,"pixelRatio":1},"night-alcohol-shop-12":{"x":84,"y":130,"width":12,"height":12,"pixelRatio":1},"night-america-football-12":{"x":98,"y":130,"width":12,"height":12,"pixelRatio":1},"night-art-gallery-12":{"x":112,"y":130,"width":12,"height":12,"pixelRatio":1},"night-bakery-12":{"x":126,"y":130,"width":12,"height":12,"pixelRatio":1},"night-bank-12":{"x":146,"y":0,"width":12,"height":12,"pixelRatio":1},"night-bar-12":{"x":146,"y":14,"width":12,"height":12,"pixelRatio":1},"night-baseball-12":{"x":146,"y":28,"width":12,"height":12,"pixelRatio":1},"night-basketball-12":{"x":146,"y":42,"width":12,"height":12,"pixelRatio":1},"night-beer-12":{"x":146,"y":56,"width":12,"height":12,"pixelRatio":1},"night-bicycle-12":{"x":146,"y":70,"width":12,"height":12,"pixelRatio":1},"night-building-12":{"x":146,"y":84,"width":12,"height":12,"pixelRatio":1},"night-bus-12":{"x":146,"y":98,"width":12,"height":12,"pixelRatio":1},"night-cafe-12":{"x":146,"y":112,"width":12,"height":12,"pixelRatio":1},"night-camera-12":{"x":146,"y":126,"width":12,"height":12,"pixelRatio":1},"night-campsite-12":{"x":0,"y":144,"width":12,"height":12,"pixelRatio":1},"night-car-12":{"x":14,"y":144,"width":12,"height":12,"pixelRatio":1},"night-cemetery-12":{"x":28,"y":144,"width":12,"height":12,"pixelRatio":1},"night-chemist-12":{"x":42,"y":144,"width":12,"height":12,"pixelRatio":1},"night-cinema-12":{"x":56,"y":144,"width":12,"height":12,"pixelRatio":1},"night-circle-12":{"x":70,"y":144,"width":12,"height":12,"pixelRatio":1},"night-circle-stroked-12":{"x":84,"y":144,"width":12,"height":12,"pixelRatio":1},"night-city-12":{"x":98,"y":144,"width":12,"height":12,"pixelRatio":1},"night-clothing-store-12":{"x":112,"y":144,"width":12,"height":12,"pixelRatio":1},"night-college-12":{"x":126,"y":144,"width":12,"height":12,"pixelRatio":1},"night-commercial-12":{"x":140,"y":144,"width":12,"height":12,"pixelRatio":1},"night-cricket-12":{"x":160,"y":0,"width":12,"height":12,"pixelRatio":1},"night-cross-12":{"x":160,"y":14,"width":12,"height":12,"pixelRatio":1},"night-dam-12":{"x":160,"y":28,"width":12,"height":12,"pixelRatio":1},"night-danger-12":{"x":160,"y":42,"width":12,"height":12,"pixelRatio":1},"night-disability-12":{"x":160,"y":56,"width":12,"height":12,"pixelRatio":1},"night-dog-park-12":{"x":160,"y":70,"width":12,"height":12,"pixelRatio":1},"night-embassy-12":{"x":160,"y":84,"width":12,"height":12,"pixelRatio":1},"night-emergency-telephone-12":{"x":160,"y":98,"width":12,"height":12,"pixelRatio":1},"night-entrance-12":{"x":160,"y":112,"width":12,"height":12,"pixelRatio":1},"night-farm-12":{"x":160,"y":126,"width":12,"height":12,"pixelRatio":1},"night-fast-food-12":{"x":160,"y":140,"width":12,"height":12,"pixelRatio":1},"night-ferry-12":{"x":0,"y":158,"width":12,"height":12,"pixelRatio":1},"night-fire-station-12":{"x":14,"y":158,"width":12,"height":12,"pixelRatio":1},"night-fuel-12":{"x":28,"y":158,"width":12,"height":12,"pixelRatio":1},"night-garden-12":{"x":42,"y":158,"width":12,"height":12,"pixelRatio":1},"night-golf-12":{"x":56,"y":158,"width":12,"height":12,"pixelRatio":1},"night-grocery-12":{"x":70,"y":158,"width":12,"height":12,"pixelRatio":1},"night-hairdresser-12":{"x":84,"y":158,"width":12,"height":12,"pixelRatio":1},"night-harbor-12":{"x":98,"y":158,"width":12,"height":12,"pixelRatio":1},"night-heart-12":{"x":112,"y":158,"width":12,"height":12,"pixelRatio":1},"night-heliport-12":{"x":126,"y":158,"width":12,"height":12,"pixelRatio":1},"night-hospital-12":{"x":140,"y":158,"width":12,"height":12,"pixelRatio":1},"night-industrial-12":{"x":154,"y":158,"width":12,"height":12,"pixelRatio":1},"night-land-use-12":{"x":174,"y":0,"width":12,"height":12,"pixelRatio":1},"night-laundry-12":{"x":174,"y":14,"width":12,"height":12,"pixelRatio":1},"airport-12":{"x":174,"y":28,"width":12,"height":12,"pixelRatio":1},"night-lighthouse-12":{"x":174,"y":42,"width":12,"height":12,"pixelRatio":1},"night-lodging-12":{"x":174,"y":56,"width":12,"height":12,"pixelRatio":1},"night-logging-12":{"x":174,"y":70,"width":12,"height":12,"pixelRatio":1},"night-london-underground-12":{"x":174,"y":84,"width":12,"height":12,"pixelRatio":1},"night-marker-12":{"x":174,"y":98,"width":12,"height":12,"pixelRatio":1},"night-marker-stroked-12":{"x":174,"y":112,"width":12,"height":12,"pixelRatio":1},"night-minefield-12":{"x":174,"y":126,"width":12,"height":12,"pixelRatio":1},"night-mobilephone-12":{"x":174,"y":140,"width":12,"height":12,"pixelRatio":1},"night-monument-12":{"x":174,"y":154,"width":12,"height":12,"pixelRatio":1},"night-museum-12":{"x":0,"y":172,"width":12,"height":12,"pixelRatio":1},"night-music-12":{"x":14,"y":172,"width":12,"height":12,"pixelRatio":1},"night-oil-well-12":{"x":28,"y":172,"width":12,"height":12,"pixelRatio":1},"night-park-12":{"x":42,"y":172,"width":12,"height":12,"pixelRatio":1},"night-park2-12":{"x":56,"y":172,"width":12,"height":12,"pixelRatio":1},"night-parking-12":{"x":70,"y":172,"width":12,"height":12,"pixelRatio":1},"night-parking-garage-12":{"x":84,"y":172,"width":12,"height":12,"pixelRatio":1},"night-pharmacy-12":{"x":98,"y":172,"width":12,"height":12,"pixelRatio":1},"night-pitch-12":{"x":112,"y":172,"width":12,"height":12,"pixelRatio":1},"night-place-of-worship-12":{"x":126,"y":172,"width":12,"height":12,"pixelRatio":1},"night-playground-12":{"x":140,"y":172,"width":12,"height":12,"pixelRatio":1},"night-police-12":{"x":154,"y":172,"width":12,"height":12,"pixelRatio":1},"night-polling-place-12":{"x":168,"y":172,"width":12,"height":12,"pixelRatio":1},"night-post-12":{"x":188,"y":0,"width":12,"height":12,"pixelRatio":1},"night-prison-12":{"x":188,"y":14,"width":12,"height":12,"pixelRatio":1},"night-rail-12":{"x":188,"y":28,"width":12,"height":12,"pixelRatio":1},"night-rail-above-12":{"x":188,"y":42,"width":12,"height":12,"pixelRatio":1},"night-rail-light-12":{"x":188,"y":56,"width":12,"height":12,"pixelRatio":1},"night-rail-metro-12":{"x":188,"y":70,"width":12,"height":12,"pixelRatio":1},"night-rail-underground-12":{"x":188,"y":84,"width":12,"height":12,"pixelRatio":1},"night-religious-christian-12":{"x":188,"y":98,"width":12,"height":12,"pixelRatio":1},"night-religious-jewish-12":{"x":188,"y":112,"width":12,"height":12,"pixelRatio":1},"night-religious-muslim-12":{"x":188,"y":126,"width":12,"height":12,"pixelRatio":1},"night-restaurant-12":{"x":188,"y":140,"width":12,"height":12,"pixelRatio":1},"night-roadblock-12":{"x":188,"y":154,"width":12,"height":12,"pixelRatio":1},"night-rocket-12":{"x":188,"y":168,"width":12,"height":12,"pixelRatio":1},"night-school-12":{"x":0,"y":186,"width":12,"height":12,"pixelRatio":1},"night-scooter-12":{"x":14,"y":186,"width":12,"height":12,"pixelRatio":1},"night-shop-12":{"x":28,"y":186,"width":12,"height":12,"pixelRatio":1},"night-skiing-12":{"x":42,"y":186,"width":12,"height":12,"pixelRatio":1},"night-slaughterhouse-12":{"x":56,"y":186,"width":12,"height":12,"pixelRatio":1},"night-soccer-12":{"x":70,"y":186,"width":12,"height":12,"pixelRatio":1},"night-square-12":{"x":84,"y":186,"width":12,"height":12,"pixelRatio":1},"night-square-stroked-12":{"x":98,"y":186,"width":12,"height":12,"pixelRatio":1},"night-star-12":{"x":112,"y":186,"width":12,"height":12,"pixelRatio":1},"night-star-stroked-12":{"x":126,"y":186,"width":12,"height":12,"pixelRatio":1},"night-suitcase-12":{"x":140,"y":186,"width":12,"height":12,"pixelRatio":1},"night-swimming-12":{"x":154,"y":186,"width":12,"height":12,"pixelRatio":1},"night-telephone-12":{"x":168,"y":186,"width":12,"height":12,"pixelRatio":1},"night-tennis-12":{"x":182,"y":186,"width":12,"height":12,"pixelRatio":1},"night-theatre-12":{"x":202,"y":0,"width":12,"height":12,"pixelRatio":1},"night-toilets-12":{"x":202,"y":14,"width":12,"height":12,"pixelRatio":1},"night-town-12":{"x":202,"y":28,"width":12,"height":12,"pixelRatio":1},"night-town-hall-12":{"x":202,"y":42,"width":12,"height":12,"pixelRatio":1},"night-triangle-12":{"x":202,"y":56,"width":12,"height":12,"pixelRatio":1},"night-triangle-stroked-12":{"x":202,"y":70,"width":12,"height":12,"pixelRatio":1},"night-village-12":{"x":202,"y":84,"width":12,"height":12,"pixelRatio":1},"night-warehouse-12":{"x":202,"y":98,"width":12,"height":12,"pixelRatio":1},"night-waste-basket-12":{"x":202,"y":112,"width":12,"height":12,"pixelRatio":1},"night-water-12":{"x":202,"y":126,"width":12,"height":12,"pixelRatio":1},"night-wetland-12":{"x":202,"y":140,"width":12,"height":12,"pixelRatio":1},"night-zoo-12":{"x":202,"y":154,"width":12,"height":12,"pixelRatio":1},"oil-well-12":{"x":202,"y":168,"width":12,"height":12,"pixelRatio":1},"park-12":{"x":202,"y":182,"width":12,"height":12,"pixelRatio":1},"park2-12":{"x":0,"y":200,"width":12,"height":12,"pixelRatio":1},"parking-12":{"x":14,"y":200,"width":12,"height":12,"pixelRatio":1},"parking-garage-12":{"x":28,"y":200,"width":12,"height":12,"pixelRatio":1},"pharmacy-12":{"x":42,"y":200,"width":12,"height":12,"pixelRatio":1},"pitch-12":{"x":56,"y":200,"width":12,"height":12,"pixelRatio":1},"place-of-worship-12":{"x":70,"y":200,"width":12,"height":12,"pixelRatio":1},"playground-12":{"x":84,"y":200,"width":12,"height":12,"pixelRatio":1},"police-12":{"x":98,"y":200,"width":12,"height":12,"pixelRatio":1},"polling-place-12":{"x":112,"y":200,"width":12,"height":12,"pixelRatio":1},"post-12":{"x":126,"y":200,"width":12,"height":12,"pixelRatio":1},"prison-12":{"x":140,"y":200,"width":12,"height":12,"pixelRatio":1},"rail-12":{"x":154,"y":200,"width":12,"height":12,"pixelRatio":1},"rail-above-12":{"x":168,"y":200,"width":12,"height":12,"pixelRatio":1},"rail-light-12":{"x":182,"y":200,"width":12,"height":12,"pixelRatio":1},"rail-metro-12":{"x":196,"y":200,"width":12,"height":12,"pixelRatio":1},"rail-underground-12":{"x":216,"y":0,"width":12,"height":12,"pixelRatio":1},"religious-christian-12":{"x":216,"y":14,"width":12,"height":12,"pixelRatio":1},"religious-jewish-12":{"x":216,"y":28,"width":12,"height":12,"pixelRatio":1},"religious-muslim-12":{"x":216,"y":42,"width":12,"height":12,"pixelRatio":1},"restaurant-12":{"x":216,"y":56,"width":12,"height":12,"pixelRatio":1},"roadblock-12":{"x":216,"y":70,"width":12,"height":12,"pixelRatio":1},"rocket-12":{"x":216,"y":84,"width":12,"height":12,"pixelRatio":1},"school-12":{"x":216,"y":98,"width":12,"height":12,"pixelRatio":1},"scooter-12":{"x":216,"y":112,"width":12,"height":12,"pixelRatio":1},"shop-12":{"x":216,"y":126,"width":12,"height":12,"pixelRatio":1},"skiing-12":{"x":216,"y":140,"width":12,"height":12,"pixelRatio":1},"slaughterhouse-12":{"x":216,"y":154,"width":12,"height":12,"pixelRatio":1},"soccer-12":{"x":216,"y":168,"width":12,"height":12,"pixelRatio":1},"square-12":{"x":216,"y":182,"width":12,"height":12,"pixelRatio":1},"square-stroked-12":{"x":216,"y":196,"width":12,"height":12,"pixelRatio":1},"star-12":{"x":0,"y":214,"width":12,"height":12,"pixelRatio":1},"star-stroked-12":{"x":14,"y":214,"width":12,"height":12,"pixelRatio":1},"suitcase-12":{"x":28,"y":214,"width":12,"height":12,"pixelRatio":1},"swimming-12":{"x":42,"y":214,"width":12,"height":12,"pixelRatio":1},"telephone-12":{"x":56,"y":214,"width":12,"height":12,"pixelRatio":1},"tennis-12":{"x":70,"y":214,"width":12,"height":12,"pixelRatio":1},"theatre-12":{"x":84,"y":214,"width":12,"height":12,"pixelRatio":1},"toilets-12":{"x":98,"y":214,"width":12,"height":12,"pixelRatio":1},"town-12":{"x":112,"y":214,"width":12,"height":12,"pixelRatio":1},"town-hall-12":{"x":126,"y":214,"width":12,"height":12,"pixelRatio":1},"triangle-12":{"x":140,"y":214,"width":12,"height":12,"pixelRatio":1},"triangle-stroked-12":{"x":154,"y":214,"width":12,"height":12,"pixelRatio":1},"village-12":{"x":168,"y":214,"width":12,"height":12,"pixelRatio":1},"warehouse-12":{"x":182,"y":214,"width":12,"height":12,"pixelRatio":1},"waste-basket-12":{"x":196,"y":214,"width":12,"height":12,"pixelRatio":1},"water-12":{"x":210,"y":214,"width":12,"height":12,"pixelRatio":1},"wetland-12":{"x":230,"y":0,"width":12,"height":12,"pixelRatio":1},"airfield-12":{"x":230,"y":14,"width":12,"height":12,"pixelRatio":1},"alcohol-shop-12":{"x":230,"y":28,"width":12,"height":12,"pixelRatio":1},"america-football-12":{"x":230,"y":42,"width":12,"height":12,"pixelRatio":1},"art-gallery-12":{"x":230,"y":56,"width":12,"height":12,"pixelRatio":1},"zoo-12":{"x":230,"y":70,"width":12,"height":12,"pixelRatio":1},"wetland_noveg_16":{"x":0,"y":228,"width":16,"height":8,"pixelRatio":1},"wetland_16":{"x":18,"y":228,"width":16,"height":8,"pixelRatio":1}} \ No newline at end of file
diff --git a/test/fixtures/sprites/outdoors.png b/test/fixtures/sprites/outdoors.png
deleted file mode 100644
index 61e99085f1..0000000000
--- a/test/fixtures/sprites/outdoors.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/styles/icons.info.json b/test/fixtures/styles/icons.info.json
deleted file mode 100644
index e116913aa4..0000000000
--- a/test/fixtures/styles/icons.info.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "default": {
- "zoom": 14,
- "center": [52.499167, 13.418056],
- "height": 256,
- "log": [
- [1, "INFO", "HttpRequest", 200, "sprites/outdoors.json"],
- [1, "INFO", "HttpRequest", 200, "sprites/outdoors.png"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5375.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5375.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5374.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5374.vector.pbf"],
- [6, "INFO", "HttpRequest"],
-
- [1, "INFO", "Sprite", "loaded sprites/outdoors"]
- ]
- }
-}
diff --git a/test/fixtures/styles/icons.style.json b/test/fixtures/styles/icons.style.json
deleted file mode 100644
index 46adfbd408..0000000000
--- a/test/fixtures/styles/icons.style.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "version": 3,
- "sources": {
- "mapbox": {
- "type": "vector",
- "url": "tiles/{z}-{x}-{y}.vector.pbf",
- "tileSize": 512,
- "maxZoom": 14
- }
- },
- "sprite": "sprites/outdoors",
- "layers": [
- {
- "id": "background",
- "type": "background",
- "style": {
- "background-color": "green"
- }
- },
- {
- "id": "poi",
- "source": "mapbox",
- "source-layer": "poi_label",
- "type": "icon",
- "filter": { "maki": "restaurant" },
- "render": {
- "icon-image": "{maki}-12",
- "icon-size": 12,
- "icon-allow-overlap": true
- }
- }
- ]
-}
diff --git a/test/fixtures/styles/icons/default.expected.png b/test/fixtures/styles/icons/default.expected.png
deleted file mode 100644
index 17e3252c88..0000000000
--- a/test/fixtures/styles/icons/default.expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/styles/line-color.info.json b/test/fixtures/styles/line-color.info.json
deleted file mode 100644
index d9be88b102..0000000000
--- a/test/fixtures/styles/line-color.info.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "default": {
- "zoom": 14,
- "center": [52.499167, 13.418056],
- "height": 256,
- "log": [
- [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5375.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5375.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5374.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5374.vector.pbf"],
- [4, "INFO", "HttpRequest"]
- ]
- },
- "colored": {
- "zoom": 14,
- "center": [52.499167, 13.418056],
- "height": 256,
- "classes": ["colored"],
- "log": [
- [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5375.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5375.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5374.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5374.vector.pbf"],
- [4, "INFO", "HttpRequest"]
- ]
- }
-}
diff --git a/test/fixtures/styles/line-color.style.json b/test/fixtures/styles/line-color.style.json
deleted file mode 100644
index 10f5fb9cb7..0000000000
--- a/test/fixtures/styles/line-color.style.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "version": 3,
- "sources": {
- "mapbox": {
- "type": "vector",
- "url": "tiles/{z}-{x}-{y}.vector.pbf",
- "tileSize": 512,
- "maxZoom": 14
- }
- },
- "layers": [
- {
- "id": "background",
- "type": "background",
- "style": {
- "background-color": "white"
- }
- },
- {
- "id": "road",
- "source": "mapbox",
- "source-layer": "road",
- "type": "line",
- "style": {
- "line-width": 2,
- "line-color": "#3590db"
- },
- "style.colored": {
- "line-color": "#222222"
- }
- }
- ]
-}
diff --git a/test/fixtures/styles/line-color/colored.expected.png b/test/fixtures/styles/line-color/colored.expected.png
deleted file mode 100644
index ffd1ac3fb5..0000000000
--- a/test/fixtures/styles/line-color/colored.expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/styles/line-color/default.expected.png b/test/fixtures/styles/line-color/default.expected.png
deleted file mode 100644
index 6369f5620b..0000000000
--- a/test/fixtures/styles/line-color/default.expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/styles/road-width.info.json b/test/fixtures/styles/road-width.info.json
deleted file mode 100644
index 0094f715ca..0000000000
--- a/test/fixtures/styles/road-width.info.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "z13.9": {
- "zoom": 13.9,
- "center": [52.499167, 13.418056],
- "height": 256,
- "log": [
- [1, "INFO", "HttpRequest", 200, "tiles/13-4401-2687.vector.pbf"],
- [1, "INFO", "HttpRequest"]
- ]
- },
- "z14.0": {
- "zoom": 14,
- "center": [52.499167, 13.418056],
- "height": 256,
- "log": [
- [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5375.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5375.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5374.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5374.vector.pbf"],
- [4, "INFO", "HttpRequest"]
- ]
- },
- "z14.1": {
- "zoom": 14.1,
- "center": [52.499167, 13.418056],
- "height": 256,
- "log": [
- [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5375.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5375.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5374.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5374.vector.pbf"],
- [4, "INFO", "HttpRequest"]
- ]
- },
- "z14.2": {
- "zoom": 14.2,
- "center": [52.499167, 13.418056],
- "height": 256,
- "log": [
- [1, "INFO", "HttpRequest", 200, "tiles/14-8803-5374.vector.pbf"],
- [1, "INFO", "HttpRequest", 200, "tiles/14-8802-5374.vector.pbf"],
- [2, "INFO", "HttpRequest"]
- ]
- }
-}
diff --git a/test/fixtures/styles/road-width.style.json b/test/fixtures/styles/road-width.style.json
deleted file mode 100644
index 76d7b5258c..0000000000
--- a/test/fixtures/styles/road-width.style.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "version": 3,
- "sources": {
- "mapbox": {
- "type": "vector",
- "url": "tiles/{z}-{x}-{y}.vector.pbf",
- "tileSize": 512,
- "maxZoom": 14
- }
- },
- "layers": [
- {
- "id": "background",
- "type": "background",
- "style": {
- "background-color": "white"
- }
- },
- {
- "id": "road",
- "source": "mapbox",
- "source-layer": "road",
- "type": "line",
- "style": {
- "line-width": {
- "stops": [[13, 0], [13.999, 0], [14, 4], [14.1, 10], [14.2, 20]]
- }
- }
- }
- ]
-}
diff --git a/test/fixtures/styles/road-width/z13.9.expected.png b/test/fixtures/styles/road-width/z13.9.expected.png
deleted file mode 100644
index e65d3339d6..0000000000
--- a/test/fixtures/styles/road-width/z13.9.expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/styles/road-width/z14.0.expected.png b/test/fixtures/styles/road-width/z14.0.expected.png
deleted file mode 100644
index 01444c6f87..0000000000
--- a/test/fixtures/styles/road-width/z14.0.expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/styles/road-width/z14.1.expected.png b/test/fixtures/styles/road-width/z14.1.expected.png
deleted file mode 100644
index 3a28f3c4de..0000000000
--- a/test/fixtures/styles/road-width/z14.1.expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/styles/road-width/z14.2.expected.png b/test/fixtures/styles/road-width/z14.2.expected.png
deleted file mode 100644
index 8cd62453cb..0000000000
--- a/test/fixtures/styles/road-width/z14.2.expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/styles/world-aa.info.json b/test/fixtures/styles/world-aa.info.json
deleted file mode 100644
index e5e123dcef..0000000000
--- a/test/fixtures/styles/world-aa.info.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "plain": {
- "center": [0, 0],
- "zoom": 0,
- "log": [
- [ 1, "INFO", "HttpRequest", 200, "tiles/0-0-0.vector.pbf" ]
- ]
- }
-}
diff --git a/test/fixtures/styles/world-aa.style.json b/test/fixtures/styles/world-aa.style.json
deleted file mode 100644
index 3165ec5b9f..0000000000
--- a/test/fixtures/styles/world-aa.style.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "version": 3,
- "sources": {
- "mapbox": {
- "type": "vector",
- "url": "tiles/{z}-{x}-{y}.vector.pbf",
- "tileSize": 512,
- "maxZoom": 14
- }
- },
- "layers": [
- {
- "id": "background",
- "type": "background",
- "style": {
- "background-color": "red"
- }
- },
- {
- "id": "water",
- "source": "mapbox",
- "source-layer": "water",
- "type": "fill",
- "style": {
- "fill-color": "blue"
- }
- }
- ]
-}
diff --git a/test/fixtures/styles/world-aa/plain.expected.png b/test/fixtures/styles/world-aa/plain.expected.png
deleted file mode 100644
index d34c46a6c9..0000000000
--- a/test/fixtures/styles/world-aa/plain.expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/styles/world-no-aa.info.json b/test/fixtures/styles/world-no-aa.info.json
deleted file mode 100644
index f5bc0c1462..0000000000
--- a/test/fixtures/styles/world-no-aa.info.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "plain": {
- "center": [0, 0],
- "zoom": 0,
- "log": [
- [1, "INFO", "HttpRequest", 200, "tiles/0-0-0.vector.pbf"],
- [1, "INFO", "HttpRequest"]
- ]
- }
-}
diff --git a/test/fixtures/styles/world-no-aa.style.json b/test/fixtures/styles/world-no-aa.style.json
deleted file mode 100644
index c37774b662..0000000000
--- a/test/fixtures/styles/world-no-aa.style.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "version": 3,
- "sources": {
- "mapbox": {
- "type": "vector",
- "url": "tiles/{z}-{x}-{y}.vector.pbf",
- "tileSize": 512,
- "maxZoom": 14
- }
- },
- "layers": [
- {
- "id": "background",
- "type": "background",
- "style": {
- "background-color": "red"
- }
- },
- {
- "id": "water",
- "source": "mapbox",
- "source-layer": "water",
- "type": "fill",
- "style": {
- "fill-color": "blue",
- "fill-antialias": false
- }
- }
- ]
-}
diff --git a/test/fixtures/styles/world-no-aa/plain.expected.png b/test/fixtures/styles/world-no-aa/plain.expected.png
deleted file mode 100644
index 34e984cce3..0000000000
--- a/test/fixtures/styles/world-no-aa/plain.expected.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/tiles/0-0-0.vector.pbf b/test/fixtures/tiles/0-0-0.vector.pbf
deleted file mode 100644
index 5eee529357..0000000000
--- a/test/fixtures/tiles/0-0-0.vector.pbf
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/tiles/13-4401-2687.vector.pbf b/test/fixtures/tiles/13-4401-2687.vector.pbf
deleted file mode 100644
index f2165b8fe5..0000000000
--- a/test/fixtures/tiles/13-4401-2687.vector.pbf
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/tiles/14-8802-5374.vector.pbf b/test/fixtures/tiles/14-8802-5374.vector.pbf
deleted file mode 100644
index a2277ea1ff..0000000000
--- a/test/fixtures/tiles/14-8802-5374.vector.pbf
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/tiles/14-8802-5375.vector.pbf b/test/fixtures/tiles/14-8802-5375.vector.pbf
deleted file mode 100644
index 0804e8736c..0000000000
--- a/test/fixtures/tiles/14-8802-5375.vector.pbf
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/tiles/14-8803-5374.vector.pbf b/test/fixtures/tiles/14-8803-5374.vector.pbf
deleted file mode 100644
index 4e66bead09..0000000000
--- a/test/fixtures/tiles/14-8803-5374.vector.pbf
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/tiles/14-8803-5375.vector.pbf b/test/fixtures/tiles/14-8803-5375.vector.pbf
deleted file mode 100644
index f940be5992..0000000000
--- a/test/fixtures/tiles/14-8803-5375.vector.pbf
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/tiles/2-1-1.vector.pbf b/test/fixtures/tiles/2-1-1.vector.pbf
deleted file mode 100644
index 00a5435b7e..0000000000
--- a/test/fixtures/tiles/2-1-1.vector.pbf
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/tiles/2-1-2.vector.pbf b/test/fixtures/tiles/2-1-2.vector.pbf
deleted file mode 100644
index 4d26226c57..0000000000
--- a/test/fixtures/tiles/2-1-2.vector.pbf
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/tiles/2-2-1.vector.pbf b/test/fixtures/tiles/2-2-1.vector.pbf
deleted file mode 100644
index a92e85b60e..0000000000
--- a/test/fixtures/tiles/2-2-1.vector.pbf
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/tiles/2-2-2.vector.pbf b/test/fixtures/tiles/2-2-2.vector.pbf
deleted file mode 100644
index 209014708f..0000000000
--- a/test/fixtures/tiles/2-2-2.vector.pbf
+++ /dev/null
Binary files differ
diff --git a/test/headless.cpp b/test/headless.cpp
index 18a17d6bdf..bd84e37681 100644
--- a/test/headless.cpp
+++ b/test/headless.cpp
@@ -6,6 +6,8 @@
#include <mbgl/util/std.hpp>
#include <rapidjson/document.h>
+#include <rapidjson/writer.h>
+#include <rapidjson/stringbuffer.h>
#include "../common/headless_view.hpp"
@@ -16,24 +18,47 @@
const std::string base_directory = []{
std::string fn = __FILE__;
fn.erase(fn.find_last_of("/"));
- return fn + "/fixtures/styles";
+ return fn + "/../node_modules/mapbox-gl-test-suite/";
}();
class HeadlessTest : public ::testing::TestWithParam<std::string> {};
+void ResolveLocalURL(rapidjson::Value& value, rapidjson::Document& doc) {
+ std::string str { value.GetString(), value.GetStringLength() };
+ str.replace(0, 8, base_directory); // local://
+ value.SetString(str.c_str(), str.length(), doc.GetAllocator());
+}
+
TEST_P(HeadlessTest, render) {
using namespace mbgl;
const std::string &base = GetParam();
- const std::string style = util::read_file(base_directory + "/" + base + ".style.json");
- const std::string info = util::read_file(base_directory + "/" + base + ".info.json");
+ std::string style = util::read_file(base_directory + "tests/" + base + "/style.json");
+ std::string info = util::read_file(base_directory + "tests/" + base + "/info.json");
+
+ // Parse style.
+ rapidjson::Document styleDoc;
+ styleDoc.Parse<0>((const char *const)style.c_str());
+ ASSERT_EQ(false, styleDoc.HasParseError());
+ ASSERT_EQ(true, styleDoc.IsObject());
+
+ if (styleDoc.HasMember("sprite")) {
+ ResolveLocalURL(styleDoc["sprite"], styleDoc);
+ }
+
+ ResolveLocalURL(styleDoc["sources"]["mapbox"]["url"], styleDoc);
+
+ rapidjson::StringBuffer buffer;
+ rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+ styleDoc.Accept(writer);
+ style = buffer.GetString();
// Parse settings.
- rapidjson::Document doc;
- doc.Parse<0>((const char *const)info.c_str());
- ASSERT_EQ(false, doc.HasParseError());
- ASSERT_EQ(true, doc.IsObject());
+ rapidjson::Document infoDoc;
+ infoDoc.Parse<0>((const char *const)info.c_str());
+ ASSERT_EQ(false, infoDoc.HasParseError());
+ ASSERT_EQ(true, infoDoc.IsObject());
Log::Set<FixtureLogBackend>();
@@ -41,15 +66,13 @@ TEST_P(HeadlessTest, render) {
HeadlessView view;
Map map(view);
- for (auto it = doc.MemberBegin(), end = doc.MemberEnd(); it != end; it++) {
- const FixtureLogBackend &log = Log::Set<FixtureLogBackend>();
-
+ for (auto it = infoDoc.MemberBegin(), end = infoDoc.MemberEnd(); it != end; it++) {
const std::string name { it->name.GetString(), it->name.GetStringLength() };
const rapidjson::Value &value = it->value;
ASSERT_EQ(true, value.IsObject());
if (value.HasMember("center")) ASSERT_EQ(true, value["center"].IsArray());
- const std::string actual_image = base_directory + "/" + base + "/" + name + ".actual.png";
+ const std::string actual_image = base_directory + "tests/" + base + "/" + name + "/actual.png";
const double zoom = value.HasMember("zoom") ? value["zoom"].GetDouble() : 0;
const double bearing = value.HasMember("bearing") ? value["bearing"].GetDouble() : 0;
@@ -74,7 +97,7 @@ TEST_P(HeadlessTest, render) {
view.resize(width, height);
map.resize(width, height);
map.setLonLatZoom(longitude, latitude, zoom);
- map.setAngle(bearing);
+ map.setBearing(bearing);
// Run the loop. It will terminate when we don't have any further listeners.
map.run();
@@ -84,73 +107,22 @@ TEST_P(HeadlessTest, render) {
const std::string image = util::compress_png(width, height, pixels.get(), true);
util::write_file(actual_image, image);
-
- if (value.HasMember("log")) {
- const rapidjson::Value &js_log = value["log"];
- ASSERT_EQ(true, js_log.IsArray());
- for (rapidjson::SizeType i = 0; i < js_log.Size(); i++) {
- const rapidjson::Value &js_entry = js_log[i];
- ASSERT_EQ(true, js_entry.IsArray());
- if (js_entry.Size() == 5) {
- const uint32_t count = js_entry[rapidjson::SizeType(0)].GetUint();
- const FixtureLogBackend::LogMessage message {
- EventSeverityClass(js_entry[rapidjson::SizeType(1)].GetString()),
- EventClass(js_entry[rapidjson::SizeType(2)].GetString()),
- js_entry[rapidjson::SizeType(3)].GetInt64(),
- js_entry[rapidjson::SizeType(4)].GetString()
- };
- ASSERT_EQ(count, log.count(message)) << "Message: " << message << "Full Log: " << std::endl << log.messages;
- } else if (js_entry.Size() == 4) {
- const uint32_t count = js_entry[rapidjson::SizeType(0)].GetUint();
- if (js_entry[rapidjson::SizeType(3)].IsString()) {
- const FixtureLogBackend::LogMessage message {
- EventSeverityClass(js_entry[rapidjson::SizeType(1)].GetString()),
- EventClass(js_entry[rapidjson::SizeType(2)].GetString()),
- js_entry[rapidjson::SizeType(3)].GetString()
- };
- ASSERT_EQ(count, log.count(message)) << "Message: " << message << "Full Log: " << std::endl << log.messages;
- } else {
- const FixtureLogBackend::LogMessage message {
- EventSeverityClass(js_entry[rapidjson::SizeType(1)].GetString()),
- EventClass(js_entry[rapidjson::SizeType(2)].GetString()),
- js_entry[rapidjson::SizeType(3)].GetInt64()
- };
- ASSERT_EQ(count, log.count(message)) << "Message: " << message << "Full Log: " << std::endl << log.messages;
- }
- } else if (js_entry.Size() == 3) {
- const uint32_t count = js_entry[rapidjson::SizeType(0)].GetUint();
- const FixtureLogBackend::LogMessage message {
- EventSeverityClass(js_entry[rapidjson::SizeType(1)].GetString()),
- EventClass(js_entry[rapidjson::SizeType(2)].GetString())
- };
- ASSERT_EQ(count, log.count(message)) << "Message: " << message << "Full Log: " << std::endl << log.messages;
- } else {
- FAIL();
- }
- }
- }
-
- const auto &unchecked = log.unchecked();
- if (unchecked.size()) {
- std::cerr << "Unchecked Log Messages (" << base << "/" << name << "): " << std::endl << unchecked;
- }
}
}
INSTANTIATE_TEST_CASE_P(Headless, HeadlessTest, ::testing::ValuesIn([] {
std::vector<std::string> names;
- const std::string ending = ".info.json";
- DIR *dir = opendir(base_directory.c_str());
+ DIR *dir = opendir((base_directory + "tests").c_str());
if (dir == nullptr) {
return names;
}
for (dirent *dp = nullptr; (dp = readdir(dir)) != nullptr;) {
const std::string name = dp->d_name;
- if (name.length() >= ending.length() && name.compare(name.length() - ending.length(), ending.length(), ending) == 0) {
- names.push_back(name.substr(0, name.length() - ending.length()));
+ if (name != "." && name != ".." && name != "index.html") {
+ names.push_back(name);
}
}
diff --git a/test/test.gyp b/test/test.gyp
index f91f118080..75ab26a514 100644
--- a/test/test.gyp
+++ b/test/test.gyp
@@ -208,7 +208,7 @@
"dependencies": [
"../deps/gtest/gtest.gyp:gtest",
"../mapboxgl.gyp:mapboxgl",
- "../mapboxgl.gyp:copy_default_stylesheet",
+ '../mapboxgl.gyp:bundle_styles',
"link_gl",
]
},