From 139b9e7a60acadadaef80eea1cd07811e00f2cfb Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 24 Nov 2015 17:24:20 -0800 Subject: [PATCH 01/63] refs #352: catalog (hardcoded: POI) features on tile parse --- src/mbgl/annotation/point_annotation_impl.hpp | 1 + src/mbgl/map/tile_worker.cpp | 47 +++++++++++++++++++ src/mbgl/map/tile_worker.hpp | 30 ++++++++++++ src/mbgl/text/collision_tile.cpp | 2 +- src/mbgl/text/collision_tile.hpp | 14 +++--- 5 files changed, 86 insertions(+), 8 deletions(-) diff --git a/src/mbgl/annotation/point_annotation_impl.hpp b/src/mbgl/annotation/point_annotation_impl.hpp index 2977caf5773..4522f0514a3 100644 --- a/src/mbgl/annotation/point_annotation_impl.hpp +++ b/src/mbgl/annotation/point_annotation_impl.hpp @@ -31,6 +31,7 @@ // Make Boost Geometry aware of our LatLng type BOOST_GEOMETRY_REGISTER_POINT_2D(mbgl::LatLng, double, boost::geometry::cs::cartesian, longitude, latitude) BOOST_GEOMETRY_REGISTER_BOX(mbgl::LatLngBounds, mbgl::LatLng, sw, ne) +// FIXME like Collision/Feature namespace mbgl { diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 9dc0698db7c..e243d5945f6 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -140,6 +140,53 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr // We cannot parse this bucket yet. Instead, we're saving it for later. pending.emplace_back(layer, std::move(bucket)); } else { + + // catalog features for interactivity + // + // if (layer.interactive) { ... + // + // also, we don't get here for raster buckets, since they don't have layers + + if (!partialParse && layer.id.substr(0, 3) == "poi" && bucket->hasData()) { + result.featureTree.clear(); + for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { + const auto feature = geometryLayer->getFeature(i); + const auto geometries = feature->getGeometries(); + for (std::size_t j = 0; j < geometries.size(); j++) { + FeatureBox featureBox {{ 4096 + 64, 4096 + 64 }, { -64, -64 }}; + const auto geometry = geometries.at(j); + for (std::size_t k = 0; k < geometry.size(); k++) { + const auto point = geometry.at(k); + const auto min = featureBox.min_corner(); + const auto max = featureBox.max_corner(); + if (point.x < min.get<0>()) { + featureBox.min_corner().set<0>(point.x); + } + if (point.y < min.get<1>()) { + featureBox.min_corner().set<1>(point.y); + } + if (point.x > max.get<0>()) { + featureBox.max_corner().set<0>(point.x); + } + if (point.y > max.get<1>()) { + featureBox.max_corner().set<1>(point.y); + } + std::string name = "(unknown)"; + const auto maybe_name = feature->getValue("name_en"); + if (maybe_name.get().is()) { + name = maybe_name.get().get(); + } + name = layer.id + " - " + name; + result.featureTree.insert(std::make_pair(featureBox, layer.id + name)); +// printf("added %s\n", name.c_str()); + } + } + } + if (result.featureTree.size()) { +// printf("feature tree for %i,%i,%i [%s] has %lu members\n", id.z, id.x, id.y, layer.id.c_str(), result.featureTree.size()); + } + } + insertBucket(layer.bucketName(), std::move(bucket)); } } diff --git a/src/mbgl/map/tile_worker.hpp b/src/mbgl/map/tile_worker.hpp index ee94f756ed0..82b7fe96074 100644 --- a/src/mbgl/map/tile_worker.hpp +++ b/src/mbgl/map/tile_worker.hpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include #include #include @@ -14,6 +16,25 @@ #include #include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wshadow" +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#endif +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wdeprecated-register" +#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#include +#include +#include +#include +#pragma GCC diagnostic pop + namespace mbgl { class CollisionTile; @@ -22,12 +43,21 @@ class Style; class Bucket; class StyleLayer; +namespace FeatureBG = boost::geometry; +namespace FeatureBGM = FeatureBG::model; +namespace FeatureBGI = FeatureBG::index; +typedef FeatureBGM::point FeaturePoint; +typedef FeatureBGM::box FeatureBox; +typedef std::pair Feature; +typedef FeatureBGI::rtree> FeatureTree; + // We're using this class to shuttle the resulting buckets from the worker thread to the MapContext // thread. This class is movable-only because the vector contains movable-only value elements. class TileParseResultBuckets { public: TileData::State state = TileData::State::invalid; std::unordered_map> buckets; + FeatureTree featureTree; }; using TileParseResult = mapbox::util::variant blockingBoxes; - tree.query(bgi::intersects(getTreeBox(anchor, box)), std::back_inserter(blockingBoxes)); + tree.query(CollisionBGI::intersects(getTreeBox(anchor, box)), std::back_inserter(blockingBoxes)); for (auto& blockingTreeBox : blockingBoxes) { const auto& blocking = std::get<1>(blockingTreeBox); diff --git a/src/mbgl/text/collision_tile.hpp b/src/mbgl/text/collision_tile.hpp index edd5eb61a0e..64577a06b97 100644 --- a/src/mbgl/text/collision_tile.hpp +++ b/src/mbgl/text/collision_tile.hpp @@ -25,13 +25,13 @@ namespace mbgl { -namespace bg = boost::geometry; -namespace bgm = bg::model; -namespace bgi = bg::index; -typedef bgm::point CollisionPoint; -typedef bgm::box Box; +namespace CollisionBG = boost::geometry; +namespace CollisionBGM = CollisionBG::model; +namespace CollisionBGI = CollisionBG::index; +typedef CollisionBGM::point CollisionPoint; +typedef CollisionBGM::box Box; typedef std::pair CollisionTreeBox; -typedef bgi::rtree> Tree; +typedef CollisionBGI::rtree> CollisionTree; class CollisionTile { public: @@ -49,7 +49,7 @@ class CollisionTile { private: Box getTreeBox(const vec2& anchor, const CollisionBox& box); - Tree tree; + CollisionTree tree; std::array rotationMatrix; }; From b1ad1b6bb4b8b1bc7fbd276b6cc14dd53cc0bdce Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 25 Nov 2015 18:52:45 -0800 Subject: [PATCH 02/63] fix crasher --- src/mbgl/map/tile_worker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index e243d5945f6..81942efd9c3 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -173,7 +173,7 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr } std::string name = "(unknown)"; const auto maybe_name = feature->getValue("name_en"); - if (maybe_name.get().is()) { + if (maybe_name && maybe_name.get().is()) { name = maybe_name.get().get(); } name = layer.id + " - " + name; From 8a4f068a9b8e1335402b2a763a99ed6048731223 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 25 Nov 2015 18:53:51 -0800 Subject: [PATCH 03/63] refs #352: current state of feature querying --- include/mbgl/ios/MGLMapView.h | 2 + include/mbgl/map/map.hpp | 3 ++ ios/app/MBXViewController.mm | 16 ++++--- platform/ios/MGLMapView.mm | 5 ++ src/mbgl/map/map.cpp | 7 +++ src/mbgl/map/map_context.cpp | 78 +++++++++++++++++++++++++++++++ src/mbgl/map/map_context.hpp | 3 ++ src/mbgl/map/tile_data.hpp | 29 ++++++++++++ src/mbgl/map/tile_worker.cpp | 6 +-- src/mbgl/map/vector_tile_data.cpp | 3 ++ 10 files changed, 142 insertions(+), 10 deletions(-) diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index 83ef395cf9e..0b86f4249e8 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -371,6 +371,8 @@ IB_DESIGNABLE /** Whether the map view should display a heading calibration alert when necessary. The default value is `YES`. */ @property (nonatomic, assign) BOOL displayHeadingCalibration; +- (void)featuresAt:(CGPoint)point; + #pragma mark - Debugging /** @name Debugging */ diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index c190088088b..07eabaddca2 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -159,6 +159,9 @@ class Map : private util::noncopyable { LatLngBounds getBoundsForAnnotations(const AnnotationIDs&); double getTopOffsetPixelsForAnnotationSymbol(const std::string&); + // Features + std::vector featuresAt(const PrecisionPoint) const; + // Sprites void setSprite(const std::string&, std::shared_ptr); void removeSprite(const std::string&); diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm index 6380406eec7..f045f718b72 100644 --- a/ios/app/MBXViewController.mm +++ b/ios/app/MBXViewController.mm @@ -296,13 +296,15 @@ - (void)handleLongPress:(UILongPressGestureRecognizer *)longPress { if (longPress.state == UIGestureRecognizerStateBegan) { - MGLPointAnnotation *point = [MGLPointAnnotation new]; - point.coordinate = [self.mapView convertPoint:[longPress locationInView:longPress.view] - toCoordinateFromView:self.mapView]; - point.title = @"Dropped Marker"; - point.subtitle = [NSString stringWithFormat:@"lat: %.3f, lon: %.3f", point.coordinate.latitude, point.coordinate.longitude]; - [self.mapView addAnnotation:point]; - [self.mapView selectAnnotation:point animated:YES]; +// MGLPointAnnotation *point = [MGLPointAnnotation new]; +// point.coordinate = [self.mapView convertPoint:[longPress locationInView:longPress.view] +// toCoordinateFromView:self.mapView]; +// point.title = @"Dropped Marker"; +// point.subtitle = [NSString stringWithFormat:@"lat: %.3f, lon: %.3f", point.coordinate.latitude, point.coordinate.longitude]; +// [self.mapView addAnnotation:point]; +// [self.mapView selectAnnotation:point animated:YES]; + + [self.mapView featuresAt:[longPress locationInView:longPress.view]]; } } diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index db5ef1ee469..dc4ac45a265 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -383,6 +383,11 @@ - (void)commonInit }]; } +- (void)featuresAt:(CGPoint)point +{ + _mbglMap->featuresAt(mbgl::PrecisionPoint(point.x, point.y)); +} + - (void)createGLView { if (_context) return; diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 713222fe54b..7fc196f9301 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -407,6 +407,13 @@ LatLngBounds Map::getBoundsForAnnotations(const AnnotationIDs& annotations) { } +#pragma mark - Features + +std::vector Map::featuresAt(const PrecisionPoint point) const { + return context->invokeSync>(&MapContext::featuresAt, point); +} + + #pragma mark - Sprites void Map::setSprite(const std::string& name, std::shared_ptr sprite) { diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index cf06dd06eb2..13974b9e35e 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include @@ -22,9 +23,12 @@ #include #include #include +#include #include +#include + namespace mbgl { MapContext::MapContext(View& view_, FileSource& fileSource, MapData& data_) @@ -277,6 +281,80 @@ double MapContext::getTopOffsetPixelsForAnnotationSymbol(const std::string& symb } } +std::vector MapContext::featuresAt(const PrecisionPoint point) const { + + LatLng p_ = transformState.pointToLatLng(point); + + // figure out tile + // + double sine = std::sin(p_.latitude * M_PI / 180); + double x = p_.longitude / 360 + 0.5; + double y = 0.5 - 0.25 * std::log((1 + sine) / (1 - sine)) / M_PI; + + y = y < -1 ? -1 : y > 1 ? 1 : y; + +// PrecisionPoint p(x, y); + + const auto z = floor(transformState.getZoom()); + const auto z2 = powf(2, z); + TileID id(z, floor(x * z2), floor(y * z2), ::fmin(z, 15)); + + // figure out tile coordinate + // + TileCoordinate coordinate = transformState.pointToCoordinate(point); + + // figure out query bounds + // + const auto world_size = util::tileSize * transformState.getScale(); + const auto scale = world_size / z2; + + coordinate.zoomTo(::fmin(id.z, 18)); +// const auto tileCoordinate = vec2(id.x * 4096, id.y * 4096); + + + vec3 position((coordinate.column - id.x) * 4096, (coordinate.row - id.y) * 4096, scale); + + + + + std::vector results; + + printf("=====\n"); + + + + const auto radius = 5 * 4096 / scale; + FeatureBox queryBox = { + { position.x - radius, position.y - radius }, + { position.x + radius, position.y + radius } + }; + + + + + for (const auto& source : style->sources) { + if (source->info.type == SourceType::Vector) { + for (const auto& tile : source->getLoadedTiles()) { + // if (tile->id == coordinate) +// printf("[%s]: %i,%i,%i\n", source->info.source_id.c_str(), tile->id.z, tile->id.x, tile->id.y); + + const auto& tile_data = tile->data; + tile_data->featureTree.query(boost::geometry::index::intersects(queryBox), + boost::make_function_output_iterator([&](const auto& val) { + results.push_back(val.second); + })); + + + } + } + } + +// (void)point; + + return results; + +} + void MapContext::setSourceTileCacheSize(size_t size) { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); if (size != sourceCacheSize) { diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index f4df3aae255..c7b208cfeea 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -51,6 +52,8 @@ class MapContext : public Style::Observer { double getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol); void updateAnnotations(); + std::vector featuresAt(const PrecisionPoint) const; + void setSourceTileCacheSize(size_t size); void onLowMemory(); diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp index 2a5745142d4..562e89deef4 100644 --- a/src/mbgl/map/tile_data.hpp +++ b/src/mbgl/map/tile_data.hpp @@ -11,12 +11,39 @@ #include #include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wshadow" +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#endif +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wdeprecated-register" +#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#include +#include +#include +#include +#pragma GCC diagnostic pop + namespace mbgl { class StyleLayer; class Worker; class DebugBucket; +namespace FeatureBG = boost::geometry; +namespace FeatureBGM = FeatureBG::model; +namespace FeatureBGI = FeatureBG::index; +typedef FeatureBGM::point FeaturePoint; +typedef FeatureBGM::box FeatureBox; +typedef std::pair Feature; +typedef FeatureBGI::rtree> FeatureTree; + class TileData : private util::noncopyable { public: // initial: @@ -98,6 +125,8 @@ class TileData : private util::noncopyable { // Contains the tile ID string for painting debug information. std::unique_ptr debugBucket; + FeatureTree featureTree; + protected: std::atomic state; std::string error; diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 81942efd9c3..6295b372d73 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -147,7 +147,7 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr // // also, we don't get here for raster buckets, since they don't have layers - if (!partialParse && layer.id.substr(0, 3) == "poi" && bucket->hasData()) { + if (!partialParse && /*layer.id.substr(0, 3) == "poi" &&*/ bucket->hasData()) { result.featureTree.clear(); for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { const auto feature = geometryLayer->getFeature(i); @@ -178,12 +178,12 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr } name = layer.id + " - " + name; result.featureTree.insert(std::make_pair(featureBox, layer.id + name)); -// printf("added %s\n", name.c_str()); + printf("added %s\n", name.c_str()); } } } if (result.featureTree.size()) { -// printf("feature tree for %i,%i,%i [%s] has %lu members\n", id.z, id.x, id.y, layer.id.c_str(), result.featureTree.size()); + printf("feature tree for %i,%i,%i [%s] has %lu members\n", id.z, id.x, id.y, layer.id.c_str(), result.featureTree.size()); } } diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index 28be9627aec..54ca4507af4 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -72,6 +72,9 @@ VectorTileData::VectorTileData(const TileID& id_, // existing buckets in case we got a refresh parse. buckets = std::move(resultBuckets.buckets); +// featureTree.clear(); + featureTree.insert(resultBuckets.featureTree.begin(), resultBuckets.featureTree.end()); + // The target configuration could have changed since we started placement. In this case, // we're starting another placement run. if (placedConfig != targetConfig) { From 5de3f996557cbf0a400df61af4cac2d988f45731 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Thu, 26 Nov 2015 10:37:04 -0800 Subject: [PATCH 04/63] refs #352: remove unused forward declaration --- src/mbgl/map/tile.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mbgl/map/tile.hpp b/src/mbgl/map/tile.hpp index 996433b5d9b..e4542b84b13 100644 --- a/src/mbgl/map/tile.hpp +++ b/src/mbgl/map/tile.hpp @@ -10,7 +10,6 @@ namespace mbgl { class TileData; -struct box; class Tile : private util::noncopyable { public: From 3f89f50527bb8f74dbb0ba55fbfe27e1a3c0a453 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Thu, 26 Nov 2015 10:46:03 -0800 Subject: [PATCH 05/63] refs #352: parse interactive layer property from style --- src/mbgl/map/tile_worker.cpp | 2 +- src/mbgl/style/style_layer.cpp | 1 + src/mbgl/style/style_layer.hpp | 1 + src/mbgl/style/style_parser.cpp | 9 +++++++++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 6295b372d73..cc608040bcd 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -147,7 +147,7 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr // // also, we don't get here for raster buckets, since they don't have layers - if (!partialParse && /*layer.id.substr(0, 3) == "poi" &&*/ bucket->hasData()) { + if (!partialParse && /*layer.interactive && layer.id.substr(0, 3) == "poi" &&*/ bucket->hasData()) { result.featureTree.clear(); for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { const auto feature = geometryLayer->getFeature(i); diff --git a/src/mbgl/style/style_layer.cpp b/src/mbgl/style/style_layer.cpp index 1b3d1a3c34c..a7a5a9a0c66 100644 --- a/src/mbgl/style/style_layer.cpp +++ b/src/mbgl/style/style_layer.cpp @@ -43,6 +43,7 @@ void StyleLayer::copy(const StyleLayer& src) { minZoom = src.minZoom; maxZoom = src.maxZoom; visibility = src.visibility; + interactive = src.interactive; } } diff --git a/src/mbgl/style/style_layer.hpp b/src/mbgl/style/style_layer.hpp index a1a0389fbe6..82c08b6b27d 100644 --- a/src/mbgl/style/style_layer.hpp +++ b/src/mbgl/style/style_layer.hpp @@ -56,6 +56,7 @@ class StyleLayer : public util::noncopyable { float minZoom = -std::numeric_limits::infinity(); float maxZoom = std::numeric_limits::infinity(); VisibilityType visibility = VisibilityType::Visible; + bool interactive; protected: // Stores what render passes this layer is currently enabled for. This depends on the diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp index dc14827dc6d..d8a4e1422e1 100644 --- a/src/mbgl/style/style_parser.cpp +++ b/src/mbgl/style/style_parser.cpp @@ -263,6 +263,15 @@ void StyleParser::parseLayer(const std::string& id, const JSVal& value, util::pt } } + if (value.HasMember("interactive")) { + const JSVal& interactive = value["interactive"]; + if (interactive.IsBool()) { + layer->interactive = interactive.GetBool(); + } else { + Log::Warning(Event::ParseStyle, "interactive of layer %s must be a boolean", layer->id.c_str()); + } + } + if (value.HasMember("layout")) { parseVisibility(*layer, value["layout"]); layer->parseLayout(value["layout"]); From e4f1339a4fbe479a0a914077350daaf8e6ab7563 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 30 Nov 2015 17:23:22 -0800 Subject: [PATCH 06/63] refs #352: further work on featuresAt - return layer name as string + feature properties dictionary - abstract r-tree & boost stuff into common header - more typedefs for clarity - more logging of parse box & interaction point - move interactivity parsing ahead of any bucket type branching --- include/mbgl/map/map.hpp | 3 +- include/mbgl/util/interactive_features.hpp | 43 ++++++++++ src/mbgl/map/map.cpp | 4 +- src/mbgl/map/map_context.cpp | 34 +++++--- src/mbgl/map/map_context.hpp | 2 +- src/mbgl/map/tile_data.hpp | 29 +------ src/mbgl/map/tile_worker.cpp | 93 +++++++++++----------- src/mbgl/map/tile_worker.hpp | 29 ------- 8 files changed, 120 insertions(+), 117 deletions(-) create mode 100644 include/mbgl/util/interactive_features.hpp diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 07eabaddca2..61c83f3efca 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -160,7 +161,7 @@ class Map : private util::noncopyable { double getTopOffsetPixelsForAnnotationSymbol(const std::string&); // Features - std::vector featuresAt(const PrecisionPoint) const; + std::vector> featuresAt(const PrecisionPoint) const; // Sprites void setSprite(const std::string&, std::shared_ptr); diff --git a/include/mbgl/util/interactive_features.hpp b/include/mbgl/util/interactive_features.hpp new file mode 100644 index 00000000000..a3ba1cd52a2 --- /dev/null +++ b/include/mbgl/util/interactive_features.hpp @@ -0,0 +1,43 @@ +#ifndef MBGL_UTIL_INTERACTIVE_FEATURES +#define MBGL_UTIL_INTERACTIVE_FEATURES + +#include +#include + +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wshadow" +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#endif +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wdeprecated-register" +#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#include +#include +#include +#include +#pragma GCC diagnostic pop + +namespace mbgl { + +namespace FeatureBG = boost::geometry; +namespace FeatureBGM = FeatureBG::model; +namespace FeatureBGI = FeatureBG::index; +typedef FeatureBGM::point FeaturePoint; +typedef FeatureBGM::box FeatureBox; +typedef mapbox::util::variant FeaturePropertyValue; +typedef std::map> FeatureProperties; +typedef std::tuple Feature; // box, layer, properties +typedef FeatureBGI::rtree> FeatureTree; + +} // namespace mbgl + +#endif diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 7fc196f9301..09347402e30 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -409,8 +409,8 @@ LatLngBounds Map::getBoundsForAnnotations(const AnnotationIDs& annotations) { #pragma mark - Features -std::vector Map::featuresAt(const PrecisionPoint point) const { - return context->invokeSync>(&MapContext::featuresAt, point); +std::vector> Map::featuresAt(const PrecisionPoint point) const { + return context->invokeSync>>(&MapContext::featuresAt, point); } diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 13974b9e35e..d47f17ecc47 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -281,7 +281,7 @@ double MapContext::getTopOffsetPixelsForAnnotationSymbol(const std::string& symb } } -std::vector MapContext::featuresAt(const PrecisionPoint point) const { +std::vector> MapContext::featuresAt(const PrecisionPoint point) const { LatLng p_ = transformState.pointToLatLng(point); @@ -301,29 +301,35 @@ std::vector MapContext::featuresAt(const PrecisionPoint point) cons // figure out tile coordinate // - TileCoordinate coordinate = transformState.pointToCoordinate(point); +// TileCoordinate coordinate = transformState.pointToCoordinate(point); // figure out query bounds // const auto world_size = util::tileSize * transformState.getScale(); const auto scale = world_size / z2; - coordinate.zoomTo(::fmin(id.z, 18)); -// const auto tileCoordinate = vec2(id.x * 4096, id.y * 4096); +// coordinate.zoomTo(::fmin(id.z, 18)); +// coordinate.column /= id.overscaling; +// coordinate.row /= id.overscaling; +// coordinate.row = 4096 - coordinate.row; - vec3 position((coordinate.column - id.x) * 4096, (coordinate.row - id.y) * 4096, scale); + vec2 coordinate(x * z2, y * z2); + vec3 position((coordinate.x - id.x) * 4096, (coordinate.y - id.y) * 4096, scale); - std::vector results; - printf("=====\n"); + std::vector> results; - const auto radius = 5 * 4096 / scale; + printf("===== query: %i, %i\n", position.x, position.y); + + + + const auto radius = 50 * 4096 / scale; FeatureBox queryBox = { { position.x - radius, position.y - radius }, { position.x + radius, position.y + radius } @@ -341,8 +347,16 @@ std::vector MapContext::featuresAt(const PrecisionPoint point) cons const auto& tile_data = tile->data; tile_data->featureTree.query(boost::geometry::index::intersects(queryBox), boost::make_function_output_iterator([&](const auto& val) { - results.push_back(val.second); - })); + const std::string layer_id = std::get<1>(val); + const FeatureProperties feature_properties = std::get<2>(val); + + const auto result = std::make_pair(layer_id, feature_properties); + + printf("found feature in %s\n", layer_id.c_str()); + + + results.push_back(result); + })); } diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index c7b208cfeea..5aecc59de94 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -52,7 +52,7 @@ class MapContext : public Style::Observer { double getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol); void updateAnnotations(); - std::vector featuresAt(const PrecisionPoint) const; + std::vector> featuresAt(const PrecisionPoint) const; void setSourceTileCacheSize(size_t size); void onLowMemory(); diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp index 562e89deef4..4d1604f5676 100644 --- a/src/mbgl/map/tile_data.hpp +++ b/src/mbgl/map/tile_data.hpp @@ -5,45 +5,18 @@ #include #include #include +#include #include #include #include #include -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wshadow" -#ifdef __clang__ -#pragma GCC diagnostic ignored "-Wunknown-pragmas" -#endif -#pragma GCC diagnostic ignored "-Wpragmas" -#pragma GCC diagnostic ignored "-Wdeprecated-register" -#pragma GCC diagnostic ignored "-Wshorten-64-to-32" -#pragma GCC diagnostic ignored "-Wunused-local-typedefs" -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#include -#include -#include -#include -#pragma GCC diagnostic pop - namespace mbgl { -class StyleLayer; class Worker; class DebugBucket; -namespace FeatureBG = boost::geometry; -namespace FeatureBGM = FeatureBG::model; -namespace FeatureBGI = FeatureBG::index; -typedef FeatureBGM::point FeaturePoint; -typedef FeatureBGM::box FeatureBox; -typedef std::pair Feature; -typedef FeatureBGI::rtree> FeatureTree; - class TileData : private util::noncopyable { public: // initial: diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index cc608040bcd..9d43949269b 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -10,6 +10,7 @@ #include #include #include +#include using namespace mbgl; @@ -136,57 +137,57 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr std::unique_ptr bucket = layer.createBucket(parameters); - if (layer.type == StyleLayerType::Symbol && partialParse) { - // We cannot parse this bucket yet. Instead, we're saving it for later. - pending.emplace_back(layer, std::move(bucket)); - } else { - - // catalog features for interactivity - // - // if (layer.interactive) { ... - // - // also, we don't get here for raster buckets, since they don't have layers - - if (!partialParse && /*layer.interactive && layer.id.substr(0, 3) == "poi" &&*/ bucket->hasData()) { - result.featureTree.clear(); - for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { - const auto feature = geometryLayer->getFeature(i); - const auto geometries = feature->getGeometries(); - for (std::size_t j = 0; j < geometries.size(); j++) { - FeatureBox featureBox {{ 4096 + 64, 4096 + 64 }, { -64, -64 }}; - const auto geometry = geometries.at(j); - for (std::size_t k = 0; k < geometry.size(); k++) { - const auto point = geometry.at(k); - const auto min = featureBox.min_corner(); - const auto max = featureBox.max_corner(); - if (point.x < min.get<0>()) { - featureBox.min_corner().set<0>(point.x); - } - if (point.y < min.get<1>()) { - featureBox.min_corner().set<1>(point.y); - } - if (point.x > max.get<0>()) { - featureBox.max_corner().set<0>(point.x); - } - if (point.y > max.get<1>()) { - featureBox.max_corner().set<1>(point.y); - } - std::string name = "(unknown)"; - const auto maybe_name = feature->getValue("name_en"); - if (maybe_name && maybe_name.get().is()) { - name = maybe_name.get().get(); - } - name = layer.id + " - " + name; - result.featureTree.insert(std::make_pair(featureBox, layer.id + name)); - printf("added %s\n", name.c_str()); + if (/*layer.interactive &&*/ layer.id.substr(0, 3) == "poi" && bucket->hasData()) { +// result.featureTree.clear(); + printf("tile %i,%i/%i\n", id.z, id.x, id.y); + for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { + const auto feature = geometryLayer->getFeature(i); + const auto geometries = feature->getGeometries(); + for (std::size_t j = 0; j < geometries.size(); j++) { + FeatureBox featureBox {{ 4096, 4096 }, { 0, 0 }}; + const auto geometry = geometries.at(j); + for (std::size_t k = 0; k < geometry.size(); k++) { + auto point = geometry.at(k); + point.x /= id.overscaling; + point.y /= id.overscaling; + if (point.x < 0 || point.x > 4096 || point.y < 0 || point.y > 4096) continue; + const auto min = featureBox.min_corner(); + const auto max = featureBox.max_corner(); + if (point.x < min.get<0>()) { + featureBox.min_corner().set<0>(::fmax(point.x, 0)); + } + if (point.y < min.get<1>()) { + featureBox.min_corner().set<1>(::fmax(point.y, 0)); + } + if (point.x > max.get<0>()) { + featureBox.max_corner().set<0>(::fmin(point.x, 4096)); + } + if (point.y > max.get<1>()) { + featureBox.max_corner().set<1>(::fmin(point.y, 4096)); } + std::string name = "(unknown)"; + const auto maybe_name = feature->getValue("name_en"); + if (maybe_name && maybe_name.get().is()) { + name = maybe_name.get().get(); + } + name = layer.id + " - " + name; + const FeatureProperties empty_properties; + result.featureTree.insert(std::make_tuple(featureBox, layer.id, empty_properties)); + printf("added %s at %i, %i\n", name.c_str(), point.x, point.y); } } - if (result.featureTree.size()) { - printf("feature tree for %i,%i,%i [%s] has %lu members\n", id.z, id.x, id.y, layer.id.c_str(), result.featureTree.size()); - } } + if (result.featureTree.size()) { + printf("feature tree for %i,%i,%i [%s] has %lu members\n", id.z, id.x, id.y, layer.id.c_str(), result.featureTree.size()); + const auto bounds = result.featureTree.bounds(); + printf("box: %i, %i to %i, %i\n", bounds.min_corner().get<0>(), bounds.min_corner().get<1>(), bounds.max_corner().get<0>(), bounds.max_corner().get<1>()); + } + } + if (layer.type == StyleLayerType::Symbol && partialParse) { + // We cannot parse this bucket yet. Instead, we're saving it for later. + pending.emplace_back(layer, std::move(bucket)); + } else { insertBucket(layer.bucketName(), std::move(bucket)); } } diff --git a/src/mbgl/map/tile_worker.hpp b/src/mbgl/map/tile_worker.hpp index 82b7fe96074..0e48d0b9405 100644 --- a/src/mbgl/map/tile_worker.hpp +++ b/src/mbgl/map/tile_worker.hpp @@ -16,40 +16,11 @@ #include #include -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wshadow" -#ifdef __clang__ -#pragma GCC diagnostic ignored "-Wunknown-pragmas" -#endif -#pragma GCC diagnostic ignored "-Wpragmas" -#pragma GCC diagnostic ignored "-Wdeprecated-register" -#pragma GCC diagnostic ignored "-Wshorten-64-to-32" -#pragma GCC diagnostic ignored "-Wunused-local-typedefs" -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#include -#include -#include -#include -#pragma GCC diagnostic pop - namespace mbgl { class CollisionTile; -class GeometryTile; class Style; class Bucket; -class StyleLayer; - -namespace FeatureBG = boost::geometry; -namespace FeatureBGM = FeatureBG::model; -namespace FeatureBGI = FeatureBG::index; -typedef FeatureBGM::point FeaturePoint; -typedef FeatureBGM::box FeatureBox; -typedef std::pair Feature; -typedef FeatureBGI::rtree> FeatureTree; // We're using this class to shuttle the resulting buckets from the worker thread to the MapContext // thread. This class is movable-only because the vector contains movable-only value elements. From 32cb4327b74b020878f42861ae70560ddf185e15 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 30 Nov 2015 18:01:00 -0800 Subject: [PATCH 07/63] refs #352: debug tap coordinate & fix y flip for core --- platform/ios/MGLMapView.mm | 5 ++++- src/mbgl/map/map_context.cpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index dc4ac45a265..e61c219877d 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -385,7 +385,10 @@ - (void)commonInit - (void)featuresAt:(CGPoint)point { - _mbglMap->featuresAt(mbgl::PrecisionPoint(point.x, point.y)); + NSLog(@"iOS: %f, %f", [self convertPoint:point toCoordinateFromView:self].latitude, [self convertPoint:point toCoordinateFromView:self].longitude); + + // flip y for core + _mbglMap->featuresAt(mbgl::PrecisionPoint(point.x, self.bounds.size.height - point.y)); } - (void)createGLView diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index d47f17ecc47..6c50a4aeb2d 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -285,6 +285,8 @@ std::vector> MapContext::featuresAt(co LatLng p_ = transformState.pointToLatLng(point); + printf("core: %f, %f\n", p_.latitude, p_.longitude); + // figure out tile // double sine = std::sin(p_.latitude * M_PI / 180); From e309fe34af77398e4641c0f83285096f328d22fe Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 30 Nov 2015 18:05:06 -0800 Subject: [PATCH 08/63] refs #352: remove logging --- platform/ios/MGLMapView.mm | 2 +- src/mbgl/map/map_context.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index e61c219877d..f83c3003f21 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -385,7 +385,7 @@ - (void)commonInit - (void)featuresAt:(CGPoint)point { - NSLog(@"iOS: %f, %f", [self convertPoint:point toCoordinateFromView:self].latitude, [self convertPoint:point toCoordinateFromView:self].longitude); +// NSLog(@"iOS: %f, %f", [self convertPoint:point toCoordinateFromView:self].latitude, [self convertPoint:point toCoordinateFromView:self].longitude); // flip y for core _mbglMap->featuresAt(mbgl::PrecisionPoint(point.x, self.bounds.size.height - point.y)); diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 6c50a4aeb2d..9849db46b52 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -285,7 +285,7 @@ std::vector> MapContext::featuresAt(co LatLng p_ = transformState.pointToLatLng(point); - printf("core: %f, %f\n", p_.latitude, p_.longitude); +// printf("core: %f, %f\n", p_.latitude, p_.longitude); // figure out tile // From 7515847f63d27c305fe6a9f8856611512f52ce36 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 30 Nov 2015 18:18:35 -0800 Subject: [PATCH 09/63] refs #352: hook up `name_en` & normal radius (works for <=z15!) now to fix overzooming --- src/mbgl/map/map_context.cpp | 10 ++++++++-- src/mbgl/map/tile_worker.cpp | 8 ++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 9849db46b52..61f11a4dd09 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -331,7 +331,7 @@ std::vector> MapContext::featuresAt(co - const auto radius = 50 * 4096 / scale; + const auto radius = 5 * 4096 / scale; FeatureBox queryBox = { { position.x - radius, position.y - radius }, { position.x + radius, position.y + radius } @@ -354,7 +354,13 @@ std::vector> MapContext::featuresAt(co const auto result = std::make_pair(layer_id, feature_properties); - printf("found feature in %s\n", layer_id.c_str()); + std::string name = "foo"; + const auto maybe_name = feature_properties.at("name_en"); + if (maybe_name && maybe_name.get().is()) { + name = maybe_name.get().get(); + } + + printf("found feature in %s: %s\n", layer_id.c_str(), name.c_str()); results.push_back(result); diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 9d43949269b..2270e2c35de 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -165,14 +165,18 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr if (point.y > max.get<1>()) { featureBox.max_corner().set<1>(::fmin(point.y, 4096)); } + + FeatureProperties properties; + std::string name = "(unknown)"; const auto maybe_name = feature->getValue("name_en"); if (maybe_name && maybe_name.get().is()) { name = maybe_name.get().get(); + properties.emplace("name_en", maybe_name); } name = layer.id + " - " + name; - const FeatureProperties empty_properties; - result.featureTree.insert(std::make_tuple(featureBox, layer.id, empty_properties)); + + result.featureTree.insert(std::make_tuple(featureBox, layer.id, properties)); printf("added %s at %i, %i\n", name.c_str(), point.x, point.y); } } From dc4f5faf557628eb75a8111fe7b828b2934a488d Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 30 Nov 2015 19:29:28 -0800 Subject: [PATCH 10/63] refs #352: naively fetch all feature properties upfront for now --- include/mbgl/util/interactive_features.hpp | 5 ++--- src/mbgl/annotation/annotation_tile.cpp | 4 ++++ src/mbgl/annotation/annotation_tile.hpp | 1 + src/mbgl/map/geometry_tile.hpp | 2 ++ src/mbgl/map/map_context.cpp | 10 ++++------ src/mbgl/map/tile_worker.cpp | 13 +++++++------ src/mbgl/map/vector_tile.cpp | 15 +++++++++++++++ src/mbgl/map/vector_tile.hpp | 2 ++ 8 files changed, 37 insertions(+), 15 deletions(-) diff --git a/include/mbgl/util/interactive_features.hpp b/include/mbgl/util/interactive_features.hpp index a3ba1cd52a2..1da8ec62238 100644 --- a/include/mbgl/util/interactive_features.hpp +++ b/include/mbgl/util/interactive_features.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #pragma GCC diagnostic push @@ -33,8 +33,7 @@ namespace FeatureBGM = FeatureBG::model; namespace FeatureBGI = FeatureBG::index; typedef FeatureBGM::point FeaturePoint; typedef FeatureBGM::box FeatureBox; -typedef mapbox::util::variant FeaturePropertyValue; -typedef std::map> FeatureProperties; +typedef std::unordered_map FeatureProperties; typedef std::tuple Feature; // box, layer, properties typedef FeatureBGI::rtree> FeatureTree; diff --git a/src/mbgl/annotation/annotation_tile.cpp b/src/mbgl/annotation/annotation_tile.cpp index f9ab79e4f42..64879f0b472 100644 --- a/src/mbgl/annotation/annotation_tile.cpp +++ b/src/mbgl/annotation/annotation_tile.cpp @@ -19,6 +19,10 @@ mapbox::util::optional AnnotationTileFeature::getValue(const std::string& return mapbox::util::optional(); } +std::unordered_map AnnotationTileFeature::getAllValues() const { + return std::unordered_map(); +} + util::ptr AnnotationTile::getLayer(const std::string& name) const { auto it = layers.find(name); if (it != layers.end()) { diff --git a/src/mbgl/annotation/annotation_tile.hpp b/src/mbgl/annotation/annotation_tile.hpp index 70c9f7265f9..ac256f5dc64 100644 --- a/src/mbgl/annotation/annotation_tile.hpp +++ b/src/mbgl/annotation/annotation_tile.hpp @@ -16,6 +16,7 @@ class AnnotationTileFeature : public GeometryTileFeature { FeatureType getType() const override { return type; } mapbox::util::optional getValue(const std::string&) const override; + std::unordered_map getAllValues() const override; GeometryCollection getGeometries() const override { return geometries; } const FeatureType type; diff --git a/src/mbgl/map/geometry_tile.hpp b/src/mbgl/map/geometry_tile.hpp index d6717ddc471..a911ab07c07 100644 --- a/src/mbgl/map/geometry_tile.hpp +++ b/src/mbgl/map/geometry_tile.hpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace mbgl { @@ -30,6 +31,7 @@ class GeometryTileFeature : private util::noncopyable { virtual ~GeometryTileFeature() = default; virtual FeatureType getType() const = 0; virtual mapbox::util::optional getValue(const std::string& key) const = 0; + virtual std::unordered_map getAllValues() const = 0; virtual GeometryCollection getGeometries() const = 0; }; diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 61f11a4dd09..cf172614b8c 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -354,14 +354,12 @@ std::vector> MapContext::featuresAt(co const auto result = std::make_pair(layer_id, feature_properties); - std::string name = "foo"; - const auto maybe_name = feature_properties.at("name_en"); - if (maybe_name && maybe_name.get().is()) { - name = maybe_name.get().get(); + std::string properties = ""; + for (const auto property : feature_properties) { + properties = "\n\t" + property.first + ": " + property.second; } - printf("found feature in %s: %s\n", layer_id.c_str(), name.c_str()); - + printf("found feature in %s: %s\n", layer_id.c_str(), properties.c_str()); results.push_back(result); })); diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 2270e2c35de..37748747c01 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -166,14 +166,15 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr featureBox.max_corner().set<1>(::fmin(point.y, 4096)); } - FeatureProperties properties; + // TODO: do this opportunistically + FeatureProperties properties = feature->getAllValues(); std::string name = "(unknown)"; - const auto maybe_name = feature->getValue("name_en"); - if (maybe_name && maybe_name.get().is()) { - name = maybe_name.get().get(); - properties.emplace("name_en", maybe_name); - } +// const auto maybe_name = feature->getValue("name_en"); +// if (maybe_name && maybe_name.get().is()) { +// name = maybe_name.get().get(); +// properties.emplace("name_en", maybe_name); +// } name = layer.id + " - " + name; result.featureTree.insert(std::make_tuple(featureBox, layer.id, properties)); diff --git a/src/mbgl/map/vector_tile.cpp b/src/mbgl/map/vector_tile.cpp index 8b069326152..f427ad7d5e9 100644 --- a/src/mbgl/map/vector_tile.cpp +++ b/src/mbgl/map/vector_tile.cpp @@ -84,6 +84,21 @@ mapbox::util::optional VectorTileFeature::getValue(const std::string& key return mapbox::util::optional(); } +std::unordered_map VectorTileFeature::getAllValues() const { + std::unordered_map values; + + for (const auto key_it : layer.keys) { + const auto& key = key_it.first; + const auto maybe_val = getValue(key); + if (maybe_val && maybe_val.get().is()) { + const auto& val = maybe_val.get().get(); + values.emplace(key, val); + } + } + + return values; +} + GeometryCollection VectorTileFeature::getGeometries() const { pbf data(geometry_pbf); uint8_t cmd = 1; diff --git a/src/mbgl/map/vector_tile.hpp b/src/mbgl/map/vector_tile.hpp index 7c7f96abbde..25174690fe8 100644 --- a/src/mbgl/map/vector_tile.hpp +++ b/src/mbgl/map/vector_tile.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace mbgl { @@ -16,6 +17,7 @@ class VectorTileFeature : public GeometryTileFeature { FeatureType getType() const override { return type; } mapbox::util::optional getValue(const std::string&) const override; + std::unordered_map getAllValues() const override; GeometryCollection getGeometries() const override; private: From 454c0145a50774c0ea52df17f89154bc878dbc34 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 30 Nov 2015 20:06:03 -0800 Subject: [PATCH 11/63] refs #352: clean up adds --- src/mbgl/map/tile_worker.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 37748747c01..1297ed9a73d 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -169,16 +169,8 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr // TODO: do this opportunistically FeatureProperties properties = feature->getAllValues(); - std::string name = "(unknown)"; -// const auto maybe_name = feature->getValue("name_en"); -// if (maybe_name && maybe_name.get().is()) { -// name = maybe_name.get().get(); -// properties.emplace("name_en", maybe_name); -// } - name = layer.id + " - " + name; - result.featureTree.insert(std::make_tuple(featureBox, layer.id, properties)); - printf("added %s at %i, %i\n", name.c_str(), point.x, point.y); + printf("added feature from %s at %i, %i\n", layer.id.c_str(), point.x, point.y); } } } From 8fd4eafd80a4dfcd76c48f24a53d2d9b53f83ac3 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 30 Nov 2015 21:18:07 -0800 Subject: [PATCH 12/63] refs #352: better debug logging --- src/mbgl/map/map_context.cpp | 2 +- src/mbgl/map/tile_worker.cpp | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index cf172614b8c..e0a305d2bdc 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -359,7 +359,7 @@ std::vector> MapContext::featuresAt(co properties = "\n\t" + property.first + ": " + property.second; } - printf("found feature in %s: %s\n", layer_id.c_str(), properties.c_str()); + printf("%s: %s\n", layer_id.c_str(), properties.c_str()); results.push_back(result); })); diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 1297ed9a73d..302e91edf94 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -139,7 +139,7 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr if (/*layer.interactive &&*/ layer.id.substr(0, 3) == "poi" && bucket->hasData()) { // result.featureTree.clear(); - printf("tile %i,%i/%i\n", id.z, id.x, id.y); + printf("parsing tile %i,%i,%i (%i)\n", id.z, id.x, id.y, id.sourceZ); for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { const auto feature = geometryLayer->getFeature(i); const auto geometries = feature->getGeometries(); @@ -169,13 +169,23 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr // TODO: do this opportunistically FeatureProperties properties = feature->getAllValues(); + std::string name = ""; + const auto& maybe_name = feature->getValue("name_en"); + if (maybe_name && maybe_name.get().is()) { + name = maybe_name.get().get(); + } + result.featureTree.insert(std::make_tuple(featureBox, layer.id, properties)); - printf("added feature from %s at %i, %i\n", layer.id.c_str(), point.x, point.y); + printf("added feature '%s' from %s at %i, %i\n", + name.c_str(), + layer.id.c_str(), + point.x, + point.y); } } } if (result.featureTree.size()) { - printf("feature tree for %i,%i,%i [%s] has %lu members\n", id.z, id.x, id.y, layer.id.c_str(), result.featureTree.size()); + printf("feature tree for %i,%i,%i (%i) [%s] has %lu members\n", id.z, id.x, id.y, id.sourceZ, layer.id.c_str(), result.featureTree.size()); const auto bounds = result.featureTree.bounds(); printf("box: %i, %i to %i, %i\n", bounds.min_corner().get<0>(), bounds.min_corner().get<1>(), bounds.max_corner().get<0>(), bounds.max_corner().get<1>()); } From bda6e0ccf67a5bafe5ecee2a5344557ba953b292 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 30 Nov 2015 21:18:45 -0800 Subject: [PATCH 13/63] refs #352: only query clicked tile --- src/mbgl/map/map_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index e0a305d2bdc..930d43f74e3 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -343,7 +343,7 @@ std::vector> MapContext::featuresAt(co for (const auto& source : style->sources) { if (source->info.type == SourceType::Vector) { for (const auto& tile : source->getLoadedTiles()) { - // if (tile->id == coordinate) + if (tile->id != id) continue; // printf("[%s]: %i,%i,%i\n", source->info.source_id.c_str(), tile->id.z, tile->id.x, tile->id.y); const auto& tile_data = tile->data; From cd15d852b7ffb5222cb5a1df20c3b0b354d8b034 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 30 Nov 2015 21:21:34 -0800 Subject: [PATCH 14/63] refs #352: properly query scale --- src/mbgl/map/map_context.cpp | 37 +++++++++++------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 930d43f74e3..419875ef5db 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -287,7 +287,7 @@ std::vector> MapContext::featuresAt(co // printf("core: %f, %f\n", p_.latitude, p_.longitude); - // figure out tile + // figure out tile (bounded by source max zoom) // double sine = std::sin(p_.latitude * M_PI / 180); double x = p_.longitude / 360 + 0.5; @@ -297,48 +297,33 @@ std::vector> MapContext::featuresAt(co // PrecisionPoint p(x, y); - const auto z = floor(transformState.getZoom()); + const auto z = ::fmin(::floor(transformState.getZoom()), 15); const auto z2 = powf(2, z); - TileID id(z, floor(x * z2), floor(y * z2), ::fmin(z, 15)); + TileID id(z, ::floor(x * z2), ::floor(y * z2), ::floor(transformState.getZoom())); // figure out tile coordinate // -// TileCoordinate coordinate = transformState.pointToCoordinate(point); + TileCoordinate coordinate = transformState.pointToCoordinate(point); // figure out query bounds // - const auto world_size = util::tileSize * transformState.getScale(); - const auto scale = world_size / z2; + coordinate = coordinate.zoomTo(::fmin(id.z, 15)); -// coordinate.zoomTo(::fmin(id.z, 18)); -// coordinate.column /= id.overscaling; -// coordinate.row /= id.overscaling; -// coordinate.row = 4096 - coordinate.row; + vec2 position((coordinate.column - id.x) * 4096, (coordinate.row - id.y) * 4096); + const auto tile_scale = ::pow(2, z); + const auto scale = util::tileSize * transformState.getScale() / tile_scale; - vec2 coordinate(x * z2, y * z2); - - - - vec3 position((coordinate.x - id.x) * 4096, (coordinate.y - id.y) * 4096, scale); - - - - - std::vector> results; - - printf("===== query: %i, %i\n", position.x, position.y); - + const auto radius = 5 * 4096 / scale; + printf("===== query: %i,%i,%i @ %i, %i (radius: %f)\n", id.z, id.x, id.y, position.x, position.y, radius); - const auto radius = 5 * 4096 / scale; FeatureBox queryBox = { { position.x - radius, position.y - radius }, { position.x + radius, position.y + radius } }; - - + std::vector> results; for (const auto& source : style->sources) { if (source->info.type == SourceType::Vector) { From 29dc55e86b0cc820f59f02fbbdf7774787254a58 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 1 Dec 2015 16:35:27 -0800 Subject: [PATCH 15/63] refs #352: clean out existing tile feature tree on any sort of re-parse --- src/mbgl/map/vector_tile_data.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index 54ca4507af4..9595000514c 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -72,7 +72,7 @@ VectorTileData::VectorTileData(const TileID& id_, // existing buckets in case we got a refresh parse. buckets = std::move(resultBuckets.buckets); -// featureTree.clear(); + featureTree.clear(); featureTree.insert(resultBuckets.featureTree.begin(), resultBuckets.featureTree.end()); // The target configuration could have changed since we started placement. In this case, From b1e3da9055a54b9af9ec72d7f6654205f5c31fd7 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 1 Dec 2015 16:34:41 -0800 Subject: [PATCH 16/63] refs #352: fix for overzoomed tiles & disable some debug logs --- src/mbgl/map/map_context.cpp | 11 ++++++----- src/mbgl/map/tile_data.cpp | 1 + src/mbgl/map/tile_worker.cpp | 20 +++++++++----------- src/mbgl/map/vector_tile_data.cpp | 1 + 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 419875ef5db..a1f40d75727 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -297,9 +297,10 @@ std::vector> MapContext::featuresAt(co // PrecisionPoint p(x, y); - const auto z = ::fmin(::floor(transformState.getZoom()), 15); - const auto z2 = powf(2, z); - TileID id(z, ::floor(x * z2), ::floor(y * z2), ::floor(transformState.getZoom())); + const auto z = ::floor(transformState.getZoom()); + const auto source_max_z = ::fmin(z, 15); + const auto z2 = ::powf(2, source_max_z); + TileID id(z, ::floor(x * z2), ::floor(y * z2), source_max_z); // figure out tile coordinate // @@ -311,8 +312,8 @@ std::vector> MapContext::featuresAt(co vec2 position((coordinate.column - id.x) * 4096, (coordinate.row - id.y) * 4096); - const auto tile_scale = ::pow(2, z); - const auto scale = util::tileSize * transformState.getScale() / tile_scale; + const auto tile_scale = ::pow(2, id.z); // z); + const auto scale = util::tileSize * transformState.getScale() / (tile_scale / id.overscaling); const auto radius = 5 * 4096 / scale; diff --git a/src/mbgl/map/tile_data.cpp b/src/mbgl/map/tile_data.cpp index bba7d7fe222..0c4356877fd 100644 --- a/src/mbgl/map/tile_data.cpp +++ b/src/mbgl/map/tile_data.cpp @@ -6,6 +6,7 @@ namespace mbgl { TileData::TileData(const TileID& id_) : id(id_), state(State::initial) { +// printf("creating TileData %s (%p)\n", std::string(id).c_str(), this); } TileData::~TileData() = default; diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 302e91edf94..6d40038f1b2 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -139,7 +139,7 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr if (/*layer.interactive &&*/ layer.id.substr(0, 3) == "poi" && bucket->hasData()) { // result.featureTree.clear(); - printf("parsing tile %i,%i,%i (%i)\n", id.z, id.x, id.y, id.sourceZ); +// printf("parsing tile %i,%i,%i (%i)\n", id.z, id.x, id.y, id.z); for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { const auto feature = geometryLayer->getFeature(i); const auto geometries = feature->getGeometries(); @@ -148,8 +148,6 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr const auto geometry = geometries.at(j); for (std::size_t k = 0; k < geometry.size(); k++) { auto point = geometry.at(k); - point.x /= id.overscaling; - point.y /= id.overscaling; if (point.x < 0 || point.x > 4096 || point.y < 0 || point.y > 4096) continue; const auto min = featureBox.min_corner(); const auto max = featureBox.max_corner(); @@ -176,18 +174,18 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr } result.featureTree.insert(std::make_tuple(featureBox, layer.id, properties)); - printf("added feature '%s' from %s at %i, %i\n", - name.c_str(), - layer.id.c_str(), - point.x, - point.y); +// printf("added feature '%s' from %s at %i, %i\n", +// name.c_str(), +// layer.id.c_str(), +// point.x, +// point.y); } } } if (result.featureTree.size()) { - printf("feature tree for %i,%i,%i (%i) [%s] has %lu members\n", id.z, id.x, id.y, id.sourceZ, layer.id.c_str(), result.featureTree.size()); - const auto bounds = result.featureTree.bounds(); - printf("box: %i, %i to %i, %i\n", bounds.min_corner().get<0>(), bounds.min_corner().get<1>(), bounds.max_corner().get<0>(), bounds.max_corner().get<1>()); +// printf("feature tree for %i,%i,%i (%i) [%s] has %lu members\n", id.z, id.x, id.y, id.sourceZ, layer.id.c_str(), result.featureTree.size()); +// const auto bounds = result.featureTree.bounds(); +// printf("box: %i, %i to %i, %i\n", bounds.min_corner().get<0>(), bounds.min_corner().get<1>(), bounds.max_corner().get<0>(), bounds.max_corner().get<1>()); } } diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index 9595000514c..382adaeda5d 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -74,6 +74,7 @@ VectorTileData::VectorTileData(const TileID& id_, featureTree.clear(); featureTree.insert(resultBuckets.featureTree.begin(), resultBuckets.featureTree.end()); +// printf("consolidated results feature tree items (%lu) into own (%s/%p of %lu items)\n", resultBuckets.featureTree.size(), std::string(id).c_str(), this, featureTree.size()); // The target configuration could have changed since we started placement. In this case, // we're starting another placement run. From d0a34c5ddbf228d3ff5e64472e82b34d3a0100a3 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 1 Dec 2015 18:31:48 -0800 Subject: [PATCH 17/63] refs #352: pipe source through the features query --- include/mbgl/map/map.hpp | 4 ++-- src/mbgl/map/map.cpp | 4 ++-- src/mbgl/map/map_context.cpp | 8 ++++---- src/mbgl/map/map_context.hpp | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 61c83f3efca..ad41aeb8b6f 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -160,8 +160,8 @@ class Map : private util::noncopyable { LatLngBounds getBoundsForAnnotations(const AnnotationIDs&); double getTopOffsetPixelsForAnnotationSymbol(const std::string&); - // Features - std::vector> featuresAt(const PrecisionPoint) const; + // Features - layer name, source name, feature properties + std::vector> featuresAt(const PrecisionPoint) const; // Sprites void setSprite(const std::string&, std::shared_ptr); diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 09347402e30..77bb0b91b01 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -409,8 +409,8 @@ LatLngBounds Map::getBoundsForAnnotations(const AnnotationIDs& annotations) { #pragma mark - Features -std::vector> Map::featuresAt(const PrecisionPoint point) const { - return context->invokeSync>>(&MapContext::featuresAt, point); +std::vector> Map::featuresAt(const PrecisionPoint point) const { + return context->invokeSync>>(&MapContext::featuresAt, point); } diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index a1f40d75727..957d0b669ee 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -281,7 +281,7 @@ double MapContext::getTopOffsetPixelsForAnnotationSymbol(const std::string& symb } } -std::vector> MapContext::featuresAt(const PrecisionPoint point) const { +std::vector> MapContext::featuresAt(const PrecisionPoint point) const { LatLng p_ = transformState.pointToLatLng(point); @@ -324,7 +324,7 @@ std::vector> MapContext::featuresAt(co { position.x + radius, position.y + radius } }; - std::vector> results; + std::vector> results; for (const auto& source : style->sources) { if (source->info.type == SourceType::Vector) { @@ -338,14 +338,14 @@ std::vector> MapContext::featuresAt(co const std::string layer_id = std::get<1>(val); const FeatureProperties feature_properties = std::get<2>(val); - const auto result = std::make_pair(layer_id, feature_properties); + const auto result = std::make_tuple(layer_id, source->info.source_id, feature_properties); std::string properties = ""; for (const auto property : feature_properties) { properties = "\n\t" + property.first + ": " + property.second; } - printf("%s: %s\n", layer_id.c_str(), properties.c_str()); + printf("%s in %s: %s\n", layer_id.c_str(), source->info.source_id.c_str(), properties.c_str()); results.push_back(result); })); diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index 5aecc59de94..787692903a3 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -52,7 +52,7 @@ class MapContext : public Style::Observer { double getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol); void updateAnnotations(); - std::vector> featuresAt(const PrecisionPoint) const; + std::vector> featuresAt(const PrecisionPoint) const; void setSourceTileCacheSize(size_t size); void onLowMemory(); From f8fb7912a187f374911bbf89fdfb8de786416f4c Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 1 Dec 2015 18:34:56 -0800 Subject: [PATCH 18/63] refs #352: typedef feature results for brevity --- include/mbgl/map/map.hpp | 2 +- include/mbgl/util/interactive_features.hpp | 1 + src/mbgl/map/map.cpp | 2 +- src/mbgl/map/map_context.cpp | 4 ++-- src/mbgl/map/map_context.hpp | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index ad41aeb8b6f..fe604a8b683 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -161,7 +161,7 @@ class Map : private util::noncopyable { double getTopOffsetPixelsForAnnotationSymbol(const std::string&); // Features - layer name, source name, feature properties - std::vector> featuresAt(const PrecisionPoint) const; + FeatureResults featuresAt(const PrecisionPoint) const; // Sprites void setSprite(const std::string&, std::shared_ptr); diff --git a/include/mbgl/util/interactive_features.hpp b/include/mbgl/util/interactive_features.hpp index 1da8ec62238..5caed1f6dec 100644 --- a/include/mbgl/util/interactive_features.hpp +++ b/include/mbgl/util/interactive_features.hpp @@ -36,6 +36,7 @@ typedef FeatureBGM::box FeatureBox; typedef std::unordered_map FeatureProperties; typedef std::tuple Feature; // box, layer, properties typedef FeatureBGI::rtree> FeatureTree; +typedef std::vector> FeatureResults; // layer, source, properties } // namespace mbgl diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 77bb0b91b01..5ebfdd753ad 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -409,7 +409,7 @@ LatLngBounds Map::getBoundsForAnnotations(const AnnotationIDs& annotations) { #pragma mark - Features -std::vector> Map::featuresAt(const PrecisionPoint point) const { +FeatureResults Map::featuresAt(const PrecisionPoint point) const { return context->invokeSync>>(&MapContext::featuresAt, point); } diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 957d0b669ee..227e24750f9 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -281,7 +281,7 @@ double MapContext::getTopOffsetPixelsForAnnotationSymbol(const std::string& symb } } -std::vector> MapContext::featuresAt(const PrecisionPoint point) const { +FeatureResults MapContext::featuresAt(const PrecisionPoint point) const { LatLng p_ = transformState.pointToLatLng(point); @@ -324,7 +324,7 @@ std::vector> MapContext: { position.x + radius, position.y + radius } }; - std::vector> results; + FeatureResults results; for (const auto& source : style->sources) { if (source->info.type == SourceType::Vector) { diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index 787692903a3..1054288a147 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -52,7 +52,7 @@ class MapContext : public Style::Observer { double getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol); void updateAnnotations(); - std::vector> featuresAt(const PrecisionPoint) const; + FeatureResults featuresAt(const PrecisionPoint) const; void setSourceTileCacheSize(size_t size); void onLowMemory(); From caa257621cc39b97e512df2545cfad6b63329459 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 1 Dec 2015 18:56:34 -0800 Subject: [PATCH 19/63] refs #352: naive plumbing of work down into source --- src/mbgl/map/map_context.cpp | 83 ++---------------------------------- src/mbgl/map/source.cpp | 73 +++++++++++++++++++++++++++++++ src/mbgl/map/source.hpp | 4 ++ src/mbgl/style/style.cpp | 15 +++++++ src/mbgl/style/style.hpp | 3 ++ 5 files changed, 98 insertions(+), 80 deletions(-) diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 227e24750f9..454b56efda3 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -23,12 +23,9 @@ #include #include #include -#include #include -#include - namespace mbgl { MapContext::MapContext(View& view_, FileSource& fileSource, MapData& data_) @@ -282,83 +279,9 @@ double MapContext::getTopOffsetPixelsForAnnotationSymbol(const std::string& symb } FeatureResults MapContext::featuresAt(const PrecisionPoint point) const { - - LatLng p_ = transformState.pointToLatLng(point); - -// printf("core: %f, %f\n", p_.latitude, p_.longitude); - - // figure out tile (bounded by source max zoom) - // - double sine = std::sin(p_.latitude * M_PI / 180); - double x = p_.longitude / 360 + 0.5; - double y = 0.5 - 0.25 * std::log((1 + sine) / (1 - sine)) / M_PI; - - y = y < -1 ? -1 : y > 1 ? 1 : y; - -// PrecisionPoint p(x, y); - - const auto z = ::floor(transformState.getZoom()); - const auto source_max_z = ::fmin(z, 15); - const auto z2 = ::powf(2, source_max_z); - TileID id(z, ::floor(x * z2), ::floor(y * z2), source_max_z); - - // figure out tile coordinate - // - TileCoordinate coordinate = transformState.pointToCoordinate(point); - - // figure out query bounds - // - coordinate = coordinate.zoomTo(::fmin(id.z, 15)); - - vec2 position((coordinate.column - id.x) * 4096, (coordinate.row - id.y) * 4096); - - const auto tile_scale = ::pow(2, id.z); // z); - const auto scale = util::tileSize * transformState.getScale() / (tile_scale / id.overscaling); - - const auto radius = 5 * 4096 / scale; - - printf("===== query: %i,%i,%i @ %i, %i (radius: %f)\n", id.z, id.x, id.y, position.x, position.y, radius); - - FeatureBox queryBox = { - { position.x - radius, position.y - radius }, - { position.x + radius, position.y + radius } - }; - - FeatureResults results; - - for (const auto& source : style->sources) { - if (source->info.type == SourceType::Vector) { - for (const auto& tile : source->getLoadedTiles()) { - if (tile->id != id) continue; -// printf("[%s]: %i,%i,%i\n", source->info.source_id.c_str(), tile->id.z, tile->id.x, tile->id.y); - - const auto& tile_data = tile->data; - tile_data->featureTree.query(boost::geometry::index::intersects(queryBox), - boost::make_function_output_iterator([&](const auto& val) { - const std::string layer_id = std::get<1>(val); - const FeatureProperties feature_properties = std::get<2>(val); - - const auto result = std::make_tuple(layer_id, source->info.source_id, feature_properties); - - std::string properties = ""; - for (const auto property : feature_properties) { - properties = "\n\t" + property.first + ": " + property.second; - } - - printf("%s in %s: %s\n", layer_id.c_str(), source->info.source_id.c_str(), properties.c_str()); - - results.push_back(result); - })); - - - } - } - } - -// (void)point; - - return results; - + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); + if (!style) return FeatureResults(); + return style->featuresAt(point, transformState); } void MapContext::setSourceTileCacheSize(size_t size) { diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 3237c544da3..33b2f5f104b 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,8 @@ #include +#include + namespace mbgl { void parse(const rapidjson::Value& value, std::vector& target, const char *name) { @@ -603,4 +606,74 @@ void Source::dumpDebugLogs() const { } } +FeatureResults Source::featuresAt(const PrecisionPoint point, const TransformState& transform) const { + LatLng p_ = transform.pointToLatLng(point); + + // printf("core: %f, %f\n", p_.latitude, p_.longitude); + + // figure out tile (bounded by source max zoom) + // + double sine = std::sin(p_.latitude * M_PI / 180); + double x = p_.longitude / 360 + 0.5; + double y = 0.5 - 0.25 * std::log((1 + sine) / (1 - sine)) / M_PI; + + y = y < -1 ? -1 : y > 1 ? 1 : y; + + // PrecisionPoint p(x, y); + + const auto z = ::floor(transform.getZoom()); + const auto source_max_z = ::fmin(z, 15); + const auto z2 = ::powf(2, source_max_z); + TileID id(z, ::floor(x * z2), ::floor(y * z2), source_max_z); + + // figure out tile coordinate + // + TileCoordinate coordinate = transform.pointToCoordinate(point); + + // figure out query bounds + // + coordinate = coordinate.zoomTo(::fmin(id.z, 15)); + + vec2 position((coordinate.column - id.x) * 4096, (coordinate.row - id.y) * 4096); + + const auto tile_scale = ::pow(2, id.z); // z); + const auto scale = util::tileSize * transform.getScale() / (tile_scale / id.overscaling); + + const auto radius = 5 * 4096 / scale; + + printf("===== query: %i,%i,%i @ %i, %i (radius: %f)\n", id.z, id.x, id.y, position.x, position.y, radius); + + FeatureBox queryBox = { + { position.x - radius, position.y - radius }, + { position.x + radius, position.y + radius } + }; + + FeatureResults results; + + for (const auto& tile : getLoadedTiles()) { + if (tile->id != id) continue; +// printf("[%s]: %i,%i,%i\n", source->info.source_id.c_str(), tile->id.z, tile->id.x, tile->id.y); + + const auto& data = tile->data; + data->featureTree.query(boost::geometry::index::intersects(queryBox), + boost::make_function_output_iterator([&](const auto& val) { + const std::string layer_id = std::get<1>(val); + const FeatureProperties feature_properties = std::get<2>(val); + + const auto result = std::make_tuple(layer_id, info.source_id, feature_properties); + + std::string properties = ""; + for (const auto property : feature_properties) { + properties = "\n\t" + property.first + ": " + property.second; + } + + printf("%s in %s: %s\n", layer_id.c_str(), info.source_id.c_str(), properties.c_str()); + + results.push_back(result); + })); + } + + return results; +} + } diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp index 661aa09e847..824fcb9e2b9 100644 --- a/src/mbgl/map/source.hpp +++ b/src/mbgl/map/source.hpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include @@ -91,6 +93,8 @@ class Source : private util::noncopyable { void setObserver(Observer* observer); void dumpDebugLogs() const; + FeatureResults featuresAt(const PrecisionPoint, const TransformState&) const; + SourceInfo info; bool enabled; diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index 3523a72079d..121d8bb3786 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -265,6 +265,21 @@ void Style::emitResourceLoadingFailed(std::exception_ptr error) { } } +FeatureResults Style::featuresAt(const PrecisionPoint point, const TransformState& transform) const { + assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); + + FeatureResults results; + + for (const auto& source : sources) { + if (source->info.type == SourceType::Vector && source->isLoaded()) { + const auto source_results = source->featuresAt(point, transform); + results.insert(results.end(), source_results.begin(), source_results.end()); + } + } + + return results; +} + void Style::dumpDebugLogs() const { for (const auto& source : sources) { source->dumpDebugLogs(); diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index dbaf8cf02c9..d52a15dafa6 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -68,6 +69,8 @@ class Style : public GlyphStore::Observer, void addLayer(util::ptr, const std::string& beforeLayerID); void removeLayer(const std::string& layerID); + FeatureResults featuresAt(const PrecisionPoint, const TransformState& transform) const; + void dumpDebugLogs() const; MapData& data; From fdfb37751b03b75a339721c106ec9f225c336010 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 1 Dec 2015 19:00:42 -0800 Subject: [PATCH 20/63] refs #352: commenting cleanup --- include/mbgl/map/map.hpp | 2 +- include/mbgl/util/interactive_features.hpp | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index fe604a8b683..6eaa1c4804d 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -160,7 +160,7 @@ class Map : private util::noncopyable { LatLngBounds getBoundsForAnnotations(const AnnotationIDs&); double getTopOffsetPixelsForAnnotationSymbol(const std::string&); - // Features - layer name, source name, feature properties + // Features FeatureResults featuresAt(const PrecisionPoint) const; // Sprites diff --git a/include/mbgl/util/interactive_features.hpp b/include/mbgl/util/interactive_features.hpp index 5caed1f6dec..d0a0386b3f9 100644 --- a/include/mbgl/util/interactive_features.hpp +++ b/include/mbgl/util/interactive_features.hpp @@ -28,15 +28,24 @@ namespace mbgl { +// Boost namespacing namespace FeatureBG = boost::geometry; namespace FeatureBGM = FeatureBG::model; namespace FeatureBGI = FeatureBG::index; + +// Index properties typedef FeatureBGM::point FeaturePoint; typedef FeatureBGM::box FeatureBox; typedef std::unordered_map FeatureProperties; -typedef std::tuple Feature; // box, layer, properties + +// Query item (bounding box, layer name, properties) +typedef std::tuple Feature; + +// R-tree setup typedef FeatureBGI::rtree> FeatureTree; -typedef std::vector> FeatureResults; // layer, source, properties + +// Query results (layer name, source name, properties) +typedef std::vector> FeatureResults; } // namespace mbgl From 41159cb7a65e035cd2636a74e7095f065a5fdd32 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Tue, 1 Dec 2015 19:24:41 -0800 Subject: [PATCH 21/63] refs #352: public interface cleanup & get rid of unneeded optional/variant --- include/mbgl/util/interactive_features.hpp | 43 +++------------------ src/mbgl/map/source.hpp | 2 +- src/mbgl/map/tile_data.hpp | 2 +- src/mbgl/map/tile_worker.cpp | 2 +- src/mbgl/style/style.hpp | 2 +- src/mbgl/util/interactive_features_impl.hpp | 41 ++++++++++++++++++++ 6 files changed, 50 insertions(+), 42 deletions(-) create mode 100644 src/mbgl/util/interactive_features_impl.hpp diff --git a/include/mbgl/util/interactive_features.hpp b/include/mbgl/util/interactive_features.hpp index d0a0386b3f9..67547754347 100644 --- a/include/mbgl/util/interactive_features.hpp +++ b/include/mbgl/util/interactive_features.hpp @@ -1,52 +1,19 @@ #ifndef MBGL_UTIL_INTERACTIVE_FEATURES #define MBGL_UTIL_INTERACTIVE_FEATURES -#include -#include - #include +#include +#include #include -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wshadow" -#ifdef __clang__ -#pragma GCC diagnostic ignored "-Wunknown-pragmas" -#endif -#pragma GCC diagnostic ignored "-Wpragmas" -#pragma GCC diagnostic ignored "-Wdeprecated-register" -#pragma GCC diagnostic ignored "-Wshorten-64-to-32" -#pragma GCC diagnostic ignored "-Wunused-local-typedefs" -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" -#include -#include -#include -#include -#pragma GCC diagnostic pop - namespace mbgl { -// Boost namespacing -namespace FeatureBG = boost::geometry; -namespace FeatureBGM = FeatureBG::model; -namespace FeatureBGI = FeatureBG::index; - -// Index properties -typedef FeatureBGM::point FeaturePoint; -typedef FeatureBGM::box FeatureBox; +// key, value typedef std::unordered_map FeatureProperties; -// Query item (bounding box, layer name, properties) -typedef std::tuple Feature; - -// R-tree setup -typedef FeatureBGI::rtree> FeatureTree; - -// Query results (layer name, source name, properties) +// layer name, source name, feature properties typedef std::vector> FeatureResults; -} // namespace mbgl +} #endif diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp index 824fcb9e2b9..a946cbecc90 100644 --- a/src/mbgl/map/source.hpp +++ b/src/mbgl/map/source.hpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp index 4d1604f5676..14ccd83a7a6 100644 --- a/src/mbgl/map/tile_data.hpp +++ b/src/mbgl/map/tile_data.hpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 6d40038f1b2..df9ddb2a878 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include using namespace mbgl; diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index d52a15dafa6..26e12d5c392 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/mbgl/util/interactive_features_impl.hpp b/src/mbgl/util/interactive_features_impl.hpp new file mode 100644 index 00000000000..03672501877 --- /dev/null +++ b/src/mbgl/util/interactive_features_impl.hpp @@ -0,0 +1,41 @@ +#ifndef MBGL_UTIL_INTERACTIVE_FEATURES_IMPL +#define MBGL_UTIL_INTERACTIVE_FEATURES_IMPL + +#include + +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wshadow" +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#endif +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wdeprecated-register" +#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" +#include +#include +#include +#include +#pragma GCC diagnostic pop + +namespace mbgl { + +namespace FeatureBG = boost::geometry; +namespace FeatureBGM = FeatureBG::model; +namespace FeatureBGI = FeatureBG::index; + +typedef FeatureBGM::point FeaturePoint; +typedef FeatureBGM::box FeatureBox; +typedef std::tuple Feature; +typedef FeatureBGI::rtree> FeatureTree; + +} + +#endif From fd4b063dd0c1c10157ab513e605c1de1379ab551 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 15:09:28 -0800 Subject: [PATCH 22/63] refs #352: cleanups --- src/mbgl/map/source.cpp | 8 +++----- src/mbgl/map/tile_worker.cpp | 1 - 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 33b2f5f104b..3aa977a10fa 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -607,20 +607,18 @@ void Source::dumpDebugLogs() const { } FeatureResults Source::featuresAt(const PrecisionPoint point, const TransformState& transform) const { - LatLng p_ = transform.pointToLatLng(point); + LatLng p = transform.pointToLatLng(point); // printf("core: %f, %f\n", p_.latitude, p_.longitude); // figure out tile (bounded by source max zoom) // - double sine = std::sin(p_.latitude * M_PI / 180); - double x = p_.longitude / 360 + 0.5; + double sine = std::sin(p.latitude * M_PI / 180); + double x = p.longitude / 360 + 0.5; double y = 0.5 - 0.25 * std::log((1 + sine) / (1 - sine)) / M_PI; y = y < -1 ? -1 : y > 1 ? 1 : y; - // PrecisionPoint p(x, y); - const auto z = ::floor(transform.getZoom()); const auto source_max_z = ::fmin(z, 15); const auto z2 = ::powf(2, source_max_z); diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index df9ddb2a878..fb9ba2555cd 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -138,7 +138,6 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr std::unique_ptr bucket = layer.createBucket(parameters); if (/*layer.interactive &&*/ layer.id.substr(0, 3) == "poi" && bucket->hasData()) { -// result.featureTree.clear(); // printf("parsing tile %i,%i,%i (%i)\n", id.z, id.x, id.y, id.z); for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { const auto feature = geometryLayer->getFeature(i); From 181a997f5cd762f35377e38cdd09471c59192216 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 15:15:44 -0800 Subject: [PATCH 23/63] refs #352: add comment --- src/mbgl/map/vector_tile_data.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index 382adaeda5d..4191035eee0 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -72,6 +72,7 @@ VectorTileData::VectorTileData(const TileID& id_, // existing buckets in case we got a refresh parse. buckets = std::move(resultBuckets.buckets); + // Replace interactivity feature tree in case we got a refresh parse. featureTree.clear(); featureTree.insert(resultBuckets.featureTree.begin(), resultBuckets.featureTree.end()); // printf("consolidated results feature tree items (%lu) into own (%s/%p of %lu items)\n", resultBuckets.featureTree.size(), std::string(id).c_str(), this, featureTree.size()); From 641e7db2a29d0df0ccc7343f5e9c1b816bfbaff1 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 15:22:18 -0800 Subject: [PATCH 24/63] refs #352: move result feature tree directly --- src/mbgl/map/vector_tile_data.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index 4191035eee0..a0c873093e8 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -72,9 +72,8 @@ VectorTileData::VectorTileData(const TileID& id_, // existing buckets in case we got a refresh parse. buckets = std::move(resultBuckets.buckets); - // Replace interactivity feature tree in case we got a refresh parse. - featureTree.clear(); - featureTree.insert(resultBuckets.featureTree.begin(), resultBuckets.featureTree.end()); + // Move over interactivity feature tree in case we got a refresh parse. + featureTree = std::move(resultBuckets.featureTree); // printf("consolidated results feature tree items (%lu) into own (%s/%p of %lu items)\n", resultBuckets.featureTree.size(), std::string(id).c_str(), this, featureTree.size()); // The target configuration could have changed since we started placement. In this case, From ac6ada3ba34dee1734ac525971ac62e3d7b1a8bf Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 16:24:23 -0800 Subject: [PATCH 25/63] refs #352: clean up extent handling & only add features when valid bbox --- src/mbgl/map/tile_worker.cpp | 41 ++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index fb9ba2555cd..7c5168d4fe6 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -141,13 +141,14 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr // printf("parsing tile %i,%i,%i (%i)\n", id.z, id.x, id.y, id.z); for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { const auto feature = geometryLayer->getFeature(i); + + FeatureBox featureBox = {{ 4096, 4096 }, { -1, -1 }}; const auto geometries = feature->getGeometries(); for (std::size_t j = 0; j < geometries.size(); j++) { - FeatureBox featureBox {{ 4096, 4096 }, { 0, 0 }}; const auto geometry = geometries.at(j); for (std::size_t k = 0; k < geometry.size(); k++) { auto point = geometry.at(k); - if (point.x < 0 || point.x > 4096 || point.y < 0 || point.y > 4096) continue; + if (point.x < 0 || point.x > 4095 || point.y < 0 || point.y > 4095) continue; const auto min = featureBox.min_corner(); const auto max = featureBox.max_corner(); if (point.x < min.get<0>()) { @@ -157,28 +158,32 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr featureBox.min_corner().set<1>(::fmax(point.y, 0)); } if (point.x > max.get<0>()) { - featureBox.max_corner().set<0>(::fmin(point.x, 4096)); + featureBox.max_corner().set<0>(::fmin(point.x, 4095)); } if (point.y > max.get<1>()) { - featureBox.max_corner().set<1>(::fmin(point.y, 4096)); + featureBox.max_corner().set<1>(::fmin(point.y, 4095)); } + } + } - // TODO: do this opportunistically - FeatureProperties properties = feature->getAllValues(); + if (featureBox.min_corner().get<0>() < 4096 && featureBox.min_corner().get<1>() < 4096 && + featureBox.max_corner().get<0>() > -1 && featureBox.max_corner().get<1>() > -1) { + // TODO: do this opportunistically + FeatureProperties properties = feature->getAllValues(); - std::string name = ""; - const auto& maybe_name = feature->getValue("name_en"); - if (maybe_name && maybe_name.get().is()) { - name = maybe_name.get().get(); - } +// std::string name = ""; +// const auto& maybe_name = feature->getValue("name_en"); +// if (maybe_name && maybe_name.get().is()) { +// name = maybe_name.get().get(); +// } - result.featureTree.insert(std::make_tuple(featureBox, layer.id, properties)); -// printf("added feature '%s' from %s at %i, %i\n", -// name.c_str(), -// layer.id.c_str(), -// point.x, -// point.y); - } + result.featureTree.insert(std::make_tuple(featureBox, layer.id, properties)); + +// printf("added feature '%s' from %s at %i, %i\n", +// name.c_str(), +// layer.id.c_str(), +// point.x, +// point.y); } } if (result.featureTree.size()) { From 7cdcc49aed40f147a93bb199d0fae611d1f7d14b Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 16:28:17 -0800 Subject: [PATCH 26/63] refs #352: obtain non-string vector tile properties as well --- src/mbgl/map/vector_tile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mbgl/map/vector_tile.cpp b/src/mbgl/map/vector_tile.cpp index f427ad7d5e9..5a44ec845e4 100644 --- a/src/mbgl/map/vector_tile.cpp +++ b/src/mbgl/map/vector_tile.cpp @@ -90,8 +90,8 @@ std::unordered_map VectorTileFeature::getAllValues() c for (const auto key_it : layer.keys) { const auto& key = key_it.first; const auto maybe_val = getValue(key); - if (maybe_val && maybe_val.get().is()) { - const auto& val = maybe_val.get().get(); + if (maybe_val) { + const auto& val = mbgl::toString(maybe_val.get()); values.emplace(key, val); } } From b5f5a247eeebf7c3d4848ecc31d72aa40f53f508 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 16:36:06 -0800 Subject: [PATCH 27/63] refs #352: sort result keys at query time as on JS --- include/mbgl/util/interactive_features.hpp | 4 ++-- src/mbgl/map/tile_worker.cpp | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/mbgl/util/interactive_features.hpp b/include/mbgl/util/interactive_features.hpp index 67547754347..0c93ac12a17 100644 --- a/include/mbgl/util/interactive_features.hpp +++ b/include/mbgl/util/interactive_features.hpp @@ -1,7 +1,7 @@ #ifndef MBGL_UTIL_INTERACTIVE_FEATURES #define MBGL_UTIL_INTERACTIVE_FEATURES -#include +#include #include #include #include @@ -9,7 +9,7 @@ namespace mbgl { // key, value -typedef std::unordered_map FeatureProperties; +typedef std::map FeatureProperties; // layer name, source name, feature properties typedef std::vector> FeatureResults; diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 7c5168d4fe6..a100bb1c71e 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -169,7 +169,9 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr if (featureBox.min_corner().get<0>() < 4096 && featureBox.min_corner().get<1>() < 4096 && featureBox.max_corner().get<0>() > -1 && featureBox.max_corner().get<1>() > -1) { // TODO: do this opportunistically - FeatureProperties properties = feature->getAllValues(); + FeatureProperties properties; + const auto& values = feature->getAllValues(); + properties.insert(values.begin(), values.end()); // std::string name = ""; // const auto& maybe_name = feature->getValue("name_en"); From a9b9568b0c16bbfaaa3ee7cd4e475221d30b0619 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 16:37:13 -0800 Subject: [PATCH 28/63] refs #352: clarify comment --- src/mbgl/map/tile_worker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index a100bb1c71e..5167c646a85 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -168,7 +168,7 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr if (featureBox.min_corner().get<0>() < 4096 && featureBox.min_corner().get<1>() < 4096 && featureBox.max_corner().get<0>() > -1 && featureBox.max_corner().get<1>() > -1) { - // TODO: do this opportunistically + // TODO: opportunistically hit the pbf at query time FeatureProperties properties; const auto& values = feature->getAllValues(); properties.insert(values.begin(), values.end()); From e7b01cd2bb86425074675b237e70dc90ffb42a76 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 16:53:19 -0800 Subject: [PATCH 29/63] refs #352: don't clobber debug output properties each loop --- src/mbgl/map/source.cpp | 2 +- src/mbgl/map/tile_worker.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 3aa977a10fa..5db90f0f401 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -662,7 +662,7 @@ FeatureResults Source::featuresAt(const PrecisionPoint point, const TransformSta std::string properties = ""; for (const auto property : feature_properties) { - properties = "\n\t" + property.first + ": " + property.second; + properties = properties + "\n\t" + property.first + ": " + property.second; } printf("%s in %s: %s\n", layer_id.c_str(), info.source_id.c_str(), properties.c_str()); diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 5167c646a85..5ee49dea29d 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -169,8 +169,8 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr if (featureBox.min_corner().get<0>() < 4096 && featureBox.min_corner().get<1>() < 4096 && featureBox.max_corner().get<0>() > -1 && featureBox.max_corner().get<1>() > -1) { // TODO: opportunistically hit the pbf at query time - FeatureProperties properties; const auto& values = feature->getAllValues(); + FeatureProperties properties; properties.insert(values.begin(), values.end()); // std::string name = ""; From d5c31e2bb33773565351da7133733f808a9f46c5 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 17:11:55 -0800 Subject: [PATCH 30/63] refs #352: fix partial parse symbol layers doesn't matter if we respond to bucket->hasData() here; features still exist in tile --- src/mbgl/map/tile_worker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 5ee49dea29d..7caaf3b61c1 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -137,8 +137,8 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr std::unique_ptr bucket = layer.createBucket(parameters); - if (/*layer.interactive &&*/ layer.id.substr(0, 3) == "poi" && bucket->hasData()) { -// printf("parsing tile %i,%i,%i (%i)\n", id.z, id.x, id.y, id.z); + if (layer.interactive) { + printf("parsing tile %i,%i,%i (%i)\n", id.z, id.x, id.y, id.z); for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { const auto feature = geometryLayer->getFeature(i); From 660ff917ef6df1ecc61f618802494a545686a851 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 17:13:07 -0800 Subject: [PATCH 31/63] refs #352: remove debug log --- src/mbgl/map/tile_worker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 7caaf3b61c1..d420479a6b5 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -138,7 +138,7 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr std::unique_ptr bucket = layer.createBucket(parameters); if (layer.interactive) { - printf("parsing tile %i,%i,%i (%i)\n", id.z, id.x, id.y, id.z); +// printf("parsing tile %i,%i,%i (%i)\n", id.z, id.x, id.y, id.z); for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { const auto feature = geometryLayer->getFeature(i); From 22e5c48e811b95e0a89caa00db0b419834fdc542 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 17:22:24 -0800 Subject: [PATCH 32/63] refs #352: remove logging & reorganize Also, don't worry about possibly opportunistically grabbing the query results vector tile properties. After initial parse, we've thrown the tile request data away, so the pbf is gone. We can chalk this up to the typical overhead involved with making a layer interactive. --- src/mbgl/map/source.cpp | 17 +++++------------ src/mbgl/map/tile_worker.cpp | 21 --------------------- src/mbgl/map/vector_tile_data.cpp | 2 +- 3 files changed, 6 insertions(+), 34 deletions(-) diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 5db90f0f401..86e40f8dca3 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -607,12 +607,9 @@ void Source::dumpDebugLogs() const { } FeatureResults Source::featuresAt(const PrecisionPoint point, const TransformState& transform) const { + // figure out tile (bounded by source max zoom) LatLng p = transform.pointToLatLng(point); - // printf("core: %f, %f\n", p_.latitude, p_.longitude); - - // figure out tile (bounded by source max zoom) - // double sine = std::sin(p.latitude * M_PI / 180); double x = p.longitude / 360 + 0.5; double y = 0.5 - 0.25 * std::log((1 + sine) / (1 - sine)) / M_PI; @@ -622,14 +619,11 @@ FeatureResults Source::featuresAt(const PrecisionPoint point, const TransformSta const auto z = ::floor(transform.getZoom()); const auto source_max_z = ::fmin(z, 15); const auto z2 = ::powf(2, source_max_z); - TileID id(z, ::floor(x * z2), ::floor(y * z2), source_max_z); - // figure out tile coordinate - // - TileCoordinate coordinate = transform.pointToCoordinate(point); + TileID id(z, ::floor(x * z2), ::floor(y * z2), source_max_z); // figure out query bounds - // + TileCoordinate coordinate = transform.pointToCoordinate(point); coordinate = coordinate.zoomTo(::fmin(id.z, 15)); vec2 position((coordinate.column - id.x) * 4096, (coordinate.row - id.y) * 4096); @@ -639,8 +633,6 @@ FeatureResults Source::featuresAt(const PrecisionPoint point, const TransformSta const auto radius = 5 * 4096 / scale; - printf("===== query: %i,%i,%i @ %i, %i (radius: %f)\n", id.z, id.x, id.y, position.x, position.y, radius); - FeatureBox queryBox = { { position.x - radius, position.y - radius }, { position.x + radius, position.y + radius } @@ -648,10 +640,11 @@ FeatureResults Source::featuresAt(const PrecisionPoint point, const TransformSta FeatureResults results; + // find the right tile for (const auto& tile : getLoadedTiles()) { if (tile->id != id) continue; -// printf("[%s]: %i,%i,%i\n", source->info.source_id.c_str(), tile->id.z, tile->id.x, tile->id.y); + // query the tile const auto& data = tile->data; data->featureTree.query(boost::geometry::index::intersects(queryBox), boost::make_function_output_iterator([&](const auto& val) { diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index d420479a6b5..f1c86aff2d8 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -138,10 +138,8 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr std::unique_ptr bucket = layer.createBucket(parameters); if (layer.interactive) { -// printf("parsing tile %i,%i,%i (%i)\n", id.z, id.x, id.y, id.z); for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { const auto feature = geometryLayer->getFeature(i); - FeatureBox featureBox = {{ 4096, 4096 }, { -1, -1 }}; const auto geometries = feature->getGeometries(); for (std::size_t j = 0; j < geometries.size(); j++) { @@ -168,31 +166,12 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr if (featureBox.min_corner().get<0>() < 4096 && featureBox.min_corner().get<1>() < 4096 && featureBox.max_corner().get<0>() > -1 && featureBox.max_corner().get<1>() > -1) { - // TODO: opportunistically hit the pbf at query time const auto& values = feature->getAllValues(); FeatureProperties properties; properties.insert(values.begin(), values.end()); - -// std::string name = ""; -// const auto& maybe_name = feature->getValue("name_en"); -// if (maybe_name && maybe_name.get().is()) { -// name = maybe_name.get().get(); -// } - result.featureTree.insert(std::make_tuple(featureBox, layer.id, properties)); - -// printf("added feature '%s' from %s at %i, %i\n", -// name.c_str(), -// layer.id.c_str(), -// point.x, -// point.y); } } - if (result.featureTree.size()) { -// printf("feature tree for %i,%i,%i (%i) [%s] has %lu members\n", id.z, id.x, id.y, id.sourceZ, layer.id.c_str(), result.featureTree.size()); -// const auto bounds = result.featureTree.bounds(); -// printf("box: %i, %i to %i, %i\n", bounds.min_corner().get<0>(), bounds.min_corner().get<1>(), bounds.max_corner().get<0>(), bounds.max_corner().get<1>()); - } } if (layer.type == StyleLayerType::Symbol && partialParse) { diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index a0c873093e8..977b367b0a3 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -51,7 +51,7 @@ VectorTileData::VectorTileData(const TileID& id_, } // Kick off a fresh parse of this tile. This happens when the tile is new, or - // when tile data changed. Replacing the workdRequest will cancel a pending work + // when tile data changed. Replacing the workRequest will cancel a pending work // request in case there is one. workRequest.reset(); workRequest = worker.parseGeometryTile(tileWorker, style.layers, std::move(tile), targetConfig, [callback, this, config = targetConfig] (TileParseResult result) { From 7f6010a5ea9c2cb29a06f032fe63c049c783e4d9 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 17:36:24 -0800 Subject: [PATCH 33/63] refs #352: build up Cocoa API and remove last of logging --- include/mbgl/ios/MGLMapView.h | 2 +- platform/ios/MGLMapView.mm | 34 ++++++++++++++++++++++++++++++---- src/mbgl/map/source.cpp | 9 --------- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index 0b86f4249e8..00837b8ae6f 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -371,7 +371,7 @@ IB_DESIGNABLE /** Whether the map view should display a heading calibration alert when necessary. The default value is `YES`. */ @property (nonatomic, assign) BOOL displayHeadingCalibration; -- (void)featuresAt:(CGPoint)point; +- (NS_ARRAY_OF(NSDictionary *) *)featuresAt:(CGPoint)point; #pragma mark - Debugging diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index f83c3003f21..105946c6fd6 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -383,12 +383,38 @@ - (void)commonInit }]; } -- (void)featuresAt:(CGPoint)point +- (NS_ARRAY_OF(NSDictionary *) *)featuresAt:(CGPoint)point { -// NSLog(@"iOS: %f, %f", [self convertPoint:point toCoordinateFromView:self].latitude, [self convertPoint:point toCoordinateFromView:self].longitude); - // flip y for core - _mbglMap->featuresAt(mbgl::PrecisionPoint(point.x, self.bounds.size.height - point.y)); + point.y = self.bounds.size.height - point.y; + + mbgl::FeatureResults results = _mbglMap->featuresAt(mbgl::PrecisionPoint(point.x, point.y)); + + NSMutableArray *features = [NSMutableArray arrayWithCapacity:results.size()]; + + for (const auto& result : results) + { + NSString *layerName = [NSString stringWithUTF8String:std::get<0>(result).c_str()]; + NSString *sourceName = [NSString stringWithUTF8String:std::get<1>(result).c_str()]; + + const auto& properties = std::get<2>(result); + + NSMutableDictionary *featureProperties = [NSMutableDictionary dictionaryWithCapacity:properties.size()]; + + for (const auto& property : properties) + { + NSString *key = [NSString stringWithUTF8String:property.first.c_str()]; + NSString *val = [NSString stringWithUTF8String:property.second.c_str()]; + + featureProperties[key] = val; + } + + [features addObject:@{ @"layer": layerName, + @"source": sourceName, + @"properties": featureProperties }]; + } + + return [NSArray arrayWithArray:features]; } - (void)createGLView diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 86e40f8dca3..0b945fa96b7 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -650,16 +650,7 @@ FeatureResults Source::featuresAt(const PrecisionPoint point, const TransformSta boost::make_function_output_iterator([&](const auto& val) { const std::string layer_id = std::get<1>(val); const FeatureProperties feature_properties = std::get<2>(val); - const auto result = std::make_tuple(layer_id, info.source_id, feature_properties); - - std::string properties = ""; - for (const auto property : feature_properties) { - properties = properties + "\n\t" + property.first + ": " + property.second; - } - - printf("%s in %s: %s\n", layer_id.c_str(), info.source_id.c_str(), properties.c_str()); - results.push_back(result); })); } From 98249373fd0ac2d2540e174a68e732386a9e8566 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 17:43:00 -0800 Subject: [PATCH 34/63] refs #352: add Cocoa docs --- include/mbgl/ios/MGLMapView.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index 00837b8ae6f..d0120d6da79 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -82,6 +82,14 @@ IB_DESIGNABLE /** The button shown in the lower-right of the map which when pressed displays the map attribution information. */ @property (nonatomic, readonly) UIButton *attributionButton; +/** Query the visible map for features at a given point. +* +* @warning Beta API. Return value subject to change in subsequent releases. +* +* @param point A point on screen, for example at a user gesture. +* @return An array of `NSDictionary` objects representing features near the point. Current fields provided are the style `layer`, the style `source`, and a nested dictionary of properties of the feature as `NSString` keys and values. */ +- (NS_ARRAY_OF(NSDictionary *) *)featuresAt:(CGPoint)point; + #pragma mark - Accessing the Delegate /** @name Accessing the Delegate */ @@ -371,8 +379,6 @@ IB_DESIGNABLE /** Whether the map view should display a heading calibration alert when necessary. The default value is `YES`. */ @property (nonatomic, assign) BOOL displayHeadingCalibration; -- (NS_ARRAY_OF(NSDictionary *) *)featuresAt:(CGPoint)point; - #pragma mark - Debugging /** @name Debugging */ From 91976cb4683dde1365fee86909ee7d909831df54 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 17:53:13 -0800 Subject: [PATCH 35/63] refs #352: add gesture for feature querying --- ios/app/MBXViewController.mm | 61 ++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm index f045f718b72..f7ec9a0b5df 100644 --- a/ios/app/MBXViewController.mm +++ b/ios/app/MBXViewController.mm @@ -78,6 +78,10 @@ - (void)viewDidLoad [self.mapView addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]]; + UILongPressGestureRecognizer *twoFingerLongPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerLongPress:)]; + twoFingerLongPress.numberOfTouchesRequired = 2; + [self.mapView addGestureRecognizer:twoFingerLongPress]; + [self restoreState:nil]; } @@ -296,15 +300,54 @@ - (void)handleLongPress:(UILongPressGestureRecognizer *)longPress { if (longPress.state == UIGestureRecognizerStateBegan) { -// MGLPointAnnotation *point = [MGLPointAnnotation new]; -// point.coordinate = [self.mapView convertPoint:[longPress locationInView:longPress.view] -// toCoordinateFromView:self.mapView]; -// point.title = @"Dropped Marker"; -// point.subtitle = [NSString stringWithFormat:@"lat: %.3f, lon: %.3f", point.coordinate.latitude, point.coordinate.longitude]; -// [self.mapView addAnnotation:point]; -// [self.mapView selectAnnotation:point animated:YES]; - - [self.mapView featuresAt:[longPress locationInView:longPress.view]]; + MGLPointAnnotation *point = [MGLPointAnnotation new]; + point.coordinate = [self.mapView convertPoint:[longPress locationInView:longPress.view] + toCoordinateFromView:self.mapView]; + point.title = @"Dropped Marker"; + point.subtitle = [NSString stringWithFormat:@"lat: %.3f, lon: %.3f", point.coordinate.latitude, point.coordinate.longitude]; + [self.mapView addAnnotation:point]; + [self.mapView selectAnnotation:point animated:YES]; + } +} + +- (void)handleTwoFingerLongPress:(UILongPressGestureRecognizer *)longPress +{ + if (longPress.state == UIGestureRecognizerStateBegan) + { + NSArray *features = [self.mapView featuresAt:[longPress locationInView:longPress.view]]; + + if ([features count]) + { + NSMutableString *output = [NSMutableString string]; + + for (NSDictionary *feature in features) + { + [output appendString:@"Layer: "]; + [output appendString:[feature objectForKey:@"layer"]]; + [output appendString:@"\n"]; + + [output appendString:@"Source: "]; + [output appendString:[feature objectForKey:@"source"]]; + [output appendString:@"\n"]; + + NSDictionary *properties = [feature objectForKey:@"properties"]; + + for (NSString *key in [properties allKeys]) + { + [output appendString:key]; + [output appendString:@": "]; + [output appendString:properties[key]]; + [output appendString:@"\n"]; + } + } + + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Features" + message:output + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alert show]; + } } } From 2c266e31e02bf2693a697cd1653ee84561ab67c1 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 20:17:44 -0800 Subject: [PATCH 36/63] refs #352: added interactive style mode to iOS test app --- ios/app/MBXViewController.mm | 62 +- ios/app/mapboxgl-app.gypi | 3 +- ios/app/streets-interactive-poi-v8.json | 8876 +++++++++++++++++++++++ 3 files changed, 8916 insertions(+), 25 deletions(-) create mode 100644 ios/app/streets-interactive-poi-v8.json diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm index f7ec9a0b5df..44302f92484 100644 --- a/ios/app/MBXViewController.mm +++ b/ios/app/MBXViewController.mm @@ -314,39 +314,53 @@ - (void)handleTwoFingerLongPress:(UILongPressGestureRecognizer *)longPress { if (longPress.state == UIGestureRecognizerStateBegan) { - NSArray *features = [self.mapView featuresAt:[longPress locationInView:longPress.view]]; - - if ([features count]) + if ([self.mapView.styleURL.scheme isEqualToString:@"mapbox"]) { - NSMutableString *output = [NSMutableString string]; + self.mapView.styleURL = [NSURL URLWithString:@"asset://streets-interactive-poi-v8.json"]; - for (NSDictionary *feature in features) - { - [output appendString:@"Layer: "]; - [output appendString:[feature objectForKey:@"layer"]]; - [output appendString:@"\n"]; + [(UIButton *)self.navigationItem.titleView setTitle:@"Interactive Streets" forState:UIControlStateNormal]; - [output appendString:@"Source: "]; - [output appendString:[feature objectForKey:@"source"]]; - [output appendString:@"\n"]; + [[[UIAlertView alloc] initWithTitle:@"Map Is Now Interactive" + message:@"Long-press again with two fingers to query POIs on the map." + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil] show]; + } + else + { + NSArray *features = [self.mapView featuresAt:[longPress locationInView:longPress.view]]; - NSDictionary *properties = [feature objectForKey:@"properties"]; + if ([features count]) + { + NSMutableString *output = [NSMutableString string]; - for (NSString *key in [properties allKeys]) + for (NSDictionary *feature in features) { - [output appendString:key]; - [output appendString:@": "]; - [output appendString:properties[key]]; + [output appendString:@"Layer: "]; + [output appendString:[feature objectForKey:@"layer"]]; [output appendString:@"\n"]; + + [output appendString:@"Source: "]; + [output appendString:[feature objectForKey:@"source"]]; + [output appendString:@"\n"]; + + NSDictionary *properties = [feature objectForKey:@"properties"]; + + for (NSString *key in [properties allKeys]) + { + [output appendString:key]; + [output appendString:@": "]; + [output appendString:properties[key]]; + [output appendString:@"\n"]; + } } - } - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Features" - message:output - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil]; - [alert show]; + [[[UIAlertView alloc] initWithTitle:@"Features" + message:output + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil] show]; + } } } } diff --git a/ios/app/mapboxgl-app.gypi b/ios/app/mapboxgl-app.gypi index 799cb62e783..bb1f2d43bae 100644 --- a/ios/app/mapboxgl-app.gypi +++ b/ios/app/mapboxgl-app.gypi @@ -14,7 +14,8 @@ './polyline.geojson', './threestates.geojson', './Settings.bundle/', - './app-info.plist' + './app-info.plist', + './streets-interactive-poi-v8.json' ], 'dependencies': [ diff --git a/ios/app/streets-interactive-poi-v8.json b/ios/app/streets-interactive-poi-v8.json new file mode 100644 index 00000000000..fa40d08c934 --- /dev/null +++ b/ios/app/streets-interactive-poi-v8.json @@ -0,0 +1,8876 @@ +{ + "version": 8, + "name": "Mapbox Streets", + "metadata": { + "mapbox:groups": { + "1444934828655.3389": { + "name": "Aeroways", + "collapsed": true + }, + "1444933322393.2852": { + "name": "POI labels (scalerank 1)", + "collapsed": true + }, + "1444855898284.2651": { + "name": "Aeroways", + "collapsed": true + }, + "1444862578782.6787": { + "name": "Road labels", + "collapsed": true + }, + "1444934749452.0452": { + "name": "Wetlands", + "collapsed": true + }, + "1444862074717.8372": { + "name": "Waterways", + "collapsed": true + }, + "1444855868004.2437": { + "name": "Landuse", + "collapsed": false + }, + "1444855786460.0557": { + "name": "Roads", + "collapsed": true + }, + "1444856968392.4368": { + "name": "Contour lines", + "collapsed": true + }, + "1444856071629.7817": { + "name": "Place labels", + "collapsed": true + }, + "1444933575858.6992": { + "name": "Highway shields", + "collapsed": true + }, + "1444934295202.7542": { + "name": "Admin boundaries", + "collapsed": true + }, + "1444856904773.373": { + "name": "Land barriers", + "collapsed": true + }, + "1444856931506.5164": { + "name": "Barriers", + "collapsed": true + }, + "1444856151690.9143": { + "name": "State labels", + "collapsed": true + }, + "1444933721429.3076": { + "name": "Road labels", + "collapsed": true + }, + "1444933358918.2366": { + "name": "POI labels (scalerank 2)", + "collapsed": true + }, + "1444933808272.805": { + "name": "Water labels", + "collapsed": true + }, + "1444855815295.714": { + "name": "Hillshading", + "collapsed": true + }, + "1444855831248.8289": { + "name": "Landcover", + "collapsed": true + }, + "1444933372896.5967": { + "name": "POI labels (scalerank 3)", + "collapsed": true + }, + "1444855799204.86": { + "name": "Bridges", + "collapsed": true + }, + "1444856087950.3635": { + "name": "Marine labels", + "collapsed": true + }, + "1444856869758.2375": { + "name": "Wetlands", + "collapsed": true + }, + "1444862510685.128": { + "name": "City labels", + "collapsed": true + }, + "1444856954425.4016": { + "name": "Buildings", + "collapsed": true + }, + "1444855769305.6016": { + "name": "Tunnels", + "collapsed": true + }, + "1444856144497.7825": { + "name": "Country labels", + "collapsed": true + }, + "1444856712129.5933": { + "name": "Waterways", + "collapsed": true + }, + "1444856677484.5256": { + "name": "High zoom level labels", + "collapsed": true + }, + "1444933456003.5437": { + "name": "POI labels (scalerank 4)", + "collapsed": true + }, + "1444933837268.9458": { + "name": "Contour lines", + "collapsed": true + } + } + }, + "sources": { + "composite": { + "url": "mapbox://mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6", + "type": "vector" + } + }, + "sprite": "mapbox://sprites/mapbox/streets-v8", + "glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "layout": { + "visibility": "visible" + }, + "paint": { + "background-color": "#ede9d9" + } + }, + { + "id": "landcover_crop", + "type": "fill", + "source": "composite", + "source-layer": "landcover", + "filter": [ + "==", + "class", + "crop" + ], + "maxzoom": 14, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#ddecb1", + "fill-opacity": { + "base": 1.5, + "stops": [ + [ + 2, + 0.3 + ], + [ + 14, + 0 + ] + ] + }, + "fill-antialias": false + }, + "metadata": { + "mapbox:group": "1444855831248.8289" + } + }, + { + "id": "landcover_grass", + "type": "fill", + "source": "composite", + "source-layer": "landcover", + "filter": [ + "==", + "class", + "grass" + ], + "maxzoom": 14, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#ddecb1", + "fill-opacity": { + "base": 1.5, + "stops": [ + [ + 2, + 0.3 + ], + [ + 14, + 0 + ] + ] + }, + "fill-antialias": false + }, + "metadata": { + "mapbox:group": "1444855831248.8289" + } + }, + { + "id": "landcover_scrub", + "type": "fill", + "source": "composite", + "source-layer": "landcover", + "filter": [ + "==", + "class", + "scrub" + ], + "maxzoom": 14, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#ddecb1", + "fill-opacity": { + "base": 1.5, + "stops": [ + [ + 2, + 0.3 + ], + [ + 14, + 0 + ] + ] + }, + "fill-antialias": false + }, + "metadata": { + "mapbox:group": "1444855831248.8289" + } + }, + { + "id": "landcover_wood", + "type": "fill", + "source": "composite", + "source-layer": "landcover", + "filter": [ + "==", + "class", + "wood" + ], + "maxzoom": 14, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#ddecb1", + "fill-opacity": { + "base": 1.5, + "stops": [ + [ + 2, + 0.3 + ], + [ + 14, + 0 + ] + ] + }, + "fill-antialias": false + }, + "metadata": { + "mapbox:group": "1444855831248.8289" + } + }, + { + "id": "landcover_snow", + "type": "fill", + "source": "composite", + "source-layer": "landcover", + "filter": [ + "==", + "class", + "snow" + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#fff", + "fill-opacity": 0.2, + "fill-antialias": false + }, + "metadata": { + "mapbox:group": "1444855831248.8289" + } + }, + { + "id": "scrub", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "scrub" + ], + "minzoom": 9, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#ddecb1", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 9, + 0 + ], + [ + 16, + 0.2 + ] + ] + } + } + }, + { + "id": "grass", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "grass" + ], + "minzoom": 9, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#ddecb1", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 9, + 0 + ], + [ + 16, + 0.4 + ] + ] + } + } + }, + { + "id": "wood", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "wood" + ], + "minzoom": 6, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#ddecb1", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 6, + 0 + ], + [ + 16, + 0.5 + ] + ] + } + } + }, + { + "id": "hospital", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "hospital" + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#f4dcdc" + } + }, + { + "id": "school", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "school" + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#f3ebb4" + } + }, + { + "id": "parks", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "park" + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#cde8a2", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 5, + 0 + ], + [ + 6, + 1 + ] + ] + } + } + }, + { + "id": "glaciers", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "glacier" + ], + "minzoom": 9, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#dcedf9", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 9, + 0 + ], + [ + 10, + 0.25 + ] + ] + } + } + }, + { + "id": "pitch", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "pitch" + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#c3e194" + } + }, + { + "id": "pitch-line", + "type": "line", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "pitch" + ], + "minzoom": 15, + "layout": {}, + "paint": { + "line-color": "#e1f2c6" + } + }, + { + "id": "cemetery", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "cemetery" + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#dde6c2" + } + }, + { + "id": "industrial", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "industrial" + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#e0dae0" + } + }, + { + "id": "sand", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "sand" + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#ededcf" + } + }, + { + "id": "hillshade_highlight_bright", + "type": "fill", + "source": "composite", + "source-layer": "hillshade", + "filter": [ + "==", + "level", + 94 + ], + "maxzoom": 18, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#fff", + "fill-opacity": { + "stops": [ + [ + 15, + 0.12 + ], + [ + 18, + 0 + ] + ] + }, + "fill-antialias": false + }, + "metadata": { + "mapbox:group": "1444855815295.714" + } + }, + { + "id": "hillshade_highlight_med", + "type": "fill", + "source": "composite", + "source-layer": "hillshade", + "filter": [ + "==", + "level", + 90 + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#fff", + "fill-opacity": { + "stops": [ + [ + 15, + 0.12 + ], + [ + 18, + 0 + ] + ] + }, + "fill-antialias": false + }, + "metadata": { + "mapbox:group": "1444855815295.714" + } + }, + { + "id": "hillshade_shadow_faint", + "type": "fill", + "source": "composite", + "source-layer": "hillshade", + "filter": [ + "==", + "level", + 89 + ], + "maxzoom": 17, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#5a5517", + "fill-opacity": { + "stops": [ + [ + 15, + 0.05 + ], + [ + 17, + 0 + ] + ] + }, + "fill-antialias": false + }, + "metadata": { + "mapbox:group": "1444855815295.714" + } + }, + { + "id": "hillshade_shadow_med", + "type": "fill", + "source": "composite", + "source-layer": "hillshade", + "filter": [ + "==", + "level", + 78 + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#5a5517", + "fill-opacity": { + "stops": [ + [ + 15, + 0.05 + ], + [ + 17, + 0 + ] + ] + }, + "fill-antialias": false + }, + "metadata": { + "mapbox:group": "1444855815295.714" + } + }, + { + "id": "hillshade_shadow_dark", + "type": "fill", + "source": "composite", + "source-layer": "hillshade", + "filter": [ + "==", + "level", + 67 + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#5a5517", + "fill-opacity": { + "stops": [ + [ + 15, + 0.06 + ], + [ + 17, + 0 + ] + ] + }, + "fill-antialias": false + }, + "metadata": { + "mapbox:group": "1444855815295.714" + } + }, + { + "id": "hillshade_shadow_extreme", + "type": "fill", + "source": "composite", + "source-layer": "hillshade", + "filter": [ + "==", + "level", + 56 + ], + "maxzoom": 17, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#5a5517", + "fill-opacity": { + "stops": [ + [ + 15, + 0.06 + ], + [ + 17, + 0 + ] + ] + }, + "fill-antialias": false + }, + "metadata": { + "mapbox:group": "1444855815295.714" + } + }, + { + "id": "waterway-river-canal", + "type": "line", + "source": "composite", + "source-layer": "waterway", + "filter": [ + "any", + [ + "==", + "class", + "river" + ], + [ + "==", + "class", + "canal" + ] + ], + "minzoom": 8, + "layout": { + "visibility": "visible", + "line-cap": { + "base": 1, + "stops": [ + [ + 0, + "butt" + ], + [ + 11, + "round" + ] + ] + }, + "line-join": "round" + }, + "paint": { + "line-color": "#8ccbf7", + "line-width": { + "base": 1.3, + "stops": [ + [ + 8.5, + 0.1 + ], + [ + 20, + 8 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 8, + 0 + ], + [ + 8.5, + 1 + ] + ] + } + } + }, + { + "id": "waterway-small", + "type": "line", + "source": "composite", + "source-layer": "waterway", + "filter": [ + "all", + [ + "!=", + "class", + "river" + ], + [ + "!=", + "class", + "canal" + ] + ], + "minzoom": 13, + "layout": { + "visibility": "visible", + "line-join": "round", + "line-cap": "round" + }, + "paint": { + "line-color": "#8ccbf7", + "line-width": { + "base": 1.35, + "stops": [ + [ + 13.5, + 0.1 + ], + [ + 20, + 3 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 13, + 0 + ], + [ + 13.5, + 1 + ] + ] + } + } + }, + { + "id": "water", + "type": "fill", + "source": "composite", + "source-layer": "water", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#8ccbf7" + } + }, + { + "id": "landuse-overlay", + "type": "fill", + "source": "composite", + "source-layer": "landuse_overlay", + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#9DD3D8", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 10, + 0.25 + ], + [ + 10.5, + 0.15 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444934749452.0452" + } + }, + { + "id": "landuse-overlay-pattern", + "ref": "landuse-overlay", + "paint": { + "fill-color": "#9DD3D8", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 10, + 0 + ], + [ + 10.5, + 1 + ] + ] + }, + "fill-pattern": "marsh-16", + "fill-translate-anchor": "viewport" + }, + "metadata": { + "mapbox:group": "1444934749452.0452" + } + }, + { + "id": "barrier_line-land-polygon", + "type": "fill", + "source": "composite", + "source-layer": "barrier_line", + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "==", + "class", + "land" + ] + ], + "layout": {}, + "paint": { + "fill-color": "#ede9d9" + } + }, + { + "id": "barrier_line-land-line", + "type": "line", + "source": "composite", + "source-layer": "barrier_line", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "land" + ] + ], + "layout": { + "line-cap": "round" + }, + "paint": { + "line-width": { + "base": 1.99, + "stops": [ + [ + 14, + 0.75 + ], + [ + 20, + 40 + ] + ] + }, + "line-color": "#ede9d9" + } + }, + { + "id": "building-line", + "type": "line", + "source": "composite", + "source-layer": "building", + "minzoom": 15, + "layout": { + "visibility": "visible" + }, + "paint": { + "line-color": "#d0cbbb", + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 0.75 + ], + [ + 20, + 3 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 15.5, + 0 + ], + [ + 16, + 1 + ] + ] + } + } + }, + { + "id": "building", + "type": "fill", + "source": "composite", + "source-layer": "building", + "minzoom": 15, + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [ + 15, + "#ede9d9" + ], + [ + 16, + "#e8e0cc" + ] + ] + }, + "fill-opacity": { + "base": 1, + "stops": [ + [ + 15.5, + 0 + ], + [ + 16, + 1 + ] + ] + }, + "fill-outline-color": "#d0cbbb" + } + }, + { + "id": "aeroway-polygon", + "type": "fill", + "source": "composite", + "source-layer": "aeroway", + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "!=", + "type", + "apron" + ] + ], + "minzoom": 11, + "layout": {}, + "paint": { + "fill-color": "#dbcedb", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 11, + 0 + ], + [ + 11.5, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444934828655.3389" + } + }, + { + "id": "aeroway-runway", + "type": "line", + "source": "composite", + "source-layer": "aeroway", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "type", + "runway" + ] + ], + "minzoom": 9, + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": "#dbcedb", + "line-width": { + "base": 1.5, + "stops": [ + [ + 9, + 1 + ], + [ + 18, + 80 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444934828655.3389" + } + }, + { + "id": "aeroway-taxiway", + "type": "line", + "source": "composite", + "source-layer": "aeroway", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "type", + "taxiway" + ] + ], + "minzoom": 9, + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": "#dbcedb", + "line-width": { + "base": 1.5, + "stops": [ + [ + 10, + 0.5 + ], + [ + 18, + 20 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444934828655.3389" + } + }, + { + "id": "tunnel-street_limited-polygon", + "type": "fill", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "==", + "class", + "street_limited" + ] + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#EEE8E3", + "fill-opacity": 0.75 + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-path", + "type": "line", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "==", + "class", + "path" + ], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 1 + ], + [ + 18, + 4 + ] + ] + }, + "line-dasharray": { + "base": 1, + "stops": [ + [ + 15, + [ + 0.1, + 1.25 + ] + ], + [ + 16, + [ + 0.1, + 1.6 + ] + ], + [ + 17, + [ + 0.1, + 1.45 + ] + ], + [ + 18, + [ + 0.1, + 1.3 + ] + ] + ] + }, + "line-color": "#f5f2ee", + "line-opacity": { + "base": 1, + "stops": [ + [ + 15, + 0 + ], + [ + 15.25, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-street-low", + "type": "line", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "street" + ] + ], + "minzoom": 11, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "#fff", + "line-opacity": { + "stops": [ + [ + 11.5, + 0 + ], + [ + 12, + 1 + ], + [ + 14, + 1 + ], + [ + 14.01, + 0 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-street_limited-low", + "type": "line", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "street_limited" + ] + ], + "minzoom": 11, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "#fff", + "line-opacity": { + "stops": [ + [ + 11.5, + 0 + ], + [ + 12, + 1 + ], + [ + 14, + 1 + ], + [ + 14.01, + 0 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-motorway_link-case", + "type": "line", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "==", + "class", + "motorway_link" + ], + "minzoom": 11, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "#fff", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-dasharray": [ + 3, + 3 + ] + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-service-driveway-case", + "type": "line", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "in", + "class", + "service", + "driveway" + ], + "minzoom": 15, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "#c4beb7", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + }, + "line-dasharray": [ + 3, + 3 + ] + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-street_limited-case", + "type": "line", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "!=", + "type", + "construction" + ] + ] + ], + "minzoom": 11, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "#c4beb7", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 2 + ], + [ + 18, + 12 + ] + ] + }, + "line-dasharray": [ + 3, + 3 + ], + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-street-case", + "type": "line", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "==", + "class", + "street" + ], + "minzoom": 11, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "#c4beb7", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-dasharray": [ + 3, + 3 + ], + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-main-case", + "type": "line", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "all", + [ + "==", + "class", + "main" + ], + [ + "!=", + "type", + "trunk" + ] + ], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.2, + "stops": [ + [ + 10, + 0.75 + ], + [ + 18, + 2 + ] + ] + }, + "line-dasharray": [ + 3, + 3 + ], + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 8.5, + 0.5 + ], + [ + 10, + 0.75 + ], + [ + 18, + 26 + ] + ] + }, + "line-color": "#c4beb7" + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-trunk-case", + "type": "line", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "all", + [ + "==", + "class", + "main" + ], + [ + "==", + "type", + "trunk" + ] + ], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "#fff", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-opacity": 1, + "line-dasharray": [ + 3, + 3 + ] + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-motorway-case", + "type": "line", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "==", + "class", + "motorway" + ], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "#fff", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-opacity": 1, + "line-dasharray": [ + 3, + 3 + ] + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-motorway_link", + "ref": "tunnel-motorway_link-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "#ffbe8c", + "line-opacity": 1, + "line-dasharray": [ + 1, + 0 + ] + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-service-driveway", + "ref": "tunnel-service-driveway-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "#fff", + "line-dasharray": [ + 1, + 0 + ] + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-construction", + "type": "line", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "type", + "construction" + ] + ] + ], + "minzoom": 14, + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "#d9d3c9", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + }, + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 0.4, + 0.8 + ] + ], + [ + 15, + [ + 0.3, + 0.6 + ] + ], + [ + 16, + [ + 0.2, + 0.3 + ] + ], + [ + 17, + [ + 0.2, + 0.25 + ] + ], + [ + 18, + [ + 0.15, + 0.15 + ] + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-street_limited", + "ref": "tunnel-street_limited-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "#EFEDEB", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-street", + "ref": "tunnel-street-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "#fff", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-main", + "ref": "tunnel-main-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 8.5, + 0.5 + ], + [ + 10, + 0.75 + ], + [ + 18, + 26 + ] + ] + }, + "line-color": "#fff", + "line-opacity": 1, + "line-dasharray": [ + 1, + 0 + ], + "line-blur": 0 + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-oneway-arrows-other", + "type": "symbol", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "in", + "class", + "main", + "street", + "street_limited" + ], + [ + "!=", + "type", + "trunk" + ] + ], + "minzoom": 15, + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-spaced-small" + ], + [ + 17, + "oneway-spaced-large" + ] + ] + }, + "icon-ignore-placement": false, + "symbol-spacing": 250, + "icon-allow-overlap": false, + "icon-padding": 2 + }, + "paint": {}, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-trunk", + "ref": "tunnel-trunk-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": "#f2de9e" + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-oneway-arrows-trunk", + "type": "symbol", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "==", + "type", + "trunk" + ] + ], + "minzoom": 15, + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-spaced-white-small" + ], + [ + 17, + "oneway-spaced-white-large" + ] + ] + }, + "icon-ignore-placement": false, + "symbol-spacing": 250, + "icon-allow-overlap": false, + "icon-padding": 2 + }, + "paint": {}, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-motorway", + "ref": "tunnel-motorway-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-dasharray": [ + 1, + 0 + ], + "line-opacity": 1, + "line-color": "#ffbe8c", + "line-blur": 0 + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-rail", + "type": "line", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "in", + "class", + "major_rail", + "minor_rail" + ], + "minzoom": 13, + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": { + "stops": [ + [ + 13, + "#d8d5c8" + ], + [ + 16, + "#c0beb2" + ] + ] + }, + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 20, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-rail-tracks", + "ref": "tunnel-rail", + "paint": { + "line-color": { + "stops": [ + [ + 13, + "#d8d5c8" + ], + [ + 16, + "#c0beb2" + ] + ] + }, + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 4 + ], + [ + 20, + 8 + ] + ] + }, + "line-dasharray": [ + 0.1, + 15 + ], + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.75, + 0 + ], + [ + 20, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "tunnel-oneway-arrows-motorway", + "type": "symbol", + "source": "composite", + "source-layer": "tunnel", + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "in", + "class", + "motorway", + "motorway_link" + ] + ], + "minzoom": 15, + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-spaced-white-small" + ], + [ + 17, + "oneway-spaced-white-large" + ] + ] + }, + "icon-ignore-placement": false, + "symbol-spacing": 250, + "icon-allow-overlap": false, + "icon-padding": 2 + }, + "paint": {}, + "metadata": { + "mapbox:group": "1444855769305.6016" + } + }, + { + "id": "road-path-bg", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "==", + "class", + "path" + ], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 2 + ], + [ + 18, + 7 + ] + ] + }, + "line-dasharray": [ + 1, + 0 + ], + "line-color": "#d9d3c9", + "line-blur": 0, + "line-opacity": { + "base": 1, + "stops": [ + [ + 15, + 0 + ], + [ + 15.25, + 0.5 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-path", + "ref": "road-path-bg", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 1 + ], + [ + 18, + 4 + ] + ] + }, + "line-color": "#fff", + "line-dasharray": { + "base": 1, + "stops": [ + [ + 15, + [ + 0.1, + 1.25 + ] + ], + [ + 16, + [ + 0.1, + 1.6 + ] + ], + [ + 17, + [ + 0.1, + 1.45 + ] + ], + [ + 18, + [ + 0.1, + 1.3 + ] + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 15, + 0 + ], + [ + 15.25, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-street-low", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "street" + ] + ], + "minzoom": 11, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "#fff", + "line-opacity": { + "stops": [ + [ + 11, + 0 + ], + [ + 11.25, + 1 + ], + [ + 14, + 1 + ], + [ + 14.01, + 0 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-street_limited-low", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "street_limited" + ] + ], + "minzoom": 11, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "#fff", + "line-opacity": { + "stops": [ + [ + 11, + 0 + ], + [ + 11.25, + 1 + ], + [ + 14, + 1 + ], + [ + 14.01, + 0 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-motorway_link-case", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "==", + "class", + "motorway_link" + ], + "minzoom": 10, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "#fff", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 10.99, + 0 + ], + [ + 11, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-service-driveway-case", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "in", + "class", + "service", + "driveway" + ], + "minzoom": 15, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "#d9d3c9", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-street_limited-case", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "!=", + "type", + "construction" + ] + ] + ], + "minzoom": 11, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "#d9d3c9", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 2 + ], + [ + 18, + 12 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-street-case", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "==", + "class", + "street" + ], + "minzoom": 11, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "#d9d3c9", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-main-case", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "class", + "main" + ], + [ + "!=", + "type", + "trunk" + ] + ], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.2, + "stops": [ + [ + 10, + 0.75 + ], + [ + 18, + 2 + ] + ] + }, + "line-color": "#d9d3c9", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 8.5, + 0.5 + ], + [ + 10, + 0.75 + ], + [ + 18, + 26 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 9.99, + 0 + ], + [ + 10, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-trunk-case", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "class", + "main" + ], + [ + "==", + "type", + "trunk" + ] + ], + "minzoom": 5, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "#fff", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 5.9, + 0 + ], + [ + 6, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-motorway-case", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "==", + "class", + "motorway" + ], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "#fff", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-opacity": { + "base": 1.2, + "stops": [ + [ + 5.9, + 0 + ], + [ + 6, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-service-driveway", + "ref": "road-service-driveway-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "#fff" + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-motorway_link", + "ref": "road-motorway_link-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "#ffa159", + "line-opacity": 1 + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-street_limited", + "ref": "road-street_limited-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "#EFEDEB", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-street", + "ref": "road-street-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "#fff", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-main", + "ref": "road-main-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 8.5, + 0.5 + ], + [ + 10, + 0.75 + ], + [ + 18, + 26 + ] + ] + }, + "line-color": { + "base": 1, + "stops": [ + [ + 5, + "#ede9d9" + ], + [ + 8, + "#fff" + ] + ] + }, + "line-opacity": { + "base": 1.2, + "stops": [ + [ + 5, + 0 + ], + [ + 5.5, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-oneway-arrows-other", + "type": "symbol", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "in", + "class", + "main", + "street", + "street_limited" + ], + [ + "!=", + "type", + "trunk" + ] + ], + "minzoom": 15, + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-spaced-small" + ], + [ + 17, + "oneway-spaced-large" + ] + ] + }, + "icon-ignore-placement": false, + "icon-rotation-alignment": "map", + "icon-padding": 2, + "symbol-spacing": 250, + "icon-allow-overlap": false + }, + "paint": {}, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-trunk", + "ref": "road-trunk-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": "#f2cf60" + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-oneway-arrows-trunk", + "type": "symbol", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "==", + "type", + "trunk" + ] + ], + "minzoom": 15, + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-spaced-white-small" + ], + [ + 17, + "oneway-spaced-white-large" + ] + ] + }, + "icon-ignore-placement": false, + "icon-padding": 2, + "symbol-spacing": 250, + "icon-allow-overlap": false + }, + "paint": {}, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-motorway", + "ref": "road-motorway-case", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": { + "base": 1, + "stops": [ + [ + 5.9, + "#fff" + ], + [ + 6, + "#ffa159" + ] + ] + }, + "line-opacity": { + "base": 1.2, + "stops": [ + [ + 5, + 0 + ], + [ + 5.5, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-rail", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "in", + "class", + "major_rail", + "minor_rail" + ], + "minzoom": 13, + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": { + "stops": [ + [ + 13, + "#d8d5c8" + ], + [ + 16, + "#b3b1a6" + ] + ] + }, + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 20, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-rail-tracks", + "ref": "road-rail", + "paint": { + "line-color": { + "stops": [ + [ + 13, + "#d8d5c8" + ], + [ + 16, + "#b3b1a6" + ] + ] + }, + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 4 + ], + [ + 20, + 8 + ] + ] + }, + "line-dasharray": [ + 0.1, + 15 + ], + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.75, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-construction", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "type", + "construction" + ] + ] + ], + "minzoom": 14, + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "#d9d3c9", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + }, + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 0.4, + 0.8 + ] + ], + [ + 15, + [ + 0.3, + 0.6 + ] + ], + [ + 16, + [ + 0.2, + 0.3 + ] + ], + [ + 17, + [ + 0.2, + 0.25 + ] + ], + [ + 18, + [ + 0.15, + 0.15 + ] + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "road-oneway-arrows-motorway", + "type": "symbol", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "in", + "class", + "motorway", + "motorway_link" + ] + ], + "minzoom": 15, + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-spaced-white-small" + ], + [ + 17, + "oneway-spaced-white-large" + ] + ] + }, + "icon-ignore-placement": false, + "icon-padding": 2, + "symbol-spacing": 250, + "icon-allow-overlap": false + }, + "paint": {}, + "metadata": { + "mapbox:group": "1444855786460.0557" + } + }, + { + "id": "bridge-street_limited-polygon", + "type": "fill", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "==", + "class", + "street_limited" + ] + ], + "layout": { + "visibility": "visible" + }, + "paint": { + "fill-color": "#EEE8E3", + "fill-opacity": 0.75 + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-path-bg", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "==", + "class", + "path" + ], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 2 + ], + [ + 18, + 7 + ] + ] + }, + "line-dasharray": [ + 1, + 0 + ], + "line-color": "#d9d3c9", + "line-blur": 0, + "line-opacity": { + "base": 1, + "stops": [ + [ + 15, + 0 + ], + [ + 15.25, + 0.75 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-path", + "ref": "bridge-path-bg", + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 1 + ], + [ + 18, + 4 + ] + ] + }, + "line-color": "#fff", + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 0.1, + 1.25 + ] + ], + [ + 16, + [ + 0.1, + 1.6 + ] + ], + [ + 17, + [ + 0.1, + 1.45 + ] + ], + [ + 18, + [ + 0.1, + 1.3 + ] + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 15, + 0 + ], + [ + 15.25, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-street-low", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "street" + ] + ], + "minzoom": 11, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "#fff", + "line-opacity": { + "stops": [ + [ + 11.5, + 0 + ], + [ + 12, + 1 + ], + [ + 14, + 1 + ], + [ + 14.01, + 0 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-street_limited-low", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "street_limited" + ] + ], + "minzoom": 11, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "#fff", + "line-opacity": { + "stops": [ + [ + 11.5, + 0 + ], + [ + 12, + 1 + ], + [ + 14, + 1 + ], + [ + 14.01, + 0 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-motorway_link-case", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "==", + "class", + "motorway_link" + ], + "minzoom": 12, + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "#fff", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": 1 + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-service-driveway-case", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "in", + "class", + "service", + "driveway" + ], + "minzoom": 15, + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "#d9d3c9", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-street_limited-case", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "!=", + "type", + "construction" + ] + ] + ], + "minzoom": 14, + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "#d9d3c9", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 2 + ], + [ + 18, + 12 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-street-case", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "==", + "class", + "street" + ], + "minzoom": 14, + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "#d9d3c9", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-main-case", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "all", + [ + "==", + "class", + "main" + ], + [ + "!=", + "type", + "trunk" + ] + ], + "minzoom": 8, + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.2, + "stops": [ + [ + 10, + 0.75 + ], + [ + 18, + 2 + ] + ] + }, + "line-color": "#d9d3c9", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 8.5, + 0.5 + ], + [ + 10, + 0.75 + ], + [ + 18, + 26 + ] + ] + }, + "line-translate": [ + 0, + 0 + ] + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-oneway-arrows-other", + "type": "symbol", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "in", + "class", + "main", + "street", + "street_limited" + ], + [ + "!=", + "type", + "trunk" + ] + ], + "minzoom": 15, + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-spaced-small" + ], + [ + 17, + "oneway-spaced-large" + ] + ] + }, + "icon-ignore-placement": false, + "symbol-spacing": 250, + "icon-allow-overlap": false, + "icon-rotation-alignment": "map", + "icon-padding": 2 + }, + "paint": {}, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-motorway-trunk-case", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "any", + [ + "==", + "class", + "motorway" + ], + [ + "==", + "type", + "trunk" + ] + ], + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "#fff", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-motorway_link", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "==", + "class", + "motorway_link" + ], + "minzoom": 10, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "#ffa159" + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-service-driveway", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "in", + "class", + "service", + "driveway" + ], + "minzoom": 15, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "#fff" + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-construction", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "type", + "construction" + ] + ] + ], + "minzoom": 14, + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "#d9d3c9", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + }, + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 0.4, + 0.8 + ] + ], + [ + 15, + [ + 0.3, + 0.6 + ] + ], + [ + 16, + [ + 0.2, + 0.3 + ] + ], + [ + 17, + [ + 0.2, + 0.25 + ] + ], + [ + 18, + [ + 0.15, + 0.15 + ] + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-street_limited", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "!=", + "type", + "construction" + ] + ] + ], + "minzoom": 11, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "#EFEDEB", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-street", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "==", + "class", + "street" + ], + "minzoom": 11, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "#fff", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-main", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "all", + [ + "==", + "class", + "main" + ], + [ + "!=", + "type", + "trunk" + ] + ], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 8.5, + 0.5 + ], + [ + 10, + 0.75 + ], + [ + 18, + 26 + ] + ] + }, + "line-color": "#fff", + "line-opacity": { + "base": 1.2, + "stops": [ + [ + 5, + 0 + ], + [ + 5.5, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-trunk", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "all", + [ + "==", + "class", + "main" + ], + [ + "==", + "type", + "trunk" + ] + ], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": "#f2cf60" + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-oneway-arrows-trunk", + "type": "symbol", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "==", + "type", + "trunk" + ] + ], + "minzoom": 15, + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-spaced-white-small" + ], + [ + 17, + "oneway-spaced-white-large" + ] + ] + }, + "icon-ignore-placement": false, + "symbol-spacing": 250, + "icon-allow-overlap": false, + "icon-padding": 2 + }, + "paint": {}, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-motorway", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "==", + "class", + "motorway" + ], + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": "#ffa159" + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-rail", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "in", + "class", + "major_rail", + "minor_rail" + ], + "minzoom": 13, + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": { + "stops": [ + [ + 13, + "#d8d5c8" + ], + [ + 16, + "#b3b1a6" + ] + ] + }, + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 20, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-rail-tracks", + "ref": "bridge-rail", + "paint": { + "line-color": { + "stops": [ + [ + 13, + "#d8d5c8" + ], + [ + 16, + "#b3b1a6" + ] + ] + }, + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 4 + ], + [ + 20, + 8 + ] + ] + }, + "line-dasharray": [ + 0.1, + 15 + ], + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.75, + 0 + ], + [ + 20, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-aerialway", + "type": "line", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "==", + "class", + "aerialway" + ], + "minzoom": 13, + "layout": { + "visibility": "visible", + "line-cap": "butt" + }, + "paint": { + "line-color": "#b3ada6", + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 20, + 1 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "bridge-oneway-arrows-motorway", + "type": "symbol", + "source": "composite", + "source-layer": "bridge", + "filter": [ + "all", + [ + "==", + "oneway", + 1 + ], + [ + "in", + "class", + "motorway", + "motorway_link" + ] + ], + "minzoom": 15, + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-spaced-white-small" + ], + [ + 17, + "oneway-spaced-white-large" + ] + ] + }, + "icon-ignore-placement": false, + "symbol-spacing": 250, + "icon-allow-overlap": false, + "icon-padding": 2 + }, + "paint": {}, + "metadata": { + "mapbox:group": "1444855799204.86" + } + }, + { + "id": "hedges", + "type": "line", + "source": "composite", + "source-layer": "barrier_line", + "filter": [ + "==", + "class", + "hedge" + ], + "minzoom": 16, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#e2f4c2", + "line-width": { + "base": 1, + "stops": [ + [ + 16, + 1 + ], + [ + 20, + 3 + ] + ] + }, + "line-opacity": 1, + "line-dasharray": [ + 1, + 2, + 5, + 2, + 1, + 2 + ] + } + }, + { + "id": "fences", + "type": "line", + "source": "composite", + "source-layer": "barrier_line", + "filter": [ + "==", + "class", + "fence" + ], + "minzoom": 16, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#cbc6b7", + "line-width": { + "base": 1, + "stops": [ + [ + 16, + 1 + ], + [ + 20, + 3 + ] + ] + }, + "line-opacity": 1, + "line-dasharray": [ + 1, + 2, + 5, + 2, + 1, + 2 + ] + } + }, + { + "id": "gates", + "type": "line", + "source": "composite", + "source-layer": "barrier_line", + "filter": [ + "==", + "class", + "gate" + ], + "minzoom": 17, + "layout": { + "visibility": "visible", + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#cbc6b7", + "line-width": { + "base": 1, + "stops": [ + [ + 16, + 1 + ], + [ + 20, + 3 + ] + ] + }, + "line-opacity": 0.5, + "line-dasharray": [ + 1, + 2, + 5, + 2, + 1, + 2 + ] + } + }, + { + "id": "admin-3-4-boundaries-bg", + "type": "line", + "source": "composite", + "source-layer": "admin", + "filter": [ + "all", + [ + ">=", + "admin_level", + 3 + ], + [ + "==", + "maritime", + 0 + ] + ], + "layout": { + "visibility": "visible", + "line-join": "bevel" + }, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [ + 8, + "#ede9d9" + ], + [ + 16, + "#f6e8e1" + ] + ] + }, + "line-width": { + "base": 1, + "stops": [ + [ + 3, + 3.5 + ], + [ + 10, + 8 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 7, + 0 + ], + [ + 8, + 0.75 + ] + ] + }, + "line-dasharray": [ + 1, + 0 + ], + "line-translate": [ + 0, + 0 + ], + "line-blur": { + "base": 1, + "stops": [ + [ + 3, + 0 + ], + [ + 8, + 3 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444934295202.7542" + } + }, + { + "id": "admin-2-boundaries-bg", + "type": "line", + "source": "composite", + "source-layer": "admin", + "filter": [ + "all", + [ + "==", + "admin_level", + 2 + ], + [ + "==", + "maritime", + 0 + ] + ], + "minzoom": 1, + "layout": { + "visibility": "visible", + "line-join": "miter", + "line-cap": "butt" + }, + "paint": { + "line-width": { + "base": 1, + "stops": [ + [ + 3, + 3.5 + ], + [ + 10, + 10 + ] + ] + }, + "line-color": { + "base": 1, + "stops": [ + [ + 6, + "#ede9d9" + ], + [ + 8, + "#f6e8e1" + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 3, + 0 + ], + [ + 4, + 0.5 + ] + ] + }, + "line-translate": [ + 0, + 0 + ], + "line-blur": { + "base": 1, + "stops": [ + [ + 3, + 0 + ], + [ + 10, + 2 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444934295202.7542" + } + }, + { + "id": "admin-3-4-boundaries", + "type": "line", + "source": "composite", + "source-layer": "admin", + "filter": [ + "all", + [ + ">=", + "admin_level", + 3 + ], + [ + "==", + "maritime", + 0 + ] + ], + "layout": { + "visibility": "visible", + "line-join": "round", + "line-cap": "round" + }, + "paint": { + "line-dasharray": { + "base": 1, + "stops": [ + [ + 6, + [ + 2, + 0 + ] + ], + [ + 7, + [ + 2, + 2, + 6, + 2 + ] + ] + ] + }, + "line-width": { + "base": 1, + "stops": [ + [ + 7, + 0.75 + ], + [ + 12, + 1.5 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 2, + 0 + ], + [ + 3, + 1 + ] + ] + }, + "line-color": { + "base": 1, + "stops": [ + [ + 3, + "#c3bfcc" + ], + [ + 7, + "#aba8b3" + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444934295202.7542" + } + }, + { + "id": "admin-2-boundaries", + "type": "line", + "source": "composite", + "source-layer": "admin", + "filter": [ + "all", + [ + "==", + "admin_level", + 2 + ], + [ + "==", + "maritime", + 0 + ], + [ + "==", + "disputed", + 0 + ] + ], + "minzoom": 1, + "layout": { + "visibility": "visible", + "line-join": "round", + "line-cap": "round" + }, + "paint": { + "line-color": "#787680", + "line-width": { + "base": 1, + "stops": [ + [ + 3, + 0.5 + ], + [ + 10, + 2 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444934295202.7542" + } + }, + { + "id": "admin-2-boundaries-dispute", + "type": "line", + "source": "composite", + "source-layer": "admin", + "filter": [ + "all", + [ + "==", + "admin_level", + 2 + ], + [ + "==", + "maritime", + 0 + ], + [ + "==", + "disputed", + 1 + ] + ], + "minzoom": 1, + "layout": { + "visibility": "visible", + "line-cap": "butt", + "line-join": "round" + }, + "paint": { + "line-dasharray": [ + 1.5, + 1.5 + ], + "line-color": "#787680", + "line-width": { + "base": 1, + "stops": [ + [ + 3, + 0.5 + ], + [ + 10, + 2 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444934295202.7542" + } + }, + { + "id": "contour", + "type": "line", + "source": "composite", + "source-layer": "contour", + "filter": [ + "!in", + "index", + -1, + 5, + 10 + ], + "minzoom": 14, + "layout": { + "visibility": "visible" + }, + "paint": { + "line-opacity": 0.07, + "line-color": "#66601a" + }, + "metadata": { + "mapbox:group": "1444933837268.9458" + } + }, + { + "id": "contour-index", + "type": "line", + "source": "composite", + "source-layer": "contour", + "filter": [ + "==", + "index", + 5, + 10 + ], + "minzoom": 14, + "layout": { + "visibility": "visible" + }, + "paint": { + "line-opacity": 0.12, + "line-color": "#66601a" + }, + "metadata": { + "mapbox:group": "1444933837268.9458" + } + }, + { + "id": "housenum-label", + "type": "symbol", + "source": "composite", + "source-layer": "housenum_label", + "minzoom": 17, + "layout": { + "visibility": "visible", + "text-field": "{house_num}", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "symbol-placement": "point", + "text-padding": 4, + "text-max-width": 7, + "text-size": 9.5 + }, + "paint": { + "text-color": "#b2aca5", + "text-halo-color": "#e8e0cc", + "text-halo-width": 1.5, + "text-halo-blur": 0 + } + }, + { + "id": "contour-index-label", + "type": "symbol", + "source": "composite", + "source-layer": "contour", + "filter": [ + "==", + "index", + 5, + 10 + ], + "minzoom": 14, + "layout": { + "text-field": "{ele} m", + "symbol-placement": "line", + "text-max-angle": 25, + "visibility": "visible", + "text-padding": 5, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-size": 9.5 + }, + "paint": { + "text-color": "#a7a696", + "text-halo-width": 1, + "text-halo-blur": 1, + "text-halo-color": "rgba(237,233,217, 0.25)" + } + }, + { + "id": "waterway-label", + "type": "symbol", + "source": "composite", + "source-layer": "waterway_label", + "filter": [ + "==", + "class", + "river" + ], + "minzoom": 12, + "layout": { + "text-field": "{name_en}", + "visibility": "visible", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-max-angle": 30, + "text-size": { + "base": 1, + "stops": [ + [ + 13, + 12 + ], + [ + 18, + 16 + ] + ] + } + }, + "paint": { + "text-halo-width": 0.5, + "text-halo-color": "#ffffff", + "text-color": "#004087", + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-scalerank4-l15", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "rail-light", + "rail-metro", + "rail", + "airport", + "airfield", + "heliport", + "rocket", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "==", + "scalerank", + 4 + ], + [ + ">=", + "localrank", + 15 + ] + ], + "minzoom": 17, + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 11 + ], + [ + 20, + 13 + ] + ] + }, + "text-allow-overlap": false, + "icon-image": "{maki}-11", + "text-ignore-placement": false, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [ + 0, + 1 + ], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "#65513d", + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "mapbox:group": "1444933456003.5437" + } + }, + { + "id": "poi-scalerank4-l1", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "interactive": true, + "filter": [ + "all", + [ + "!in", + "maki", + "rail-light", + "rail-metro", + "rail", + "airport", + "airfield", + "heliport", + "rocket", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "==", + "scalerank", + 4 + ], + [ + "<=", + "localrank", + 14 + ] + ], + "minzoom": 16, + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 11 + ], + [ + 20, + 13 + ] + ] + }, + "text-allow-overlap": false, + "icon-image": "{maki}-11", + "text-ignore-placement": false, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "symbol-placement": "point", + "text-padding": 1, + "visibility": "visible", + "text-offset": [ + 0, + 1 + ], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "#65513d", + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "mapbox:group": "1444933456003.5437" + } + }, + { + "id": "poi-parks_scalerank4", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "in", + "maki", + "park", + "cemetery", + "golf", + "zoo", + "playground" + ], + [ + "==", + "scalerank", + 4 + ] + ], + "minzoom": 16, + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 11 + ], + [ + 20, + 13 + ] + ] + }, + "text-allow-overlap": false, + "icon-image": "{maki}-11", + "text-ignore-placement": false, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "symbol-placement": "point", + "text-padding": 1, + "visibility": "visible", + "text-offset": [ + 0, + 1 + ], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "#4c661f", + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "mapbox:group": "1444933456003.5437" + } + }, + { + "id": "poi-scalerank3", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "rail-light", + "rail-metro", + "rail", + "airport", + "airfield", + "heliport", + "rocket", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "==", + "scalerank", + 3 + ] + ], + "minzoom": 15, + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 11 + ], + [ + 20, + 13 + ] + ] + }, + "text-allow-overlap": false, + "icon-image": "{maki}-11", + "text-ignore-placement": false, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "symbol-placement": "point", + "text-padding": 1, + "visibility": "visible", + "text-offset": [ + 0, + 1 + ], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "#65513d", + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "mapbox:group": "1444933372896.5967" + } + }, + { + "id": "poi-parks-scalerank3", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "in", + "maki", + "park", + "cemetery", + "golf", + "zoo" + ], + [ + "==", + "scalerank", + 3 + ] + ], + "minzoom": 15, + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 11 + ], + [ + 20, + 13 + ] + ] + }, + "text-allow-overlap": false, + "icon-image": "{maki}-11", + "text-ignore-placement": false, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [ + 0, + 1 + ], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "#4c661f", + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "mapbox:group": "1444933372896.5967" + } + }, + { + "id": "road-label-small", + "type": "symbol", + "source": "composite", + "source-layer": "road_label", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "!in", + "class", + "motorway", + "main", + "street_limited", + "street" + ] + ], + "minzoom": 15, + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 15, + 10 + ], + [ + 20, + 13 + ] + ] + }, + "text-ignore-placement": false, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-padding": 1, + "visibility": "visible", + "text-rotation-alignment": "map", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "#3a3836", + "text-halo-color": "#ffffff", + "text-halo-width": 1.25, + "text-halo-blur": 1 + }, + "metadata": { + "mapbox:group": "1444933721429.3076" + } + }, + { + "id": "road-label-medium", + "type": "symbol", + "source": "composite", + "source-layer": "road_label", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "street", + "street_limited" + ] + ], + "minzoom": 11, + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 11, + 10 + ], + [ + 20, + 14 + ] + ] + }, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-padding": 1, + "visibility": "visible", + "text-rotation-alignment": "map", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "#3a3836", + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "mapbox:group": "1444933721429.3076" + } + }, + { + "id": "road-label-large", + "type": "symbol", + "source": "composite", + "source-layer": "road_label", + "filter": [ + "in", + "class", + "main", + "motorway" + ], + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 9, + 10 + ], + [ + 20, + 16 + ] + ] + }, + "text-allow-overlap": false, + "text-ignore-placement": false, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-padding": 1, + "visibility": "visible", + "text-rotation-alignment": "map", + "text-keep-upright": true, + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "#3a3836", + "text-halo-color": "rgba(255,255,255, 0.75)", + "text-halo-width": 1, + "text-halo-blur": 1 + }, + "metadata": { + "mapbox:group": "1444933721429.3076" + } + }, + { + "id": "road-other-shields", + "type": "symbol", + "source": "composite", + "source-layer": "road_label", + "filter": [ + "all", + [ + "!in", + "shield", + "us-interstate", + "us-interstate-business", + "us-interstate-duplex" + ], + [ + "<=", + "reflen", + 6 + ] + ], + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 9 + ], + [ + 16.01, + 11 + ] + ] + }, + "text-allow-overlap": false, + "icon-image": { + "base": 1, + "stops": [ + [ + 0, + "{shield}-{reflen}-small" + ], + [ + 16, + "{shield}-{reflen}-large" + ] + ] + }, + "icon-rotation-alignment": "viewport", + "symbol-avoid-edges": false, + "text-ignore-placement": false, + "text-max-angle": 38, + "symbol-spacing": { + "base": 1, + "stops": [ + [ + 11, + 100 + ], + [ + 14, + 200 + ] + ] + }, + "text-font": [ + "DIN Offc Pro Bold", + "Arial Unicode MS Bold" + ], + "symbol-placement": { + "base": 1, + "stops": [ + [ + 10, + "point" + ], + [ + 11, + "line" + ] + ] + }, + "text-padding": 2, + "visibility": "visible", + "text-rotation-alignment": "viewport", + "text-field": "{ref}", + "text-letter-spacing": 0.05, + "icon-padding": 2 + }, + "paint": { + "text-color": "#3a3836", + "icon-halo-color": "rgba(0, 0, 0, 1)", + "icon-halo-width": 1, + "text-opacity": 1, + "icon-color": "white", + "text-halo-color": "#ffffff", + "text-halo-width": 0 + }, + "metadata": { + "mapbox:group": "1444933575858.6992" + } + }, + { + "id": "road-interstate-shields", + "type": "symbol", + "source": "composite", + "source-layer": "road_label", + "filter": [ + "all", + [ + "in", + "shield", + "us-interstate", + "us-interstate-business", + "us-interstate-duplex" + ], + [ + "<=", + "reflen", + 6 + ] + ], + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 9 + ], + [ + 16.01, + 11 + ] + ] + }, + "text-allow-overlap": false, + "icon-image": { + "base": 1, + "stops": [ + [ + 0, + "{shield}-{reflen}-small" + ], + [ + 16, + "{shield}-{reflen}-large" + ] + ] + }, + "icon-rotation-alignment": "viewport", + "symbol-avoid-edges": false, + "text-ignore-placement": false, + "text-max-angle": 38, + "symbol-spacing": { + "base": 1, + "stops": [ + [ + 11, + 100 + ], + [ + 14, + 200 + ] + ] + }, + "text-font": [ + "DIN Offc Pro Bold", + "Arial Unicode MS Bold" + ], + "symbol-placement": { + "base": 1, + "stops": [ + [ + 10, + "point" + ], + [ + 11, + "line" + ] + ] + }, + "text-padding": 2, + "visibility": "visible", + "text-rotation-alignment": "viewport", + "text-field": "{ref}", + "text-letter-spacing": 0.05, + "icon-padding": 2 + }, + "paint": { + "text-color": "#fff", + "icon-halo-color": "rgba(0, 0, 0, 1)", + "icon-halo-width": 1, + "text-opacity": 1, + "icon-color": "white", + "text-halo-color": "#ffffff", + "text-halo-width": 0 + }, + "metadata": { + "mapbox:group": "1444933575858.6992" + } + }, + { + "id": "poi-scalerank2", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "rail-light", + "rail-metro", + "rail", + "airport", + "airfield", + "heliport", + "rocket", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "==", + "scalerank", + 2 + ] + ], + "minzoom": 13, + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 14, + 11 + ], + [ + 20, + 14 + ] + ] + }, + "text-allow-overlap": false, + "icon-image": { + "stops": [ + [ + 14, + "{maki}-11" + ], + [ + 15, + "{maki}-15" + ] + ] + }, + "text-ignore-placement": false, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [ + 0, + 1.25 + ], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "#65513d", + "text-halo-color": "#ffffff", + "text-halo-width": 1.25 + }, + "metadata": { + "mapbox:group": "1444933358918.2366" + } + }, + { + "id": "poi-parks-scalerank2", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "in", + "maki", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "==", + "scalerank", + 2 + ] + ], + "minzoom": 13, + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 14, + 11 + ], + [ + 20, + 14 + ] + ] + }, + "text-allow-overlap": false, + "icon-image": { + "stops": [ + [ + 14, + "{maki}-11" + ], + [ + 15, + "{maki}-15" + ] + ] + }, + "text-ignore-placement": false, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [ + 0, + 1.25 + ], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "#4c661f", + "text-halo-color": "#ffffff", + "text-halo-width": 1.25 + }, + "metadata": { + "mapbox:group": "1444933358918.2366" + } + }, + { + "id": "rail-label", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "==", + "type", + "Rail Station" + ], + "minzoom": 12, + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 11 + ], + [ + 20, + 13 + ] + ] + }, + "icon-image": "{network}-11", + "symbol-avoid-edges": true, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "icon-allow-overlap": false, + "symbol-placement": "point", + "text-justify": "center", + "visibility": "visible", + "text-offset": [ + 0, + 1 + ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": { + "base": 1, + "stops": [ + [ + 0, + "" + ], + [ + 13, + "{name_en}" + ] + ] + }, + "text-letter-spacing": 0.02, + "icon-padding": 0, + "text-max-width": 7 + }, + "paint": { + "text-color": "#65513d", + "text-halo-color": "#ffffff", + "text-halo-width": 1.5, + "icon-halo-width": 4, + "icon-halo-color": "#fff", + "text-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + } + }, + { + "id": "water-label-sm", + "type": "symbol", + "source": "composite", + "source-layer": "water_label", + "filter": [ + "<=", + "area", + 10000 + ], + "minzoom": 15, + "layout": { + "text-field": "{name_en}", + "visibility": "visible", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-max-width": 7, + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 13 + ], + [ + 20, + 16 + ] + ] + } + }, + "paint": { + "text-halo-width": 0, + "text-halo-color": "#ffffff", + "text-color": "#004087", + "text-halo-blur": 1.5 + }, + "metadata": { + "mapbox:group": "1444933808272.805" + } + }, + { + "id": "water-label", + "type": "symbol", + "source": "composite", + "source-layer": "water_label", + "filter": [ + ">", + "area", + 10000 + ], + "minzoom": 5, + "layout": { + "text-field": "{name_en}", + "visibility": "visible", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-max-width": 7, + "text-size": { + "base": 1, + "stops": [ + [ + 13, + 13 + ], + [ + 18, + 18 + ] + ] + } + }, + "paint": { + "text-halo-width": 0, + "text-halo-color": "#ffffff", + "text-color": "#004087", + "text-halo-blur": 1.5 + }, + "metadata": { + "mapbox:group": "1444933808272.805" + } + }, + { + "id": "poi-parks-scalerank1", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "in", + "maki", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "<=", + "scalerank", + 1 + ] + ], + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 10, + 11 + ], + [ + 18, + 14 + ] + ] + }, + "text-allow-overlap": false, + "icon-image": { + "stops": [ + [ + 13, + "{maki}-11" + ], + [ + 14, + "{maki}-15" + ] + ] + }, + "text-ignore-placement": false, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [ + 0, + 1 + ], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "#4c661f", + "text-halo-color": "#ffffff", + "text-halo-width": 1, + "text-halo-blur": 0 + }, + "metadata": { + "mapbox:group": "1444933322393.2852" + } + }, + { + "id": "poi-scalerank1", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "rail-light", + "rail-metro", + "rail", + "airport", + "airfield", + "heliport", + "rocket", + "park", + "golf", + "cemetery", + "zoo", + "campsite", + "swimming", + "dog-park" + ], + [ + "<=", + "scalerank", + 1 + ], + [ + "!=", + "type", + "Island" + ] + ], + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 10, + 11 + ], + [ + 18, + 14 + ] + ] + }, + "text-allow-overlap": false, + "icon-image": { + "stops": [ + [ + 13, + "{maki}-11" + ], + [ + 14, + "{maki}-15" + ] + ] + }, + "text-ignore-placement": false, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [ + 0, + 1 + ], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "#65513d", + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "mapbox:group": "1444933322393.2852" + } + }, + { + "id": "airport-label", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "in", + "maki", + "airport", + "heliport", + "rocket" + ], + [ + "<=", + "scalerank", + 2 + ] + ], + "minzoom": 9, + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 10, + 12 + ], + [ + 18, + 18 + ] + ] + }, + "text-allow-overlap": false, + "icon-image": { + "stops": [ + [ + 12, + "{maki}-11" + ], + [ + 13, + "{maki}-15" + ] + ] + }, + "text-ignore-placement": false, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": { + "base": 1, + "stops": [ + [ + 12, + [ + 0, + 1 + ] + ], + [ + 13, + [ + 0, + 1.25 + ] + ] + ] + }, + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": { + "stops": [ + [ + 12, + "{ref}" + ], + [ + 13, + "{name_en}" + ] + ] + }, + "text-letter-spacing": 0.02, + "text-max-width": 9 + }, + "paint": { + "text-color": "#000000", + "text-halo-color": "#ffffff", + "text-halo-width": 1.25 + } + }, + { + "id": "poi-islets", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "==", + "type", + "Islet" + ], + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 10, + 11 + ], + [ + 14, + 16 + ] + ] + }, + "text-allow-overlap": false, + "text-ignore-placement": false, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [ + 0, + 0 + ], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "center", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 8 + }, + "paint": { + "text-color": "#65513d", + "text-halo-color": "#ffffff", + "text-halo-width": 1 + } + }, + { + "id": "place-neighbourhood", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "filter": [ + "==", + "type", + "neighbourhood" + ], + "minzoom": 10, + "maxzoom": 16, + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-transform": "uppercase", + "text-letter-spacing": 0.1, + "text-max-width": 7, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-padding": 3, + "text-size": { + "base": 1, + "stops": [ + [ + 12, + 11 + ], + [ + 16, + 16 + ] + ] + } + }, + "paint": { + "text-halo-color": "rgba(255,255,255, 0.5)", + "text-halo-width": 1.75, + "text-color": "#805540", + "text-halo-blur": 0 + } + }, + { + "id": "place-suburb", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "filter": [ + "==", + "type", + "suburb" + ], + "minzoom": 10, + "maxzoom": 16, + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-transform": "uppercase", + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-letter-spacing": 0.15, + "text-max-width": 7, + "text-padding": 3, + "text-size": { + "base": 1, + "stops": [ + [ + 11, + 11 + ], + [ + 15, + 18 + ] + ] + } + }, + "paint": { + "text-halo-color": "rgba(255,255,255, 0.5)", + "text-halo-width": 1.75, + "text-color": "#805540" + } + }, + { + "id": "place-hamlet", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "filter": [ + "==", + "type", + "hamlet" + ], + "minzoom": 10, + "maxzoom": 16, + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-size": { + "base": 1, + "stops": [ + [ + 12, + 11.5 + ], + [ + 15, + 16 + ] + ] + } + }, + "paint": { + "text-halo-color": "#ffffff", + "text-halo-width": 1.25, + "text-color": "#000000" + } + }, + { + "id": "place-village", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "filter": [ + "==", + "type", + "village" + ], + "minzoom": 8, + "maxzoom": 15, + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-max-width": 7, + "text-size": { + "base": 1, + "stops": [ + [ + 10, + 11.5 + ], + [ + 16, + 18 + ] + ] + } + }, + "paint": { + "text-halo-color": "#ffffff", + "text-halo-width": 1.25, + "text-color": "#000000" + } + }, + { + "id": "place-town", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "filter": [ + "==", + "type", + "town" + ], + "minzoom": 6, + "maxzoom": 15, + "layout": { + "icon-image": "dot-9", + "text-font": { + "base": 1, + "stops": [ + [ + 11, + [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ] + ], + [ + 12, + [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ] + ] + ] + }, + "visibility": "visible", + "text-offset": { + "base": 1, + "stops": [ + [ + 7, + [ + 0, + -0.15 + ] + ], + [ + 8, + [ + 0, + 0 + ] + ] + ] + }, + "text-anchor": { + "base": 1, + "stops": [ + [ + 7, + "bottom" + ], + [ + 8, + "center" + ] + ] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": { + "base": 1, + "stops": [ + [ + 7, + 11.5 + ], + [ + 15, + 20 + ] + ] + } + }, + "paint": { + "text-color": "#000000", + "text-halo-color": "#ffffff", + "text-halo-width": 1.25, + "icon-opacity": { + "base": 1, + "stops": [ + [ + 7.99, + 1 + ], + [ + 8, + 0 + ] + ] + } + } + }, + { + "id": "poi-islands", + "type": "symbol", + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "==", + "type", + "Island" + ], + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 10, + 11 + ], + [ + 18, + 16 + ] + ] + }, + "text-allow-overlap": false, + "text-ignore-placement": false, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "symbol-placement": "point", + "text-padding": 2, + "visibility": "visible", + "text-offset": [ + 0, + 0 + ], + "icon-optional": false, + "text-rotation-alignment": "viewport", + "text-anchor": "center", + "text-field": "{name_en}", + "text-letter-spacing": 0.02, + "text-max-width": 7 + }, + "paint": { + "text-color": "#65513d", + "text-halo-color": "#ffffff", + "text-halo-width": 1 + } + }, + { + "id": "place-city-sm", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "filter": [ + "all", + [ + "!in", + "scalerank", + 0, + 1, + 2, + 3, + 4, + 5 + ], + [ + "==", + "type", + "city" + ] + ], + "maxzoom": 14, + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 6, + 12 + ], + [ + 14, + 22 + ] + ] + }, + "icon-image": "dot-9", + "text-transform": "none", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ] + ], + [ + 8, + [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ] + ] + ] + }, + "visibility": "visible", + "text-offset": { + "base": 1, + "stops": [ + [ + 7.99, + [ + 0, + -0.2 + ] + ], + [ + 8, + [ + 0, + 0 + ] + ] + ] + }, + "text-anchor": { + "base": 1, + "stops": [ + [ + 7, + "bottom" + ], + [ + 8, + "center" + ] + ] + }, + "text-field": "{name_en}", + "text-max-width": 7 + }, + "paint": { + "text-color": "#000000", + "text-halo-color": "#ffffff", + "text-halo-width": 1.25, + "icon-opacity": { + "base": 1, + "stops": [ + [ + 7.99, + 1 + ], + [ + 8, + 0 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444862510685.128" + } + }, + { + "id": "place-city-md-s", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "filter": [ + "all", + [ + "in", + "scalerank", + 3, + 4, + 5 + ], + [ + "==", + "type", + "city" + ], + [ + "in", + "ldir", + "S", + "SE", + "SW", + "E" + ] + ], + "maxzoom": 14, + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "icon-image": "dot-10", + "text-anchor": { + "base": 1, + "stops": [ + [ + 7, + "top" + ], + [ + 8, + "center" + ] + ] + }, + "text-offset": { + "base": 1, + "stops": [ + [ + 7.99, + [ + 0, + 0.1 + ] + ], + [ + 8, + [ + 0, + 0 + ] + ] + ] + }, + "text-font": { + "base": 1, + "stops": [ + [ + 7, + [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ] + ], + [ + 8, + [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ] + ] + ] + }, + "text-size": { + "base": 0.9, + "stops": [ + [ + 5, + 12 + ], + [ + 12, + 22 + ] + ] + } + }, + "paint": { + "text-halo-width": 1, + "text-halo-color": "#ffffff", + "text-color": "#000000", + "text-halo-blur": 1, + "icon-opacity": { + "base": 1, + "stops": [ + [ + 7.99, + 1 + ], + [ + 8, + 0 + ] + ] + } + }, + "metadata": { + "mapbox:group": "1444862510685.128" + } + }, + { + "id": "place-city-md-n", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "filter": [ + "all", + [ + "in", + "scalerank", + 3, + 4, + 5 + ], + [ + "==", + "type", + "city" + ], + [ + "in", + "ldir", + "N", + "NE", + "NW", + "W" + ] + ], + "maxzoom": 14, + "layout": { + "icon-image": "dot-10", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ] + ], + [ + 8, + [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ] + ] + ] + }, + "visibility": "visible", + "text-offset": { + "base": 1, + "stops": [ + [ + 7.99, + [ + 0, + -0.25 + ] + ], + [ + 8, + [ + 0, + 0 + ] + ] + ] + }, + "text-anchor": { + "base": 1, + "stops": [ + [ + 7, + "bottom" + ], + [ + 8, + "center" + ] + ] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": { + "base": 0.9, + "stops": [ + [ + 5, + 12 + ], + [ + 12, + 22 + ] + ] + } + }, + "paint": { + "text-color": "#000000", + "text-halo-color": "#ffffff", + "text-halo-width": 1, + "icon-opacity": { + "base": 1, + "stops": [ + [ + 7.99, + 1 + ], + [ + 8, + 0 + ] + ] + }, + "text-halo-blur": 1 + }, + "metadata": { + "mapbox:group": "1444862510685.128" + } + }, + { + "id": "place-city-lg-s", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "filter": [ + "all", + [ + "<=", + "scalerank", + 2 + ], + [ + "==", + "type", + "city" + ], + [ + "in", + "ldir", + "S", + "SE", + "SW", + "E" + ] + ], + "minzoom": 1, + "maxzoom": 14, + "layout": { + "icon-image": "dot-11", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ] + ], + [ + 8, + [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ] + ] + ] + }, + "visibility": "visible", + "text-offset": { + "base": 1, + "stops": [ + [ + 7.99, + [ + 0, + 0.15 + ] + ], + [ + 8, + [ + 0, + 0 + ] + ] + ] + }, + "text-anchor": { + "base": 1, + "stops": [ + [ + 7, + "top" + ], + [ + 8, + "center" + ] + ] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": { + "base": 0.9, + "stops": [ + [ + 4, + 12 + ], + [ + 10, + 22 + ] + ] + } + }, + "paint": { + "text-color": "#000000", + "text-halo-color": "#ffffff", + "text-halo-width": 1, + "icon-opacity": { + "base": 1, + "stops": [ + [ + 7.99, + 1 + ], + [ + 8, + 0 + ] + ] + }, + "text-halo-blur": 1 + }, + "metadata": { + "mapbox:group": "1444862510685.128" + } + }, + { + "id": "place-city-lg-n", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "filter": [ + "all", + [ + "<=", + "scalerank", + 2 + ], + [ + "==", + "type", + "city" + ], + [ + "in", + "ldir", + "N", + "NE", + "NW", + "W" + ] + ], + "minzoom": 1, + "maxzoom": 14, + "layout": { + "icon-image": "dot-11", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ] + ], + [ + 8, + [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ] + ] + ] + }, + "visibility": "visible", + "text-offset": { + "base": 1, + "stops": [ + [ + 7.99, + [ + 0, + -0.25 + ] + ], + [ + 8, + [ + 0, + 0 + ] + ] + ] + }, + "text-anchor": { + "base": 1, + "stops": [ + [ + 7, + "bottom" + ], + [ + 8, + "center" + ] + ] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": { + "base": 0.9, + "stops": [ + [ + 4, + 12 + ], + [ + 10, + 22 + ] + ] + } + }, + "paint": { + "text-color": "#000000", + "text-opacity": 1, + "text-halo-color": "#ffffff", + "text-halo-width": 1, + "icon-opacity": { + "base": 1, + "stops": [ + [ + 7.99, + 1 + ], + [ + 8, + 0 + ] + ] + }, + "text-halo-blur": 1 + }, + "metadata": { + "mapbox:group": "1444862510685.128" + } + }, + { + "id": "marine-label-sm-ln", + "type": "symbol", + "source": "composite", + "source-layer": "marine_label", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + ">=", + "labelrank", + 4 + ] + ], + "minzoom": 3, + "maxzoom": 10, + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1, + "stops": [ + [ + 3, + 12 + ], + [ + 6, + 16 + ] + ] + }, + "symbol-spacing": { + "base": 1, + "stops": [ + [ + 4, + 100 + ], + [ + 6, + 400 + ] + ] + }, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "visibility": "visible", + "text-field": "{name_en}", + "text-letter-spacing": 0.1, + "text-max-width": 5 + }, + "paint": { + "text-color": "#c8e5f9" + }, + "metadata": { + "mapbox:group": "1444856087950.3635" + } + }, + { + "id": "marine-label-sm-pt", + "type": "symbol", + "source": "composite", + "source-layer": "marine_label", + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + ">=", + "labelrank", + 4 + ] + ], + "minzoom": 3, + "maxzoom": 10, + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-max-width": 5, + "text-letter-spacing": 0.1, + "text-line-height": 1.5, + "symbol-placement": "point", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-size": { + "base": 1, + "stops": [ + [ + 3, + 12 + ], + [ + 6, + 16 + ] + ] + } + }, + "paint": { + "text-color": "#c8e5f9" + }, + "metadata": { + "mapbox:group": "1444856087950.3635" + } + }, + { + "id": "marine-label-md-ln", + "type": "symbol", + "source": "composite", + "source-layer": "marine_label", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "labelrank", + 2, + 3 + ] + ], + "minzoom": 2, + "maxzoom": 8, + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1.1, + "stops": [ + [ + 2, + 12 + ], + [ + 5, + 20 + ] + ] + }, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "visibility": "visible", + "text-field": "{name_en}", + "text-letter-spacing": 0.15, + "text-max-width": 5 + }, + "paint": { + "text-color": "#c8e5f9" + }, + "metadata": { + "mapbox:group": "1444856087950.3635" + } + }, + { + "id": "marine-label-md-pt", + "type": "symbol", + "source": "composite", + "source-layer": "marine_label", + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "in", + "labelrank", + 2, + 3 + ] + ], + "minzoom": 2, + "maxzoom": 8, + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-max-width": 5, + "text-letter-spacing": 0.15, + "text-line-height": 1.5, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-size": { + "base": 1.1, + "stops": [ + [ + 2, + 14 + ], + [ + 5, + 20 + ] + ] + } + }, + "paint": { + "text-color": "#c8e5f9" + }, + "metadata": { + "mapbox:group": "1444856087950.3635" + } + }, + { + "id": "marine-label-lg-ln", + "type": "symbol", + "source": "composite", + "source-layer": "marine_label", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "labelrank", + 1 + ] + ], + "minzoom": 1, + "maxzoom": 4, + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-max-width": 4, + "text-letter-spacing": 0.25, + "text-line-height": 1.1, + "symbol-placement": "line", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-size": { + "base": 1, + "stops": [ + [ + 1, + 14 + ], + [ + 4, + 30 + ] + ] + } + }, + "paint": { + "text-color": "#c8e5f9" + }, + "metadata": { + "mapbox:group": "1444856087950.3635" + } + }, + { + "id": "marine-label-lg-pt", + "type": "symbol", + "source": "composite", + "source-layer": "marine_label", + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "==", + "labelrank", + 1 + ] + ], + "minzoom": 1, + "maxzoom": 4, + "layout": { + "visibility": "visible", + "text-field": "{name_en}", + "text-max-width": 4, + "text-letter-spacing": 0.25, + "text-line-height": 1.5, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-size": { + "base": 1, + "stops": [ + [ + 1, + 14 + ], + [ + 4, + 30 + ] + ] + } + }, + "paint": { + "text-color": "#c8e5f9" + }, + "metadata": { + "mapbox:group": "1444856087950.3635" + } + }, + { + "id": "state-label-sm", + "type": "symbol", + "source": "composite", + "source-layer": "state_label", + "filter": [ + "<", + "area", + 20000 + ], + "minzoom": 3, + "maxzoom": 9, + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 6, + 10 + ], + [ + 9, + 14 + ] + ] + }, + "text-allow-overlap": false, + "text-ignore-placement": false, + "text-transform": "uppercase", + "text-font": [ + "DIN Offc Pro Bold", + "Arial Unicode MS Bold" + ], + "visibility": "visible", + "text-field": { + "base": 1, + "stops": [ + [ + 0, + "{abbr}" + ], + [ + 6, + "{name_en}" + ] + ] + }, + "text-letter-spacing": 0.15, + "text-max-width": 5 + }, + "paint": { + "text-opacity": 1, + "text-color": "#242424", + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "mapbox:group": "1444856151690.9143" + } + }, + { + "id": "state-label-md", + "type": "symbol", + "source": "composite", + "source-layer": "state_label", + "filter": [ + "all", + [ + "<", + "area", + 80000 + ], + [ + ">=", + "area", + 20000 + ] + ], + "minzoom": 3, + "maxzoom": 8, + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 5, + 10 + ], + [ + 8, + 16 + ] + ] + }, + "text-allow-overlap": false, + "text-ignore-placement": false, + "text-transform": "uppercase", + "text-font": [ + "DIN Offc Pro Bold", + "Arial Unicode MS Bold" + ], + "visibility": "visible", + "text-field": { + "base": 1, + "stops": [ + [ + 0, + "{abbr}" + ], + [ + 5, + "{name_en}" + ] + ] + }, + "text-letter-spacing": 0.15, + "text-max-width": 6 + }, + "paint": { + "text-opacity": 1, + "text-color": "#242424", + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "mapbox:group": "1444856151690.9143" + } + }, + { + "id": "state-label-lg", + "type": "symbol", + "source": "composite", + "source-layer": "state_label", + "filter": [ + ">=", + "area", + 80000 + ], + "minzoom": 3, + "maxzoom": 7, + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 4, + 10 + ], + [ + 7, + 18 + ] + ] + }, + "text-allow-overlap": false, + "text-ignore-placement": false, + "text-transform": "uppercase", + "text-font": [ + "DIN Offc Pro Bold", + "Arial Unicode MS Bold" + ], + "text-padding": 1, + "visibility": "visible", + "text-field": { + "base": 1, + "stops": [ + [ + 0, + "{abbr}" + ], + [ + 4, + "{name_en}" + ] + ] + }, + "text-letter-spacing": 0.15, + "text-max-width": 6 + }, + "paint": { + "text-opacity": 1, + "text-color": "#242424", + "text-halo-color": "#ffffff", + "text-halo-width": 1 + }, + "metadata": { + "mapbox:group": "1444856151690.9143" + } + }, + { + "id": "country-label-sm", + "type": "symbol", + "source": "composite", + "source-layer": "country_label", + "filter": [ + ">=", + "scalerank", + 5 + ], + "minzoom": 1, + "maxzoom": 10, + "layout": { + "text-field": "{name_en}", + "visibility": "visible", + "text-max-width": 6, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-size": { + "base": 0.9, + "stops": [ + [ + 5, + 14 + ], + [ + 9, + 22 + ] + ] + } + }, + "paint": { + "text-color": "#000000", + "text-halo-color": { + "base": 1, + "stops": [ + [ + 2, + "rgba(255,255,255,0.75)" + ], + [ + 3, + "#ffffff" + ] + ] + }, + "text-halo-width": 1.25 + }, + "metadata": { + "mapbox:group": "1444856144497.7825" + } + }, + { + "id": "country-label-md", + "type": "symbol", + "source": "composite", + "source-layer": "country_label", + "filter": [ + "in", + "scalerank", + 3, + 4 + ], + "minzoom": 1, + "maxzoom": 8, + "layout": { + "text-field": { + "base": 1, + "stops": [ + [ + 0, + "{code}" + ], + [ + 2, + "{name_en}" + ] + ] + }, + "visibility": "visible", + "text-max-width": 6, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-size": { + "base": 1, + "stops": [ + [ + 3, + 10 + ], + [ + 8, + 24 + ] + ] + } + }, + "paint": { + "text-color": "#000000", + "text-halo-color": { + "base": 1, + "stops": [ + [ + 2, + "rgba(255,255,255,0.75)" + ], + [ + 3, + "#ffffff" + ] + ] + }, + "text-halo-width": 1.25 + }, + "metadata": { + "mapbox:group": "1444856144497.7825" + } + }, + { + "id": "country-label-lg", + "type": "symbol", + "source": "composite", + "source-layer": "country_label", + "filter": [ + "in", + "scalerank", + 1, + 2 + ], + "minzoom": 1, + "maxzoom": 7, + "layout": { + "text-field": "{name_en}", + "visibility": "visible", + "text-max-width": { + "base": 1, + "stops": [ + [ + 0, + 5 + ], + [ + 3, + 6 + ] + ] + }, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-size": { + "base": 1, + "stops": [ + [ + 1, + 10 + ], + [ + 6, + 24 + ] + ] + } + }, + "paint": { + "text-color": "#000000", + "text-halo-color": { + "base": 1, + "stops": [ + [ + 2, + "rgba(255,255,255,0.75)" + ], + [ + 3, + "#ffffff" + ] + ] + }, + "text-halo-width": 1.25 + }, + "metadata": { + "mapbox:group": "1444856144497.7825" + } + } + ] +} \ No newline at end of file From 00339acb773906482a08b874e99a2d415153eef4 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 20:18:15 -0800 Subject: [PATCH 37/63] refs #352: removed more extraneous debug stuff --- src/mbgl/map/map_context.cpp | 1 - src/mbgl/map/tile_data.cpp | 1 - src/mbgl/map/vector_tile_data.cpp | 1 - 3 files changed, 3 deletions(-) diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 454b56efda3..cc79ca65dc6 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include diff --git a/src/mbgl/map/tile_data.cpp b/src/mbgl/map/tile_data.cpp index 0c4356877fd..bba7d7fe222 100644 --- a/src/mbgl/map/tile_data.cpp +++ b/src/mbgl/map/tile_data.cpp @@ -6,7 +6,6 @@ namespace mbgl { TileData::TileData(const TileID& id_) : id(id_), state(State::initial) { -// printf("creating TileData %s (%p)\n", std::string(id).c_str(), this); } TileData::~TileData() = default; diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index 977b367b0a3..99109bfc720 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -74,7 +74,6 @@ VectorTileData::VectorTileData(const TileID& id_, // Move over interactivity feature tree in case we got a refresh parse. featureTree = std::move(resultBuckets.featureTree); -// printf("consolidated results feature tree items (%lu) into own (%s/%p of %lu items)\n", resultBuckets.featureTree.size(), std::string(id).c_str(), this, featureTree.size()); // The target configuration could have changed since we started placement. In this case, // we're starting another placement run. From 2a1f0e6b0ce77a3c914815bcc0e0c1ba41cdb3cf Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 21:18:02 -0800 Subject: [PATCH 38/63] refs #352: pipe through a radius parameter and use 50 on mobile --- include/mbgl/map/map.hpp | 2 +- platform/ios/MGLMapView.mm | 2 +- src/mbgl/map/map.cpp | 4 ++-- src/mbgl/map/map_context.cpp | 4 ++-- src/mbgl/map/map_context.hpp | 2 +- src/mbgl/map/source.cpp | 8 ++++---- src/mbgl/map/source.hpp | 2 +- src/mbgl/style/style.cpp | 4 ++-- src/mbgl/style/style.hpp | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 6eaa1c4804d..3abd321a98e 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -161,7 +161,7 @@ class Map : private util::noncopyable { double getTopOffsetPixelsForAnnotationSymbol(const std::string&); // Features - FeatureResults featuresAt(const PrecisionPoint) const; + FeatureResults featuresAt(const PrecisionPoint, const uint8_t radius = 5) const; // Sprites void setSprite(const std::string&, std::shared_ptr); diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 105946c6fd6..7f1258a3679 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -388,7 +388,7 @@ - (void)commonInit // flip y for core point.y = self.bounds.size.height - point.y; - mbgl::FeatureResults results = _mbglMap->featuresAt(mbgl::PrecisionPoint(point.x, point.y)); + mbgl::FeatureResults results = _mbglMap->featuresAt(mbgl::PrecisionPoint(point.x, point.y), 50); NSMutableArray *features = [NSMutableArray arrayWithCapacity:results.size()]; diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 5ebfdd753ad..88b35eee341 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -409,8 +409,8 @@ LatLngBounds Map::getBoundsForAnnotations(const AnnotationIDs& annotations) { #pragma mark - Features -FeatureResults Map::featuresAt(const PrecisionPoint point) const { - return context->invokeSync>>(&MapContext::featuresAt, point); +FeatureResults Map::featuresAt(const PrecisionPoint point, const uint8_t radius) const { + return context->invokeSync>>(&MapContext::featuresAt, point, radius); } diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index cc79ca65dc6..e01b3ee5fbd 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -277,10 +277,10 @@ double MapContext::getTopOffsetPixelsForAnnotationSymbol(const std::string& symb } } -FeatureResults MapContext::featuresAt(const PrecisionPoint point) const { +FeatureResults MapContext::featuresAt(const PrecisionPoint point, const uint8_t radius) const { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); if (!style) return FeatureResults(); - return style->featuresAt(point, transformState); + return style->featuresAt(point, radius, transformState); } void MapContext::setSourceTileCacheSize(size_t size) { diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index 1054288a147..779268a4fa7 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -52,7 +52,7 @@ class MapContext : public Style::Observer { double getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol); void updateAnnotations(); - FeatureResults featuresAt(const PrecisionPoint) const; + FeatureResults featuresAt(const PrecisionPoint, const uint8_t radius) const; void setSourceTileCacheSize(size_t size); void onLowMemory(); diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 0b945fa96b7..0be16634c8f 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -606,7 +606,7 @@ void Source::dumpDebugLogs() const { } } -FeatureResults Source::featuresAt(const PrecisionPoint point, const TransformState& transform) const { +FeatureResults Source::featuresAt(const PrecisionPoint point, const uint8_t radius, const TransformState& transform) const { // figure out tile (bounded by source max zoom) LatLng p = transform.pointToLatLng(point); @@ -631,11 +631,11 @@ FeatureResults Source::featuresAt(const PrecisionPoint point, const TransformSta const auto tile_scale = ::pow(2, id.z); // z); const auto scale = util::tileSize * transform.getScale() / (tile_scale / id.overscaling); - const auto radius = 5 * 4096 / scale; + const auto r = radius * 4096 / scale; FeatureBox queryBox = { - { position.x - radius, position.y - radius }, - { position.x + radius, position.y + radius } + { position.x - r, position.y - r }, + { position.x + r, position.y + r } }; FeatureResults results; diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp index a946cbecc90..f021b0d6449 100644 --- a/src/mbgl/map/source.hpp +++ b/src/mbgl/map/source.hpp @@ -93,7 +93,7 @@ class Source : private util::noncopyable { void setObserver(Observer* observer); void dumpDebugLogs() const; - FeatureResults featuresAt(const PrecisionPoint, const TransformState&) const; + FeatureResults featuresAt(const PrecisionPoint, const uint8_t radius, const TransformState&) const; SourceInfo info; bool enabled; diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index 121d8bb3786..27bcc8d616a 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -265,14 +265,14 @@ void Style::emitResourceLoadingFailed(std::exception_ptr error) { } } -FeatureResults Style::featuresAt(const PrecisionPoint point, const TransformState& transform) const { +FeatureResults Style::featuresAt(const PrecisionPoint point, const uint8_t radius, const TransformState& transform) const { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); FeatureResults results; for (const auto& source : sources) { if (source->info.type == SourceType::Vector && source->isLoaded()) { - const auto source_results = source->featuresAt(point, transform); + const auto source_results = source->featuresAt(point, radius, transform); results.insert(results.end(), source_results.begin(), source_results.end()); } } diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index 26e12d5c392..b58bfbf816f 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -69,7 +69,7 @@ class Style : public GlyphStore::Observer, void addLayer(util::ptr, const std::string& beforeLayerID); void removeLayer(const std::string& layerID); - FeatureResults featuresAt(const PrecisionPoint, const TransformState& transform) const; + FeatureResults featuresAt(const PrecisionPoint, const uint8_t radius, const TransformState& transform) const; void dumpDebugLogs() const; From 0e05c3ecc8d796e0cff4d321776af37573d35a5e Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 21:31:27 -0800 Subject: [PATCH 39/63] refs #352: add legit iOS feature querying mode --- ios/app/MBXViewController.mm | 124 +++++++++++++++++++++++------------ 1 file changed, 82 insertions(+), 42 deletions(-) diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm index 44302f92484..16f6b6b1855 100644 --- a/ios/app/MBXViewController.mm +++ b/ios/app/MBXViewController.mm @@ -11,6 +11,8 @@ @interface MBXViewController () @property (nonatomic) MGLMapView *mapView; @property (nonatomic) NSUInteger styleIndex; +@property (nonatomic) UIView *interactiveShield; +@property (nonatomic) UITextView *featuresView; @end @@ -78,10 +80,6 @@ - (void)viewDidLoad [self.mapView addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]]; - UILongPressGestureRecognizer *twoFingerLongPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleTwoFingerLongPress:)]; - twoFingerLongPress.numberOfTouchesRequired = 2; - [self.mapView addGestureRecognizer:twoFingerLongPress]; - [self restoreState:nil]; } @@ -143,6 +141,7 @@ - (void)showSettings @"Add 10,000 Points", @"Add Test Shapes", @"Remove Annotations", + @"Enable Interactivity", nil]; [sheet showFromBarButtonItem:self.navigationItem.leftBarButtonItem animated:YES]; @@ -249,6 +248,40 @@ - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSIn { [self.mapView removeAnnotations:self.mapView.annotations]; } + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 9) + { + if ([self.mapView.styleURL.scheme isEqualToString:@"mapbox"]) + { + self.mapView.userInteractionEnabled = NO; + + self.interactiveShield = [[UIView alloc] initWithFrame:self.mapView.frame]; + self.interactiveShield.backgroundColor = [UIColor clearColor]; + self.interactiveShield.userInteractionEnabled = YES; + [self.view insertSubview:self.interactiveShield aboveSubview:self.mapView]; + + UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleInteractivityPan:)]; + [self.interactiveShield addGestureRecognizer:pan]; + + self.featuresView = [[UITextView alloc] initWithFrame:CGRectMake(20, self.topLayoutGuide.length + 20, + self.view.bounds.size.width / 2 - 40, self.view.bounds.size.height * 2 / 3)]; + self.featuresView.font = [UIFont systemFontOfSize:10]; + self.featuresView.backgroundColor = [UIColor whiteColor]; + self.featuresView.alpha = 0.75; + + [self.view addSubview:self.featuresView]; + + self.mapView.styleURL = [NSURL URLWithString:@"asset://streets-interactive-poi-v8.json"]; + + [(UIButton *)self.navigationItem.titleView setTitle:@"Interactive Streets" forState:UIControlStateNormal]; + + [[[UIAlertView alloc] initWithTitle:@"Interactive Streets" + message:@"Moving the map is now disabled until you change the style. Pan with your finger to query for features." + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil] show]; + } + + } } - (void)parseFeaturesAddingCount:(NSUInteger)featuresCount @@ -310,63 +343,70 @@ - (void)handleLongPress:(UILongPressGestureRecognizer *)longPress } } -- (void)handleTwoFingerLongPress:(UILongPressGestureRecognizer *)longPress +- (void)handleInteractivityPan:(UIPanGestureRecognizer *)pan { - if (longPress.state == UIGestureRecognizerStateBegan) + if (pan.state == UIGestureRecognizerStateBegan || pan.state == UIGestureRecognizerStateChanged) { - if ([self.mapView.styleURL.scheme isEqualToString:@"mapbox"]) - { - self.mapView.styleURL = [NSURL URLWithString:@"asset://streets-interactive-poi-v8.json"]; + self.featuresView.userInteractionEnabled = NO; - [(UIButton *)self.navigationItem.titleView setTitle:@"Interactive Streets" forState:UIControlStateNormal]; + CGPoint point = [pan locationInView:pan.view]; - [[[UIAlertView alloc] initWithTitle:@"Map Is Now Interactive" - message:@"Long-press again with two fingers to query POIs on the map." - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil] show]; - } - else + NSArray *features = [self.mapView featuresAt:point]; + + if ([features count]) { - NSArray *features = [self.mapView featuresAt:[longPress locationInView:longPress.view]]; + NSMutableString *output = [NSMutableString string]; - if ([features count]) + for (NSDictionary *feature in features) { - NSMutableString *output = [NSMutableString string]; + [output appendString:@"Layer: "]; + [output appendString:[feature objectForKey:@"layer"]]; + [output appendString:@"\n"]; - for (NSDictionary *feature in features) - { - [output appendString:@"Layer: "]; - [output appendString:[feature objectForKey:@"layer"]]; - [output appendString:@"\n"]; - - [output appendString:@"Source: "]; - [output appendString:[feature objectForKey:@"source"]]; - [output appendString:@"\n"]; + [output appendString:@"Source: "]; + [output appendString:[feature objectForKey:@"source"]]; + [output appendString:@"\n"]; - NSDictionary *properties = [feature objectForKey:@"properties"]; + NSDictionary *properties = [feature objectForKey:@"properties"]; - for (NSString *key in [properties allKeys]) - { - [output appendString:key]; - [output appendString:@": "]; - [output appendString:properties[key]]; - [output appendString:@"\n"]; - } + for (NSString *key in [properties allKeys]) + { + [output appendString:@"{"]; + [output appendString:key]; + [output appendString:@"}: "]; + [output appendString:properties[key]]; + [output appendString:@"\n"]; } - [[[UIAlertView alloc] initWithTitle:@"Features" - message:output - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil] show]; + [output appendString:@"\n"]; } + + self.featuresView.text = output; + } + else + { + self.featuresView.text = nil; } } + else + { + self.featuresView.userInteractionEnabled = YES; + } } - (void)cycleStyles { + if (self.interactiveShield) + { + [self.interactiveShield removeFromSuperview]; + self.interactiveShield = nil; + + [self.featuresView removeFromSuperview]; + self.featuresView = nil; + + self.mapView.userInteractionEnabled = YES; + } + UIButton *titleButton = (UIButton *)self.navigationItem.titleView; self.styleIndex = (self.styleIndex + 1) % mbgl::util::default_styles::numOrderedStyles; From 72ef933ec28661002ad9a22eb62575339acc2798 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 21:41:12 -0800 Subject: [PATCH 40/63] refs #352: return all properties for annotation tiles --- src/mbgl/annotation/annotation_tile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/annotation/annotation_tile.cpp b/src/mbgl/annotation/annotation_tile.cpp index 64879f0b472..e75cf877d77 100644 --- a/src/mbgl/annotation/annotation_tile.cpp +++ b/src/mbgl/annotation/annotation_tile.cpp @@ -20,7 +20,7 @@ mapbox::util::optional AnnotationTileFeature::getValue(const std::string& } std::unordered_map AnnotationTileFeature::getAllValues() const { - return std::unordered_map(); + return properties; } util::ptr AnnotationTile::getLayer(const std::string& name) const { From b9f47f89f4a65d103dfb53068b9b7d4f7b43eb97 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 21:43:41 -0800 Subject: [PATCH 41/63] refs #352: move away from interrupting alert --- ios/app/MBXViewController.mm | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm index 16f6b6b1855..e359d728c55 100644 --- a/ios/app/MBXViewController.mm +++ b/ios/app/MBXViewController.mm @@ -267,18 +267,13 @@ - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSIn self.featuresView.font = [UIFont systemFontOfSize:10]; self.featuresView.backgroundColor = [UIColor whiteColor]; self.featuresView.alpha = 0.75; + self.featuresView.text = @"Moving the map is now disabled until you change the style. Pan with your finger to query for features."; [self.view addSubview:self.featuresView]; self.mapView.styleURL = [NSURL URLWithString:@"asset://streets-interactive-poi-v8.json"]; [(UIButton *)self.navigationItem.titleView setTitle:@"Interactive Streets" forState:UIControlStateNormal]; - - [[[UIAlertView alloc] initWithTitle:@"Interactive Streets" - message:@"Moving the map is now disabled until you change the style. Pan with your finger to query for features." - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil] show]; } } From 42741cdab72ea7d84f6a011807a207690c0da15f Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 21:48:02 -0800 Subject: [PATCH 42/63] refs #352: remove last debug note --- src/mbgl/annotation/point_annotation_impl.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mbgl/annotation/point_annotation_impl.hpp b/src/mbgl/annotation/point_annotation_impl.hpp index 4522f0514a3..2977caf5773 100644 --- a/src/mbgl/annotation/point_annotation_impl.hpp +++ b/src/mbgl/annotation/point_annotation_impl.hpp @@ -31,7 +31,6 @@ // Make Boost Geometry aware of our LatLng type BOOST_GEOMETRY_REGISTER_POINT_2D(mbgl::LatLng, double, boost::geometry::cs::cartesian, longitude, latitude) BOOST_GEOMETRY_REGISTER_BOX(mbgl::LatLngBounds, mbgl::LatLng, sw, ne) -// FIXME like Collision/Feature namespace mbgl { From f91df07708475d9bbf873bb9afd94f9c824ae395 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 22:09:20 -0800 Subject: [PATCH 43/63] refs #352: use actual source max zoom --- src/mbgl/map/source.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 0be16634c8f..913963449bd 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -617,14 +617,14 @@ FeatureResults Source::featuresAt(const PrecisionPoint point, const uint8_t radi y = y < -1 ? -1 : y > 1 ? 1 : y; const auto z = ::floor(transform.getZoom()); - const auto source_max_z = ::fmin(z, 15); + const auto source_max_z = ::fmin(z, info.max_zoom); const auto z2 = ::powf(2, source_max_z); TileID id(z, ::floor(x * z2), ::floor(y * z2), source_max_z); // figure out query bounds TileCoordinate coordinate = transform.pointToCoordinate(point); - coordinate = coordinate.zoomTo(::fmin(id.z, 15)); + coordinate = coordinate.zoomTo(::fmin(id.z, info.max_zoom)); vec2 position((coordinate.column - id.x) * 4096, (coordinate.row - id.y) * 4096); From 0b6953e0135eac55a966305e98647e39c6a32b04 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 22:13:19 -0800 Subject: [PATCH 44/63] refs #352: scroll text area to top when changing contents --- ios/app/MBXViewController.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm index e359d728c55..b5b4dbba53e 100644 --- a/ios/app/MBXViewController.mm +++ b/ios/app/MBXViewController.mm @@ -377,6 +377,7 @@ - (void)handleInteractivityPan:(UIPanGestureRecognizer *)pan } self.featuresView.text = output; + self.featuresView.contentOffset = CGPointZero; } else { From 392acd994d5f42350a4cf787f7847d4744e543a5 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 2 Dec 2015 22:24:38 -0800 Subject: [PATCH 45/63] refs #352: be more explicit about numeric types and fix tests(?) --- src/mbgl/map/source.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 913963449bd..80d9fdc4a9c 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -610,15 +610,15 @@ FeatureResults Source::featuresAt(const PrecisionPoint point, const uint8_t radi // figure out tile (bounded by source max zoom) LatLng p = transform.pointToLatLng(point); - double sine = std::sin(p.latitude * M_PI / 180); - double x = p.longitude / 360 + 0.5; + const double sine = std::sin(p.latitude * M_PI / 180); + const double x = p.longitude / 360 + 0.5; double y = 0.5 - 0.25 * std::log((1 + sine) / (1 - sine)) / M_PI; y = y < -1 ? -1 : y > 1 ? 1 : y; - const auto z = ::floor(transform.getZoom()); - const auto source_max_z = ::fmin(z, info.max_zoom); - const auto z2 = ::powf(2, source_max_z); + const uint8_t z = ::floor(transform.getZoom()); + const uint8_t source_max_z = ::fmin(z, info.max_zoom); + const uint32_t z2 = ::powf(2, source_max_z); TileID id(z, ::floor(x * z2), ::floor(y * z2), source_max_z); @@ -628,10 +628,10 @@ FeatureResults Source::featuresAt(const PrecisionPoint point, const uint8_t radi vec2 position((coordinate.column - id.x) * 4096, (coordinate.row - id.y) * 4096); - const auto tile_scale = ::pow(2, id.z); // z); - const auto scale = util::tileSize * transform.getScale() / (tile_scale / id.overscaling); + const uint32_t tile_scale = ::pow(2, id.z); + const double scale = util::tileSize * transform.getScale() / (tile_scale / id.overscaling); - const auto r = radius * 4096 / scale; + const uint16_t r = radius * 4096 / scale; FeatureBox queryBox = { { position.x - r, position.y - r }, From 1320df713e74be0443b49ee8df5fb643a251f370 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Thu, 3 Dec 2015 10:00:57 -0800 Subject: [PATCH 46/63] refs #352: finally fix tests on Linux by being explicit about numeric types --- src/mbgl/map/source.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 80d9fdc4a9c..a97a4af8964 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -631,12 +631,14 @@ FeatureResults Source::featuresAt(const PrecisionPoint point, const uint8_t radi const uint32_t tile_scale = ::pow(2, id.z); const double scale = util::tileSize * transform.getScale() / (tile_scale / id.overscaling); - const uint16_t r = radius * 4096 / scale; + const int16_t r = radius * 4096 / scale; - FeatureBox queryBox = { - { position.x - r, position.y - r }, - { position.x + r, position.y + r } - }; + const int16_t left = position.x - r; + const int16_t right = position.x + r; + const int16_t bottom = position.y - r; + const int16_t top = position.y + r; + + FeatureBox queryBox = {{ left, bottom }, { right, top }}; FeatureResults results; From 0ea4f537bbb48a1babccc2702b3e16dce9379a0c Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 11:20:38 -0800 Subject: [PATCH 47/63] more descriptive & safer public API - use string contants for known keys - better method name for easier future compatibility --- include/mbgl/ios/MGLMapView.h | 6 ++---- include/mbgl/ios/MGLTypes.h | 9 +++++++++ ios/app/MBXViewController.mm | 8 ++++---- platform/ios/MGLMapView.mm | 8 ++++---- platform/ios/MGLTypes.m | 4 ++++ 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index d0120d6da79..1df8cabae25 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -84,11 +84,9 @@ IB_DESIGNABLE /** Query the visible map for features at a given point. * -* @warning Beta API. Return value subject to change in subsequent releases. -* * @param point A point on screen, for example at a user gesture. -* @return An array of `NSDictionary` objects representing features near the point. Current fields provided are the style `layer`, the style `source`, and a nested dictionary of properties of the feature as `NSString` keys and values. */ -- (NS_ARRAY_OF(NSDictionary *) *)featuresAt:(CGPoint)point; +* @return An array of `NSDictionary` objects representing features near the point. Keys and values provided include `MGLFeatureLayerNameKey` for the feature layer name in the active style, `MGLFeatureSourceNameKey` for the feature source name in the active style, and `MGLFeaturePropertiesKey` containing a dictionary of properties of the feature from the source data as `NSString` keys and values. */ +- (NS_ARRAY_OF(NSDictionary *) *)featureDescriptionsAtPoint:(CGPoint)point; #pragma mark - Accessing the Delegate diff --git a/include/mbgl/ios/MGLTypes.h b/include/mbgl/ios/MGLTypes.h index f36fc3f44ee..f8b01a51d98 100644 --- a/include/mbgl/ios/MGLTypes.h +++ b/include/mbgl/ios/MGLTypes.h @@ -26,6 +26,15 @@ typedef NS_ENUM(NSUInteger, MGLUserTrackingMode) { MGLUserTrackingModeFollowWithCourse, }; +/** The style layer name for a queried map feature. */ +extern NSString * const MGLFeatureLayerNameKey; + +/** The style source name for a queried map feature. */ +extern NSString * const MGLFeatureSourceNameKey; + +/** The properties from the source data for a queried map feature. */ +extern NSString * const MGLFeaturePropertiesKey; + NS_ASSUME_NONNULL_END #pragma clang diagnostic push diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm index b5b4dbba53e..38971671185 100644 --- a/ios/app/MBXViewController.mm +++ b/ios/app/MBXViewController.mm @@ -346,7 +346,7 @@ - (void)handleInteractivityPan:(UIPanGestureRecognizer *)pan CGPoint point = [pan locationInView:pan.view]; - NSArray *features = [self.mapView featuresAt:point]; + NSArray *features = [self.mapView featureDescriptionsAtPoint:point]; if ([features count]) { @@ -355,14 +355,14 @@ - (void)handleInteractivityPan:(UIPanGestureRecognizer *)pan for (NSDictionary *feature in features) { [output appendString:@"Layer: "]; - [output appendString:[feature objectForKey:@"layer"]]; + [output appendString:[feature objectForKey:MGLFeatureLayerNameKey]]; [output appendString:@"\n"]; [output appendString:@"Source: "]; - [output appendString:[feature objectForKey:@"source"]]; + [output appendString:[feature objectForKey:MGLFeatureSourceNameKey]]; [output appendString:@"\n"]; - NSDictionary *properties = [feature objectForKey:@"properties"]; + NSDictionary *properties = [feature objectForKey:MGLFeaturePropertiesKey]; for (NSString *key in [properties allKeys]) { diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 7f1258a3679..84be8099808 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -383,7 +383,7 @@ - (void)commonInit }]; } -- (NS_ARRAY_OF(NSDictionary *) *)featuresAt:(CGPoint)point +- (NS_ARRAY_OF(NSDictionary *) *)featureDescriptionsAtPoint:(CGPoint)point { // flip y for core point.y = self.bounds.size.height - point.y; @@ -409,9 +409,9 @@ - (void)commonInit featureProperties[key] = val; } - [features addObject:@{ @"layer": layerName, - @"source": sourceName, - @"properties": featureProperties }]; + [features addObject:@{ MGLFeatureLayerNameKey: layerName, + MGLFeatureSourceNameKey: sourceName, + MGLFeaturePropertiesKey: featureProperties }]; } return [NSArray arrayWithArray:features]; diff --git a/platform/ios/MGLTypes.m b/platform/ios/MGLTypes.m index 01e9a1467c6..9042a212994 100644 --- a/platform/ios/MGLTypes.m +++ b/platform/ios/MGLTypes.m @@ -1,3 +1,7 @@ #import "MGLTypes.h" NSString * const MGLErrorDomain = @"MGLErrorDomain"; + +NSString * const MGLFeatureLayerNameKey = @"MGLFeatureLayerNameKey"; +NSString * const MGLFeatureSourceNameKey = @"MGLFeatureSourceNameKey"; +NSString * const MGLFeaturePropertiesKey = @"MGLFeaturePropertiesKey"; From b98b686b9e38ddd254098d671f0a93c0c54497d8 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 11:23:15 -0800 Subject: [PATCH 48/63] use defined type --- src/mbgl/map/map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 88b35eee341..e2553ba4fda 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -410,7 +410,7 @@ LatLngBounds Map::getBoundsForAnnotations(const AnnotationIDs& annotations) { #pragma mark - Features FeatureResults Map::featuresAt(const PrecisionPoint point, const uint8_t radius) const { - return context->invokeSync>>(&MapContext::featuresAt, point, radius); + return context->invokeSync(&MapContext::featuresAt, point, radius); } From 4c639e5c01202cb489f44411cc555590225c8a14 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 11:29:49 -0800 Subject: [PATCH 49/63] abstract tile extent 4096 variable --- src/mbgl/map/tile_worker.cpp | 12 ++++++------ src/mbgl/map/tile_worker.hpp | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index f1c86aff2d8..f80179b8f51 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -140,13 +140,13 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr if (layer.interactive) { for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { const auto feature = geometryLayer->getFeature(i); - FeatureBox featureBox = {{ 4096, 4096 }, { -1, -1 }}; + FeatureBox featureBox = {{ extent, extent }, { -1, -1 }}; const auto geometries = feature->getGeometries(); for (std::size_t j = 0; j < geometries.size(); j++) { const auto geometry = geometries.at(j); for (std::size_t k = 0; k < geometry.size(); k++) { auto point = geometry.at(k); - if (point.x < 0 || point.x > 4095 || point.y < 0 || point.y > 4095) continue; + if (point.x < 0 || point.x > extent - 1 || point.y < 0 || point.y > extent - 1) continue; const auto min = featureBox.min_corner(); const auto max = featureBox.max_corner(); if (point.x < min.get<0>()) { @@ -156,16 +156,16 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr featureBox.min_corner().set<1>(::fmax(point.y, 0)); } if (point.x > max.get<0>()) { - featureBox.max_corner().set<0>(::fmin(point.x, 4095)); + featureBox.max_corner().set<0>(::fmin(point.x, extent - 1)); } if (point.y > max.get<1>()) { - featureBox.max_corner().set<1>(::fmin(point.y, 4095)); + featureBox.max_corner().set<1>(::fmin(point.y, extent - 1)); } } } - if (featureBox.min_corner().get<0>() < 4096 && featureBox.min_corner().get<1>() < 4096 && - featureBox.max_corner().get<0>() > -1 && featureBox.max_corner().get<1>() > -1) { + if (featureBox.min_corner().get<0>() < extent && featureBox.min_corner().get<1>() < extent && + featureBox.max_corner().get<0>() > -1 && featureBox.max_corner().get<1>() > -1) { const auto& values = feature->getAllValues(); FeatureProperties properties; properties.insert(values.begin(), values.end()); diff --git a/src/mbgl/map/tile_worker.hpp b/src/mbgl/map/tile_worker.hpp index 0e48d0b9405..fda564d22c2 100644 --- a/src/mbgl/map/tile_worker.hpp +++ b/src/mbgl/map/tile_worker.hpp @@ -72,6 +72,8 @@ class TileWorker : public util::noncopyable { // Temporary holder TileParseResultBuckets result; + + const uint16_t extent = 4096; }; } // namespace mbgl From 6c86e789cb38c4f2e2d570a054720a05e8873f2f Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 11:33:42 -0800 Subject: [PATCH 50/63] interactive -> isInteractive --- src/mbgl/map/tile_worker.cpp | 2 +- src/mbgl/style/style_layer.cpp | 2 +- src/mbgl/style/style_layer.hpp | 2 +- src/mbgl/style/style_parser.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index f80179b8f51..150f3156963 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -137,7 +137,7 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr std::unique_ptr bucket = layer.createBucket(parameters); - if (layer.interactive) { + if (layer.isInteractive) { for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { const auto feature = geometryLayer->getFeature(i); FeatureBox featureBox = {{ extent, extent }, { -1, -1 }}; diff --git a/src/mbgl/style/style_layer.cpp b/src/mbgl/style/style_layer.cpp index a7a5a9a0c66..4244fad7c07 100644 --- a/src/mbgl/style/style_layer.cpp +++ b/src/mbgl/style/style_layer.cpp @@ -43,7 +43,7 @@ void StyleLayer::copy(const StyleLayer& src) { minZoom = src.minZoom; maxZoom = src.maxZoom; visibility = src.visibility; - interactive = src.interactive; + isInteractive = src.isInteractive; } } diff --git a/src/mbgl/style/style_layer.hpp b/src/mbgl/style/style_layer.hpp index 82c08b6b27d..12068e51995 100644 --- a/src/mbgl/style/style_layer.hpp +++ b/src/mbgl/style/style_layer.hpp @@ -56,7 +56,7 @@ class StyleLayer : public util::noncopyable { float minZoom = -std::numeric_limits::infinity(); float maxZoom = std::numeric_limits::infinity(); VisibilityType visibility = VisibilityType::Visible; - bool interactive; + bool isInteractive; protected: // Stores what render passes this layer is currently enabled for. This depends on the diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp index d8a4e1422e1..ede24ab6e01 100644 --- a/src/mbgl/style/style_parser.cpp +++ b/src/mbgl/style/style_parser.cpp @@ -266,7 +266,7 @@ void StyleParser::parseLayer(const std::string& id, const JSVal& value, util::pt if (value.HasMember("interactive")) { const JSVal& interactive = value["interactive"]; if (interactive.IsBool()) { - layer->interactive = interactive.GetBool(); + layer->isInteractive = interactive.GetBool(); } else { Log::Warning(Event::ParseStyle, "interactive of layer %s must be a boolean", layer->id.c_str()); } From 262665e2250e4b51c8f4bec9b162ec689255b8f1 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 11:36:29 -0800 Subject: [PATCH 51/63] boxed literals for UTF8 strings --- platform/ios/MGLMapView.mm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 84be8099808..338ea4274cc 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -394,8 +394,8 @@ - (void)commonInit for (const auto& result : results) { - NSString *layerName = [NSString stringWithUTF8String:std::get<0>(result).c_str()]; - NSString *sourceName = [NSString stringWithUTF8String:std::get<1>(result).c_str()]; + NSString *layerName = @(std::get<0>(result).c_str()); + NSString *sourceName = @(std::get<1>(result).c_str()); const auto& properties = std::get<2>(result); @@ -403,8 +403,8 @@ - (void)commonInit for (const auto& property : properties) { - NSString *key = [NSString stringWithUTF8String:property.first.c_str()]; - NSString *val = [NSString stringWithUTF8String:property.second.c_str()]; + NSString *key = @(property.first.c_str()); + NSString *val = @(property.second.c_str()); featureProperties[key] = val; } @@ -1157,7 +1157,7 @@ - (void)handleSingleTapGesture:(UITapGestureRecognizer *)singleTap { // pare down nearby annotations to only enabled ones NSEnumerator *metadataEnumerator = [self.annotationMetadataByAnnotation objectEnumerator]; - NSString *prefix = [NSString stringWithUTF8String:spritePrefix.c_str()]; + NSString *prefix = @(spritePrefix.c_str()); std::unordered_set disabledAnnotationIDs; while (NSDictionary *metadata = [metadataEnumerator nextObject]) @@ -2296,7 +2296,7 @@ - (void)addAnnotations:(NS_ARRAY_OF(id ) *)annotations { [self.annotationMetadataByAnnotation setObject:@{ MGLAnnotationIDKey : @(pointAnnotationIDs[i]), - MGLAnnotationSymbolKey : [NSString stringWithUTF8String:points[i].icon.c_str()] + MGLAnnotationSymbolKey : @(points[i].icon.c_str()) } forKey:annotations[i]]; } } From beda70d55f02e8d207abae98564cf79b10593cfc Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 11:46:34 -0800 Subject: [PATCH 52/63] fix bug with storing to reference --- src/mbgl/map/tile_worker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 150f3156963..2d10cd15188 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -166,7 +166,7 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr if (featureBox.min_corner().get<0>() < extent && featureBox.min_corner().get<1>() < extent && featureBox.max_corner().get<0>() > -1 && featureBox.max_corner().get<1>() > -1) { - const auto& values = feature->getAllValues(); + const auto values = feature->getAllValues(); FeatureProperties properties; properties.insert(values.begin(), values.end()); result.featureTree.insert(std::make_tuple(featureBox, layer.id, properties)); From 505f929414e1b6e4491b90cbfbc0586921e438b1 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 12:27:18 -0800 Subject: [PATCH 53/63] better, stronger types & more clear method names --- include/mbgl/map/map.hpp | 2 +- include/mbgl/util/interactive_features.hpp | 13 +++++++------ platform/ios/MGLMapView.mm | 12 +++++------- src/mbgl/map/map.cpp | 4 ++-- src/mbgl/map/map_context.cpp | 6 +++--- src/mbgl/map/map_context.hpp | 2 +- src/mbgl/map/source.cpp | 9 +++------ src/mbgl/map/source.hpp | 2 +- src/mbgl/map/tile_worker.cpp | 5 +++-- src/mbgl/style/style.cpp | 6 +++--- src/mbgl/style/style.hpp | 2 +- src/mbgl/util/interactive_features_impl.hpp | 5 +---- 12 files changed, 31 insertions(+), 37 deletions(-) diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 3abd321a98e..cf9e2ca7660 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -161,7 +161,7 @@ class Map : private util::noncopyable { double getTopOffsetPixelsForAnnotationSymbol(const std::string&); // Features - FeatureResults featuresAt(const PrecisionPoint, const uint8_t radius = 5) const; + std::vector featureDescriptionsAt(const PrecisionPoint, const uint8_t radius = 5) const; // Sprites void setSprite(const std::string&, std::shared_ptr); diff --git a/include/mbgl/util/interactive_features.hpp b/include/mbgl/util/interactive_features.hpp index 0c93ac12a17..b65720d0743 100644 --- a/include/mbgl/util/interactive_features.hpp +++ b/include/mbgl/util/interactive_features.hpp @@ -3,16 +3,17 @@ #include #include -#include -#include namespace mbgl { -// key, value -typedef std::map FeatureProperties; +struct FeatureDescription { + inline explicit FeatureDescription(std::string layer_, std::string source_, std::mapproperties_) + : layer(layer_), source(source_), properties(properties_) {} -// layer name, source name, feature properties -typedef std::vector> FeatureResults; + std::string layer; + std::string source; + std::map properties; +}; } diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 338ea4274cc..c9d8d581b60 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -388,20 +388,18 @@ - (void)commonInit // flip y for core point.y = self.bounds.size.height - point.y; - mbgl::FeatureResults results = _mbglMap->featuresAt(mbgl::PrecisionPoint(point.x, point.y), 50); + std::vector results = _mbglMap->featureDescriptionsAt(mbgl::PrecisionPoint(point.x, point.y), 50); NSMutableArray *features = [NSMutableArray arrayWithCapacity:results.size()]; for (const auto& result : results) { - NSString *layerName = @(std::get<0>(result).c_str()); - NSString *sourceName = @(std::get<1>(result).c_str()); + NSString *layerName = @(result.layer.c_str()); + NSString *sourceName = @(result.source.c_str()); - const auto& properties = std::get<2>(result); + NSMutableDictionary *featureProperties = [NSMutableDictionary dictionaryWithCapacity:result.properties.size()]; - NSMutableDictionary *featureProperties = [NSMutableDictionary dictionaryWithCapacity:properties.size()]; - - for (const auto& property : properties) + for (const auto& property : result.properties) { NSString *key = @(property.first.c_str()); NSString *val = @(property.second.c_str()); diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index e2553ba4fda..d5b0bd55fcc 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -409,8 +409,8 @@ LatLngBounds Map::getBoundsForAnnotations(const AnnotationIDs& annotations) { #pragma mark - Features -FeatureResults Map::featuresAt(const PrecisionPoint point, const uint8_t radius) const { - return context->invokeSync(&MapContext::featuresAt, point, radius); +std::vector Map::featureDescriptionsAt(const PrecisionPoint point, const uint8_t radius) const { + return context->invokeSync>(&MapContext::featureDescriptionsAt, point, radius); } diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index e01b3ee5fbd..9eab10bd642 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -277,10 +277,10 @@ double MapContext::getTopOffsetPixelsForAnnotationSymbol(const std::string& symb } } -FeatureResults MapContext::featuresAt(const PrecisionPoint point, const uint8_t radius) const { +std::vector MapContext::featureDescriptionsAt(const PrecisionPoint point, const uint8_t radius) const { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); - if (!style) return FeatureResults(); - return style->featuresAt(point, radius, transformState); + if (!style) return std::vector(); + return style->featureDescriptionsAt(point, radius, transformState); } void MapContext::setSourceTileCacheSize(size_t size) { diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index 779268a4fa7..8e52747432b 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -52,7 +52,7 @@ class MapContext : public Style::Observer { double getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol); void updateAnnotations(); - FeatureResults featuresAt(const PrecisionPoint, const uint8_t radius) const; + std::vector featureDescriptionsAt(const PrecisionPoint, const uint8_t radius) const; void setSourceTileCacheSize(size_t size); void onLowMemory(); diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index a97a4af8964..f163efcf9d9 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -606,7 +606,7 @@ void Source::dumpDebugLogs() const { } } -FeatureResults Source::featuresAt(const PrecisionPoint point, const uint8_t radius, const TransformState& transform) const { +std::vector Source::featureDescriptionsAt(const PrecisionPoint point, const uint8_t radius, const TransformState& transform) const { // figure out tile (bounded by source max zoom) LatLng p = transform.pointToLatLng(point); @@ -640,7 +640,7 @@ FeatureResults Source::featuresAt(const PrecisionPoint point, const uint8_t radi FeatureBox queryBox = {{ left, bottom }, { right, top }}; - FeatureResults results; + std::vector results; // find the right tile for (const auto& tile : getLoadedTiles()) { @@ -650,10 +650,7 @@ FeatureResults Source::featuresAt(const PrecisionPoint point, const uint8_t radi const auto& data = tile->data; data->featureTree.query(boost::geometry::index::intersects(queryBox), boost::make_function_output_iterator([&](const auto& val) { - const std::string layer_id = std::get<1>(val); - const FeatureProperties feature_properties = std::get<2>(val); - const auto result = std::make_tuple(layer_id, info.source_id, feature_properties); - results.push_back(result); + results.push_back(val.second); })); } diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp index f021b0d6449..7f4cfa7ebfa 100644 --- a/src/mbgl/map/source.hpp +++ b/src/mbgl/map/source.hpp @@ -93,7 +93,7 @@ class Source : private util::noncopyable { void setObserver(Observer* observer); void dumpDebugLogs() const; - FeatureResults featuresAt(const PrecisionPoint, const uint8_t radius, const TransformState&) const; + std::vector featureDescriptionsAt(const PrecisionPoint, const uint8_t radius, const TransformState&) const; SourceInfo info; bool enabled; diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 2d10cd15188..3ee532c876f 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -166,10 +166,11 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr if (featureBox.min_corner().get<0>() < extent && featureBox.min_corner().get<1>() < extent && featureBox.max_corner().get<0>() > -1 && featureBox.max_corner().get<1>() > -1) { + // sort properties on keys const auto values = feature->getAllValues(); - FeatureProperties properties; + std::map properties; properties.insert(values.begin(), values.end()); - result.featureTree.insert(std::make_tuple(featureBox, layer.id, properties)); + result.featureTree.insert(std::make_pair(featureBox, FeatureDescription(layer.id, layer.source, properties))); } } } diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index 27bcc8d616a..e2a14edf127 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -265,14 +265,14 @@ void Style::emitResourceLoadingFailed(std::exception_ptr error) { } } -FeatureResults Style::featuresAt(const PrecisionPoint point, const uint8_t radius, const TransformState& transform) const { +std::vector Style::featureDescriptionsAt(const PrecisionPoint point, const uint8_t radius, const TransformState& transform) const { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); - FeatureResults results; + std::vector results; for (const auto& source : sources) { if (source->info.type == SourceType::Vector && source->isLoaded()) { - const auto source_results = source->featuresAt(point, radius, transform); + const auto source_results = source->featureDescriptionsAt(point, radius, transform); results.insert(results.end(), source_results.begin(), source_results.end()); } } diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index b58bfbf816f..a2bd0eb94bd 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -69,7 +69,7 @@ class Style : public GlyphStore::Observer, void addLayer(util::ptr, const std::string& beforeLayerID); void removeLayer(const std::string& layerID); - FeatureResults featuresAt(const PrecisionPoint, const uint8_t radius, const TransformState& transform) const; + std::vector featureDescriptionsAt(const PrecisionPoint, const uint8_t radius, const TransformState& transform) const; void dumpDebugLogs() const; diff --git a/src/mbgl/util/interactive_features_impl.hpp b/src/mbgl/util/interactive_features_impl.hpp index 03672501877..eb7b35d378e 100644 --- a/src/mbgl/util/interactive_features_impl.hpp +++ b/src/mbgl/util/interactive_features_impl.hpp @@ -3,9 +3,6 @@ #include -#include -#include - #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-parameter" @@ -33,7 +30,7 @@ namespace FeatureBGI = FeatureBG::index; typedef FeatureBGM::point FeaturePoint; typedef FeatureBGM::box FeatureBox; -typedef std::tuple Feature; +typedef std::pair Feature; typedef FeatureBGI::rtree> FeatureTree; } From b6ad5e2205aa9eb21cb4d7b47346b4cc1130d1c6 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 12:35:00 -0800 Subject: [PATCH 54/63] fix camel case for local variables --- src/mbgl/map/source.cpp | 10 +++++----- src/mbgl/map/vector_tile.cpp | 10 +++++----- src/mbgl/style/style.cpp | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index f163efcf9d9..8db9ab005ec 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -617,10 +617,10 @@ std::vector Source::featureDescriptionsAt(const PrecisionPoi y = y < -1 ? -1 : y > 1 ? 1 : y; const uint8_t z = ::floor(transform.getZoom()); - const uint8_t source_max_z = ::fmin(z, info.max_zoom); - const uint32_t z2 = ::powf(2, source_max_z); + const uint8_t sourceMaxZ = ::fmin(z, info.max_zoom); + const uint32_t z2 = ::powf(2, sourceMaxZ); - TileID id(z, ::floor(x * z2), ::floor(y * z2), source_max_z); + TileID id(z, ::floor(x * z2), ::floor(y * z2), sourceMaxZ); // figure out query bounds TileCoordinate coordinate = transform.pointToCoordinate(point); @@ -628,8 +628,8 @@ std::vector Source::featureDescriptionsAt(const PrecisionPoi vec2 position((coordinate.column - id.x) * 4096, (coordinate.row - id.y) * 4096); - const uint32_t tile_scale = ::pow(2, id.z); - const double scale = util::tileSize * transform.getScale() / (tile_scale / id.overscaling); + const uint32_t tileScale = ::pow(2, id.z); + const double scale = util::tileSize * transform.getScale() / (tileScale / id.overscaling); const int16_t r = radius * 4096 / scale; diff --git a/src/mbgl/map/vector_tile.cpp b/src/mbgl/map/vector_tile.cpp index 5a44ec845e4..212494afada 100644 --- a/src/mbgl/map/vector_tile.cpp +++ b/src/mbgl/map/vector_tile.cpp @@ -87,11 +87,11 @@ mapbox::util::optional VectorTileFeature::getValue(const std::string& key std::unordered_map VectorTileFeature::getAllValues() const { std::unordered_map values; - for (const auto key_it : layer.keys) { - const auto& key = key_it.first; - const auto maybe_val = getValue(key); - if (maybe_val) { - const auto& val = mbgl::toString(maybe_val.get()); + for (const auto keyIter : layer.keys) { + const auto& key = keyIter.first; + const auto maybeVal = getValue(key); + if (maybeVal) { + const auto& val = mbgl::toString(maybeVal.get()); values.emplace(key, val); } } diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index e2a14edf127..cb3ed051bcd 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -272,8 +272,8 @@ std::vector Style::featureDescriptionsAt(const PrecisionPoin for (const auto& source : sources) { if (source->info.type == SourceType::Vector && source->isLoaded()) { - const auto source_results = source->featureDescriptionsAt(point, radius, transform); - results.insert(results.end(), source_results.begin(), source_results.end()); + const auto sourceResults = source->featureDescriptionsAt(point, radius, transform); + results.insert(results.end(), sourceResults.begin(), sourceResults.end()); } } From d123545de9239bcab735c9ed77abbf785a1a6e9c Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 12:43:39 -0800 Subject: [PATCH 55/63] radius uint8_t -> uint16_t as with height & width --- include/mbgl/map/map.hpp | 2 +- src/mbgl/map/map.cpp | 2 +- src/mbgl/map/map_context.cpp | 2 +- src/mbgl/map/map_context.hpp | 2 +- src/mbgl/map/source.cpp | 2 +- src/mbgl/map/source.hpp | 2 +- src/mbgl/style/style.cpp | 2 +- src/mbgl/style/style.hpp | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index cf9e2ca7660..7a386987df6 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -161,7 +161,7 @@ class Map : private util::noncopyable { double getTopOffsetPixelsForAnnotationSymbol(const std::string&); // Features - std::vector featureDescriptionsAt(const PrecisionPoint, const uint8_t radius = 5) const; + std::vector featureDescriptionsAt(const PrecisionPoint, const uint16_t radius = 0) const; // Sprites void setSprite(const std::string&, std::shared_ptr); diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index d5b0bd55fcc..1e88c937906 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -409,7 +409,7 @@ LatLngBounds Map::getBoundsForAnnotations(const AnnotationIDs& annotations) { #pragma mark - Features -std::vector Map::featureDescriptionsAt(const PrecisionPoint point, const uint8_t radius) const { +std::vector Map::featureDescriptionsAt(const PrecisionPoint point, const uint16_t radius) const { return context->invokeSync>(&MapContext::featureDescriptionsAt, point, radius); } diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp index 9eab10bd642..0205b7bacf3 100644 --- a/src/mbgl/map/map_context.cpp +++ b/src/mbgl/map/map_context.cpp @@ -277,7 +277,7 @@ double MapContext::getTopOffsetPixelsForAnnotationSymbol(const std::string& symb } } -std::vector MapContext::featureDescriptionsAt(const PrecisionPoint point, const uint8_t radius) const { +std::vector MapContext::featureDescriptionsAt(const PrecisionPoint point, const uint16_t radius) const { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); if (!style) return std::vector(); return style->featureDescriptionsAt(point, radius, transformState); diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp index 8e52747432b..3c16b1e168e 100644 --- a/src/mbgl/map/map_context.hpp +++ b/src/mbgl/map/map_context.hpp @@ -52,7 +52,7 @@ class MapContext : public Style::Observer { double getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol); void updateAnnotations(); - std::vector featureDescriptionsAt(const PrecisionPoint, const uint8_t radius) const; + std::vector featureDescriptionsAt(const PrecisionPoint, const uint16_t radius) const; void setSourceTileCacheSize(size_t size); void onLowMemory(); diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 8db9ab005ec..81131039d52 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -606,7 +606,7 @@ void Source::dumpDebugLogs() const { } } -std::vector Source::featureDescriptionsAt(const PrecisionPoint point, const uint8_t radius, const TransformState& transform) const { +std::vector Source::featureDescriptionsAt(const PrecisionPoint point, const uint16_t radius, const TransformState& transform) const { // figure out tile (bounded by source max zoom) LatLng p = transform.pointToLatLng(point); diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp index 7f4cfa7ebfa..59cc1d368c6 100644 --- a/src/mbgl/map/source.hpp +++ b/src/mbgl/map/source.hpp @@ -93,7 +93,7 @@ class Source : private util::noncopyable { void setObserver(Observer* observer); void dumpDebugLogs() const; - std::vector featureDescriptionsAt(const PrecisionPoint, const uint8_t radius, const TransformState&) const; + std::vector featureDescriptionsAt(const PrecisionPoint, const uint16_t radius, const TransformState&) const; SourceInfo info; bool enabled; diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index cb3ed051bcd..ccfb56d6bdc 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -265,7 +265,7 @@ void Style::emitResourceLoadingFailed(std::exception_ptr error) { } } -std::vector Style::featureDescriptionsAt(const PrecisionPoint point, const uint8_t radius, const TransformState& transform) const { +std::vector Style::featureDescriptionsAt(const PrecisionPoint point, const uint16_t radius, const TransformState& transform) const { assert(util::ThreadContext::currentlyOn(util::ThreadType::Map)); std::vector results; diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index a2bd0eb94bd..6801943aef2 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -69,7 +69,7 @@ class Style : public GlyphStore::Observer, void addLayer(util::ptr, const std::string& beforeLayerID); void removeLayer(const std::string& layerID); - std::vector featureDescriptionsAt(const PrecisionPoint, const uint8_t radius, const TransformState& transform) const; + std::vector featureDescriptionsAt(const PrecisionPoint, const uint16_t radius, const TransformState& transform) const; void dumpDebugLogs() const; From ac655cebe68065322eb773d5b96fa9dc80ddabc8 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 13:20:10 -0800 Subject: [PATCH 56/63] better comments, abstract extent, and don't iterate over all loaded tiles --- src/mbgl/map/source.cpp | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 81131039d52..3f6d541356d 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -607,7 +607,11 @@ void Source::dumpDebugLogs() const { } std::vector Source::featureDescriptionsAt(const PrecisionPoint point, const uint16_t radius, const TransformState& transform) const { - // figure out tile (bounded by source max zoom) + // First, we figure out the tile being queried, bounded by + // the source's max zoom. + // + // We project the point into Spherical Mercator unit space + // in order to simplify tile math. LatLng p = transform.pointToLatLng(point); const double sine = std::sin(p.latitude * M_PI / 180); @@ -616,22 +620,29 @@ std::vector Source::featureDescriptionsAt(const PrecisionPoi y = y < -1 ? -1 : y > 1 ? 1 : y; + // Then we determine the tile in the source's max zoom + // in which the query point resides. const uint8_t z = ::floor(transform.getZoom()); const uint8_t sourceMaxZ = ::fmin(z, info.max_zoom); const uint32_t z2 = ::powf(2, sourceMaxZ); TileID id(z, ::floor(x * z2), ::floor(y * z2), sourceMaxZ); - // figure out query bounds + // Second, we determine the query point (zero radius) or + // box (non-zero radius) in terms of tile extent space. To + // do this, we factor in the current incremental transform + // scale. + const uint16_t extent = 4096; + TileCoordinate coordinate = transform.pointToCoordinate(point); coordinate = coordinate.zoomTo(::fmin(id.z, info.max_zoom)); - vec2 position((coordinate.column - id.x) * 4096, (coordinate.row - id.y) * 4096); + vec2 position((coordinate.column - id.x) * extent, (coordinate.row - id.y) * extent); const uint32_t tileScale = ::pow(2, id.z); const double scale = util::tileSize * transform.getScale() / (tileScale / id.overscaling); - const int16_t r = radius * 4096 / scale; + const int16_t r = radius * extent / scale; const int16_t left = position.x - r; const int16_t right = position.x + r; @@ -640,18 +651,19 @@ std::vector Source::featureDescriptionsAt(const PrecisionPoi FeatureBox queryBox = {{ left, bottom }, { right, top }}; + // Third, we query the appropriate tile data object's + // feature tree for matching features. std::vector results; - // find the right tile - for (const auto& tile : getLoadedTiles()) { - if (tile->id != id) continue; - - // query the tile - const auto& data = tile->data; - data->featureTree.query(boost::geometry::index::intersects(queryBox), - boost::make_function_output_iterator([&](const auto& val) { - results.push_back(val.second); - })); + const auto tileIter = tiles.find(id); + if (tileIter != tiles.end()) { + const auto& queryTile = tileIter->second; + if (queryTile->data->getState() == TileData::State::parsed) { + queryTile->data->featureTree.query(boost::geometry::index::intersects(queryBox), + boost::make_function_output_iterator([&](const auto& val) { + results.push_back(val.second); + })); + } } return results; From 394c48403f11a27e8e89c412f245520ac1d28aeb Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 13:23:00 -0800 Subject: [PATCH 57/63] expose feature query radius in MGLMapView API --- include/mbgl/ios/MGLMapView.h | 3 ++- ios/app/MBXViewController.mm | 2 +- platform/ios/MGLMapView.mm | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index 1df8cabae25..029b7b84916 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -85,8 +85,9 @@ IB_DESIGNABLE /** Query the visible map for features at a given point. * * @param point A point on screen, for example at a user gesture. +* @param radius A distance in which to query features around the point. * @return An array of `NSDictionary` objects representing features near the point. Keys and values provided include `MGLFeatureLayerNameKey` for the feature layer name in the active style, `MGLFeatureSourceNameKey` for the feature source name in the active style, and `MGLFeaturePropertiesKey` containing a dictionary of properties of the feature from the source data as `NSString` keys and values. */ -- (NS_ARRAY_OF(NSDictionary *) *)featureDescriptionsAtPoint:(CGPoint)point; +- (NS_ARRAY_OF(NSDictionary *) *)featureDescriptionsAtPoint:(CGPoint)point radius:(CGFloat)radius; #pragma mark - Accessing the Delegate diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm index 38971671185..9e8fb83ca86 100644 --- a/ios/app/MBXViewController.mm +++ b/ios/app/MBXViewController.mm @@ -346,7 +346,7 @@ - (void)handleInteractivityPan:(UIPanGestureRecognizer *)pan CGPoint point = [pan locationInView:pan.view]; - NSArray *features = [self.mapView featureDescriptionsAtPoint:point]; + NSArray *features = [self.mapView featureDescriptionsAtPoint:point radius:50]; if ([features count]) { diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index c9d8d581b60..ea402022900 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -383,12 +383,12 @@ - (void)commonInit }]; } -- (NS_ARRAY_OF(NSDictionary *) *)featureDescriptionsAtPoint:(CGPoint)point +- (NS_ARRAY_OF(NSDictionary *) *)featureDescriptionsAtPoint:(CGPoint)point radius:(CGFloat)radius { // flip y for core point.y = self.bounds.size.height - point.y; - std::vector results = _mbglMap->featureDescriptionsAt(mbgl::PrecisionPoint(point.x, point.y), 50); + std::vector results = _mbglMap->featureDescriptionsAt(mbgl::PrecisionPoint(point.x, point.y), radius); NSMutableArray *features = [NSMutableArray arrayWithCapacity:results.size()]; From 10d36f899410eb3f058077c62a9df12111bbfd31 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 14:23:34 -0800 Subject: [PATCH 58/63] refer to screen points in public API --- include/mbgl/ios/MGLMapView.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index 029b7b84916..b1946b57656 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -85,7 +85,7 @@ IB_DESIGNABLE /** Query the visible map for features at a given point. * * @param point A point on screen, for example at a user gesture. -* @param radius A distance in which to query features around the point. +* @param radius A distance in screen points around which to query features. * @return An array of `NSDictionary` objects representing features near the point. Keys and values provided include `MGLFeatureLayerNameKey` for the feature layer name in the active style, `MGLFeatureSourceNameKey` for the feature source name in the active style, and `MGLFeaturePropertiesKey` containing a dictionary of properties of the feature from the source data as `NSString` keys and values. */ - (NS_ARRAY_OF(NSDictionary *) *)featureDescriptionsAtPoint:(CGPoint)point radius:(CGFloat)radius; From d0887949b7e5f78c88826dd6ff346542518f72fb Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 14:49:01 -0800 Subject: [PATCH 59/63] layer is now a pointer --- src/mbgl/map/tile_worker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 992aa1c4ad8..58fe661a174 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -146,7 +146,7 @@ void TileWorker::parseLayer(const StyleLayer* layer, const GeometryTile& geometr std::unique_ptr bucket = layer->createBucket(parameters); - if (layer.isInteractive) { + if (layer->isInteractive) { for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { const auto feature = geometryLayer->getFeature(i); FeatureBox featureBox = {{ extent, extent }, { -1, -1 }}; @@ -179,7 +179,7 @@ void TileWorker::parseLayer(const StyleLayer* layer, const GeometryTile& geometr const auto values = feature->getAllValues(); std::map properties; properties.insert(values.begin(), values.end()); - result.featureTree.insert(std::make_pair(featureBox, FeatureDescription(layer.id, layer.source, properties))); + result.featureTree.insert(std::make_pair(featureBox, FeatureDescription(layer->id, layer->source, properties))); } } } From a04b13ed5269d62b4a1276d46ef484f6c86cc158 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 14:51:53 -0800 Subject: [PATCH 60/63] fix getAllValues() for new GeoJSON feature type --- src/mbgl/tile/geojson_tile.cpp | 4 ++++ src/mbgl/tile/geojson_tile.hpp | 1 + 2 files changed, 5 insertions(+) diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp index 9f14780ca40..7efd9cab96a 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -22,6 +22,10 @@ mapbox::util::optional GeoJSONTileFeature::getValue(const std::string& ke return mapbox::util::optional(); } +std::unordered_map GeoJSONTileFeature::getAllValues() const { + return tags; +} + GeometryCollection GeoJSONTileFeature::getGeometries() const { return geometries; } diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp index e5e9766a179..999679dd66d 100644 --- a/src/mbgl/tile/geojson_tile.hpp +++ b/src/mbgl/tile/geojson_tile.hpp @@ -24,6 +24,7 @@ class GeoJSONTileFeature : public GeometryTileFeature { GeoJSONTileFeature(FeatureType, GeometryCollection&&, Tags&& = Tags{}); FeatureType getType() const override; mapbox::util::optional getValue(const std::string&) const override; + std::unordered_map getAllValues() const override; GeometryCollection getGeometries() const override; private: From 7f079741c31e7bc5cfdb4c062b0cdb891714ff8d Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 15:00:52 -0800 Subject: [PATCH 61/63] getAllValues() -> getValues() --- src/mbgl/annotation/annotation_tile.cpp | 2 +- src/mbgl/annotation/annotation_tile.hpp | 2 +- src/mbgl/map/geometry_tile.hpp | 2 +- src/mbgl/map/tile_worker.cpp | 2 +- src/mbgl/map/vector_tile.cpp | 2 +- src/mbgl/map/vector_tile.hpp | 2 +- src/mbgl/tile/geojson_tile.cpp | 2 +- src/mbgl/tile/geojson_tile.hpp | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mbgl/annotation/annotation_tile.cpp b/src/mbgl/annotation/annotation_tile.cpp index 6207b7460e7..ba0d8ebaf3c 100644 --- a/src/mbgl/annotation/annotation_tile.cpp +++ b/src/mbgl/annotation/annotation_tile.cpp @@ -20,7 +20,7 @@ mapbox::util::optional AnnotationTileFeature::getValue(const std::string& return mapbox::util::optional(); } -std::unordered_map AnnotationTileFeature::getAllValues() const { +std::unordered_map AnnotationTileFeature::getValues() const { return properties; } diff --git a/src/mbgl/annotation/annotation_tile.hpp b/src/mbgl/annotation/annotation_tile.hpp index 4ae04f19f45..3539c1d6c56 100644 --- a/src/mbgl/annotation/annotation_tile.hpp +++ b/src/mbgl/annotation/annotation_tile.hpp @@ -16,7 +16,7 @@ class AnnotationTileFeature : public GeometryTileFeature { FeatureType getType() const override { return type; } mapbox::util::optional getValue(const std::string&) const override; - std::unordered_map getAllValues() const override; + std::unordered_map getValues() const override; GeometryCollection getGeometries() const override { return geometries; } const FeatureType type; diff --git a/src/mbgl/map/geometry_tile.hpp b/src/mbgl/map/geometry_tile.hpp index 05e30918e4c..993d1c34183 100644 --- a/src/mbgl/map/geometry_tile.hpp +++ b/src/mbgl/map/geometry_tile.hpp @@ -32,7 +32,7 @@ class GeometryTileFeature : private util::noncopyable { virtual ~GeometryTileFeature() = default; virtual FeatureType getType() const = 0; virtual mapbox::util::optional getValue(const std::string& key) const = 0; - virtual std::unordered_map getAllValues() const = 0; + virtual std::unordered_map getValues() const = 0; virtual GeometryCollection getGeometries() const = 0; }; diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 58fe661a174..029ba9dc2fe 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -176,7 +176,7 @@ void TileWorker::parseLayer(const StyleLayer* layer, const GeometryTile& geometr if (featureBox.min_corner().get<0>() < extent && featureBox.min_corner().get<1>() < extent && featureBox.max_corner().get<0>() > -1 && featureBox.max_corner().get<1>() > -1) { // sort properties on keys - const auto values = feature->getAllValues(); + const auto values = feature->getValues(); std::map properties; properties.insert(values.begin(), values.end()); result.featureTree.insert(std::make_pair(featureBox, FeatureDescription(layer->id, layer->source, properties))); diff --git a/src/mbgl/map/vector_tile.cpp b/src/mbgl/map/vector_tile.cpp index 3c59401f319..661cc30b03c 100644 --- a/src/mbgl/map/vector_tile.cpp +++ b/src/mbgl/map/vector_tile.cpp @@ -85,7 +85,7 @@ mapbox::util::optional VectorTileFeature::getValue(const std::string& key return mapbox::util::optional(); } -std::unordered_map VectorTileFeature::getAllValues() const { +std::unordered_map VectorTileFeature::getValues() const { std::unordered_map values; for (const auto keyIter : layer.keys) { diff --git a/src/mbgl/map/vector_tile.hpp b/src/mbgl/map/vector_tile.hpp index e616b100fec..506ec72a1b6 100644 --- a/src/mbgl/map/vector_tile.hpp +++ b/src/mbgl/map/vector_tile.hpp @@ -17,7 +17,7 @@ class VectorTileFeature : public GeometryTileFeature { FeatureType getType() const override { return type; } mapbox::util::optional getValue(const std::string&) const override; - std::unordered_map getAllValues() const override; + std::unordered_map getValues() const override; GeometryCollection getGeometries() const override; private: diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp index 7efd9cab96a..2eae1db21f8 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -22,7 +22,7 @@ mapbox::util::optional GeoJSONTileFeature::getValue(const std::string& ke return mapbox::util::optional(); } -std::unordered_map GeoJSONTileFeature::getAllValues() const { +std::unordered_map GeoJSONTileFeature::getValues() const { return tags; } diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp index 999679dd66d..cf21248f7ab 100644 --- a/src/mbgl/tile/geojson_tile.hpp +++ b/src/mbgl/tile/geojson_tile.hpp @@ -24,7 +24,7 @@ class GeoJSONTileFeature : public GeometryTileFeature { GeoJSONTileFeature(FeatureType, GeometryCollection&&, Tags&& = Tags{}); FeatureType getType() const override; mapbox::util::optional getValue(const std::string&) const override; - std::unordered_map getAllValues() const override; + std::unordered_map getValues() const override; GeometryCollection getGeometries() const override; private: From 30239c25c10b86e99b506b498e530369efa0b719 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 14:58:08 -0800 Subject: [PATCH 62/63] fix Linux narrow warning by using correct type --- src/mbgl/map/tile_worker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/map/tile_worker.cpp b/src/mbgl/map/tile_worker.cpp index 029ba9dc2fe..a303d1f65bf 100644 --- a/src/mbgl/map/tile_worker.cpp +++ b/src/mbgl/map/tile_worker.cpp @@ -149,7 +149,7 @@ void TileWorker::parseLayer(const StyleLayer* layer, const GeometryTile& geometr if (layer->isInteractive) { for (std::size_t i = 0; i < geometryLayer->featureCount(); i++) { const auto feature = geometryLayer->getFeature(i); - FeatureBox featureBox = {{ extent, extent }, { -1, -1 }}; + FeatureBox featureBox = {{ int16_t(extent), int16_t(extent) }, { -1, -1 }}; const auto geometries = feature->getGeometries(); for (std::size_t j = 0; j < geometries.size(); j++) { const auto geometry = geometries.at(j); From 02ea849661afac930d4b8d0d2bc7c93760b94f22 Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Mon, 14 Dec 2015 16:23:30 -0800 Subject: [PATCH 63/63] more POI layers in demo, but cleaner output visually --- ios/app/MBXViewController.mm | 48 ++++++++++++++++--------- ios/app/streets-interactive-poi-v8.json | 10 ++++++ 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm index 5c89e152c6c..44c5d8c8ca2 100644 --- a/ios/app/MBXViewController.mm +++ b/ios/app/MBXViewController.mm @@ -263,8 +263,9 @@ - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSIn [self.interactiveShield addGestureRecognizer:pan]; self.featuresView = [[UITextView alloc] initWithFrame:CGRectMake(20, self.topLayoutGuide.length + 20, - self.view.bounds.size.width / 2 - 40, self.view.bounds.size.height * 2 / 3)]; - self.featuresView.font = [UIFont systemFontOfSize:10]; + self.view.bounds.size.width / 2 - 40, self.view.bounds.size.height / 4)]; + self.featuresView.selectable = NO; + self.featuresView.font = [UIFont systemFontOfSize:16]; self.featuresView.backgroundColor = [UIColor whiteColor]; self.featuresView.alpha = 0.75; self.featuresView.text = @"Moving the map is now disabled until you change the style. Pan with your finger to query for features."; @@ -345,29 +346,42 @@ - (void)handleInteractivityPan:(UIPanGestureRecognizer *)pan if ([features count]) { - NSMutableString *output = [NSMutableString string]; + NSMutableArray *outputNames = [NSMutableArray array]; + NSMutableArray *seenIDs = [NSMutableArray array]; for (NSDictionary *feature in features) { - [output appendString:@"Layer: "]; - [output appendString:[feature objectForKey:MGLFeatureLayerNameKey]]; - [output appendString:@"\n"]; - - [output appendString:@"Source: "]; - [output appendString:[feature objectForKey:MGLFeatureSourceNameKey]]; - [output appendString:@"\n"]; + NSDictionary *properties = feature[MGLFeaturePropertiesKey]; - NSDictionary *properties = [feature objectForKey:MGLFeaturePropertiesKey]; + NSString *featureID = properties[@"osm_id"]; - for (NSString *key in [properties allKeys]) + if ( ! [seenIDs containsObject:featureID]) { - [output appendString:@"{"]; - [output appendString:key]; - [output appendString:@"}: "]; - [output appendString:properties[key]]; - [output appendString:@"\n"]; + [seenIDs addObject:featureID]; + + NSString *featureName = properties[@"name_en"]; + + // Mapbox-returned OSM IDs have 1 + zero padding in front of + // the actual OSM ID, so let's remove that. + // + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^10+(.*)" + options:0 + error:nil]; + + featureID = [regex stringByReplacingMatchesInString:featureID + options:0 + range:NSMakeRange(0, featureID.length) + withTemplate:@"$1"]; + + [outputNames addObject:[NSString stringWithFormat:@"- %@ (OSM #%@)", featureName, featureID]]; } + } + NSMutableString *output = [NSMutableString stringWithString:@"Features:\n\n"]; + + for (NSString *outputName in outputNames) + { + [output appendString:outputName]; [output appendString:@"\n"]; } diff --git a/ios/app/streets-interactive-poi-v8.json b/ios/app/streets-interactive-poi-v8.json index fa40d08c934..9c89c3ba1a3 100644 --- a/ios/app/streets-interactive-poi-v8.json +++ b/ios/app/streets-interactive-poi-v8.json @@ -5821,6 +5821,7 @@ "type": "symbol", "source": "composite", "source-layer": "poi_label", + "interactive": true, "filter": [ "all", [ @@ -5990,6 +5991,7 @@ "type": "symbol", "source": "composite", "source-layer": "poi_label", + "interactive": true, "filter": [ "all", [ @@ -6060,6 +6062,7 @@ "type": "symbol", "source": "composite", "source-layer": "poi_label", + "interactive": true, "filter": [ "all", [ @@ -6139,6 +6142,7 @@ "type": "symbol", "source": "composite", "source-layer": "poi_label", + "interactive": true, "filter": [ "all", [ @@ -6579,6 +6583,7 @@ "type": "symbol", "source": "composite", "source-layer": "poi_label", + "interactive": true, "filter": [ "all", [ @@ -6669,6 +6674,7 @@ "type": "symbol", "source": "composite", "source-layer": "poi_label", + "interactive": true, "filter": [ "all", [ @@ -6918,6 +6924,7 @@ "type": "symbol", "source": "composite", "source-layer": "poi_label", + "interactive": true, "filter": [ "all", [ @@ -7001,6 +7008,7 @@ "type": "symbol", "source": "composite", "source-layer": "poi_label", + "interactive": true, "filter": [ "all", [ @@ -7195,6 +7203,7 @@ "type": "symbol", "source": "composite", "source-layer": "poi_label", + "interactive": true, "filter": [ "==", "type", @@ -7515,6 +7524,7 @@ "type": "symbol", "source": "composite", "source-layer": "poi_label", + "interactive": true, "filter": [ "==", "type",