diff options
author | Justin R. Miller <incanus@codesorcery.net> | 2015-03-17 17:30:24 -0700 |
---|---|---|
committer | Justin R. Miller <incanus@codesorcery.net> | 2015-03-17 17:30:24 -0700 |
commit | e049ce6df13c3ad77e9e2ecb2e1afe2992384a35 (patch) | |
tree | 17c21487d53639e3cdf3d6fa9cf78a249a8a67a1 | |
parent | 1ce51a17e7de5d6a02346efce1539ff7f36e0a6d (diff) | |
download | qtlocation-mapboxgl-e049ce6df13c3ad77e9e2ecb2e1afe2992384a35.tar.gz |
refs #893 #992: point annotations API
-rw-r--r-- | include/mbgl/map/annotation.hpp | 72 | ||||
-rw-r--r-- | include/mbgl/map/map.hpp | 15 | ||||
-rw-r--r-- | include/mbgl/util/constants.hpp | 3 | ||||
-rw-r--r-- | include/mbgl/util/geo.hpp | 15 | ||||
-rw-r--r-- | macosx/mapboxgl-app.gyp | 2 | ||||
-rw-r--r-- | src/mbgl/map/annotation.cpp | 184 | ||||
-rw-r--r-- | src/mbgl/map/geometry_tile.hpp | 10 | ||||
-rw-r--r-- | src/mbgl/map/live_tile.cpp | 56 | ||||
-rw-r--r-- | src/mbgl/map/live_tile.hpp | 53 | ||||
-rw-r--r-- | src/mbgl/map/live_tile_data.cpp | 67 | ||||
-rw-r--r-- | src/mbgl/map/live_tile_data.hpp | 32 | ||||
-rw-r--r-- | src/mbgl/map/map.cpp | 56 | ||||
-rw-r--r-- | src/mbgl/map/source.cpp | 22 | ||||
-rw-r--r-- | src/mbgl/map/source.hpp | 1 | ||||
-rw-r--r-- | src/mbgl/map/tile_parser.cpp | 7 | ||||
-rw-r--r-- | src/mbgl/map/tile_parser.hpp | 10 | ||||
-rw-r--r-- | src/mbgl/map/vector_tile.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/map/vector_tile.hpp | 4 | ||||
-rw-r--r-- | src/mbgl/map/vector_tile_data.cpp | 22 | ||||
-rw-r--r-- | src/mbgl/map/vector_tile_data.hpp | 11 | ||||
-rw-r--r-- | src/mbgl/style/style_parser.cpp | 31 | ||||
-rw-r--r-- | src/mbgl/style/types.hpp | 4 | ||||
-rw-r--r-- | src/mbgl/util/constants.cpp | 2 |
23 files changed, 646 insertions, 35 deletions
diff --git a/include/mbgl/map/annotation.hpp b/include/mbgl/map/annotation.hpp new file mode 100644 index 0000000000..e88d98b5c6 --- /dev/null +++ b/include/mbgl/map/annotation.hpp @@ -0,0 +1,72 @@ +#ifndef MBGL_MAP_ANNOTATIONS +#define MBGL_MAP_ANNOTATIONS + +#include <mbgl/map/tile.hpp> +#include <mbgl/map/live_tile.hpp> +#include <mbgl/util/geo.hpp> +#include <mbgl/util/noncopyable.hpp> +#include <mbgl/util/std.hpp> +#include <mbgl/util/vec.hpp> + +#include <string> +#include <vector> +#include <map> +#include <mutex> +#include <memory> + +namespace mbgl { + +class Annotation; +class Map; + +typedef std::vector<LatLng> AnnotationSegment; + +enum class AnnotationType : uint8_t { + Point, + Shape +}; + +class AnnotationManager : private util::noncopyable { +public: + AnnotationManager(); + + void setDefaultPointAnnotationSymbol(std::string& symbol) { defaultPointAnnotationSymbol = symbol; } + std::pair<std::vector<Tile::ID>, std::vector<uint32_t>> addPointAnnotations(std::vector<LatLng>, std::vector<std::string>& symbols, const Map&); + std::vector<Tile::ID> removeAnnotations(std::vector<uint32_t>); + std::vector<uint32_t> getAnnotationsInBounds(LatLngBounds, const Map&) const; + LatLngBounds getBoundsForAnnotations(std::vector<uint32_t>) const; + + const std::unique_ptr<LiveTile>& getTile(Tile::ID const& id); + +private: + uint32_t nextID() { return nextID_++; } + static vec2<double> projectPoint(LatLng& point); + +private: + std::mutex mtx; + std::string defaultPointAnnotationSymbol; + std::map<uint32_t, std::unique_ptr<Annotation>> annotations; + std::map<Tile::ID, std::pair<std::vector<uint32_t>, std::unique_ptr<LiveTile>>> annotationTiles; + std::unique_ptr<LiveTile> nullTile; + uint32_t nextID_ = 0; +}; + +class Annotation : private util::noncopyable { + friend class AnnotationManager; +public: + Annotation(AnnotationType, std::vector<AnnotationSegment>); + +private: + LatLng getPoint() const; + LatLngBounds getBounds() const { return bounds; } + +private: + const AnnotationType type = AnnotationType::Point; + const std::vector<AnnotationSegment> geometry; + std::map<Tile::ID, std::vector<std::weak_ptr<const LiveTileFeature>>> tileFeatures; + LatLngBounds bounds; +}; + +} + +#endif diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 44a560a468..b03217570b 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -37,6 +37,7 @@ class GlyphAtlas; class SpriteAtlas; class LineAtlas; class Environment; +class AnnotationManager; class Map : private util::noncopyable { friend class View; @@ -140,6 +141,15 @@ public: inline const vec2<double> pixelForLatLng(const LatLng latLng) const { return state.pixelForLatLng(latLng); } inline const LatLng latLngForPixel(const vec2<double> pixel) const { return state.latLngForPixel(pixel); } + // Annotations + void setDefaultPointAnnotationSymbol(std::string&); + uint32_t addPointAnnotation(LatLng, std::string& symbol); + std::vector<uint32_t> addPointAnnotations(std::vector<LatLng>, std::vector<std::string>& symbols); + void removeAnnotation(uint32_t); + void removeAnnotations(std::vector<uint32_t>); + std::vector<uint32_t> getAnnotationsInBounds(LatLngBounds) const; + LatLngBounds getBoundsForAnnotations(std::vector<uint32_t>) const; + // Debug void setDebug(bool value); void toggleDebug(); @@ -147,6 +157,7 @@ public: inline const TransformState &getState() const { return state; } inline std::chrono::steady_clock::time_point getTime() const { return animationTime; } + inline AnnotationManager& getAnnotationManager() const { return *annotationManager; } private: // This may only be called by the View object. @@ -170,6 +181,8 @@ private: // the stylesheet. void prepare(); + void updateAnnotationTiles(std::vector<Tile::ID>&); + enum class Mode : uint8_t { None, // we're not doing any processing Continuous, // continually updating map @@ -219,8 +232,8 @@ private: util::ptr<Sprite> sprite; const std::unique_ptr<LineAtlas> lineAtlas; util::ptr<TexturePool> texturePool; - const std::unique_ptr<Painter> painter; + util::ptr<AnnotationManager> annotationManager; std::string styleURL; std::string styleJSON = ""; diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp index 069e6e41ae..9e0856b68a 100644 --- a/include/mbgl/util/constants.hpp +++ b/include/mbgl/util/constants.hpp @@ -2,6 +2,7 @@ #define MBGL_UTIL_CONSTANTS #include <cmath> +#include <string> namespace mbgl { @@ -15,6 +16,8 @@ extern const double M2PI; extern const double EARTH_RADIUS_M; extern const double LATITUDE_MAX; +extern const std::string ANNOTATIONS_POINTS_LAYER_ID; + } namespace debug { diff --git a/include/mbgl/util/geo.hpp b/include/mbgl/util/geo.hpp index 1d9986bd91..b99a6e6614 100644 --- a/include/mbgl/util/geo.hpp +++ b/include/mbgl/util/geo.hpp @@ -19,6 +19,21 @@ struct ProjectedMeters { : northing(n), easting(e) {} }; +struct LatLngBounds { + LatLng sw = {90, 180}; + LatLng ne = {-90, -180}; + + inline LatLngBounds(LatLng sw_ = {90, 180}, LatLng ne_ = {-90, -180}) + : sw(sw_), ne(ne_) {} + + inline void extend(const LatLng& point) { + if (point.latitude < sw.latitude) sw.latitude = point.latitude; + if (point.latitude > ne.latitude) ne.latitude = point.latitude; + if (point.longitude < sw.longitude) sw.longitude = point.longitude; + if (point.longitude > ne.longitude) ne.longitude = point.longitude; + } +}; + } #endif diff --git a/macosx/mapboxgl-app.gyp b/macosx/mapboxgl-app.gyp index 37280286e5..39aef6435b 100644 --- a/macosx/mapboxgl-app.gyp +++ b/macosx/mapboxgl-app.gyp @@ -9,7 +9,7 @@ 'product_extension': 'app', 'mac_bundle': 1, 'mac_bundle_resources': [ - 'Icon.icns', + 'Icon.icns' ], 'dependencies': [ diff --git a/src/mbgl/map/annotation.cpp b/src/mbgl/map/annotation.cpp new file mode 100644 index 0000000000..b2a90f53c6 --- /dev/null +++ b/src/mbgl/map/annotation.cpp @@ -0,0 +1,184 @@ +#include <mbgl/map/annotation.hpp> +#include <mbgl/map/map.hpp> +#include <mbgl/util/ptr.hpp> + +#include <algorithm> +#include <memory> + +using namespace mbgl; + +Annotation::Annotation(AnnotationType type_, std::vector<AnnotationSegment> geometry_) + : type(type_), + geometry(geometry_) { + if (type == AnnotationType::Point) { + bounds = LatLngBounds(getPoint(), getPoint()); + } else { + for (auto segment : geometry) { + for (auto point : segment) { + bounds.extend(point); + } + } + } +} + +LatLng Annotation::getPoint() const { + return geometry[0][0]; +} + +AnnotationManager::AnnotationManager() + : nullTile(util::make_unique<LiveTile>()) {} + +vec2<double> AnnotationManager::projectPoint(LatLng& point) { + double sine = std::sin(point.latitude * M_PI / 180); + double x = point.longitude / 360 + 0.5; + double y = 0.5 - 0.25 * std::log((1 + sine) / (1 - sine)) / M_PI; + return vec2<double>(x, y); +} + +std::pair<std::vector<Tile::ID>, std::vector<uint32_t>> AnnotationManager::addPointAnnotations(std::vector<LatLng> points, std::vector<std::string>& symbols, const Map& map) { + + uint16_t extent = 4096; + + std::vector<uint32_t> annotationIDs(points.size()); + std::vector<Tile::ID> affectedTiles; + + for (uint32_t i = 0; i < points.size(); ++i) { + uint32_t annotationID = nextID(); + + auto anno_it = annotations.emplace(annotationID, util::make_unique<Annotation>(AnnotationType::Point, std::vector<AnnotationSegment>({{ points[i] }}))); + + uint8_t maxZoom = map.getMaxZoom(); + + uint32_t z2 = 1 << maxZoom; + + vec2<double> p = projectPoint(points[i]); + + uint32_t x = p.x * z2; + uint32_t y = p.y * z2; + + for (int8_t z = maxZoom; z >= 0; z--) { + affectedTiles.emplace_back(z, x, y); + Tile::ID tileID = affectedTiles.back(); + + Coordinate coordinate(extent * (p.x * z2 - x), extent * (p.y * z2 - y)); + + GeometryCollection geometries({{ {{ coordinate }} }}); + + std::map<std::string, std::string> properties = {{ "sprite", (symbols[i].length() ? symbols[i] : defaultPointAnnotationSymbol) }}; + + auto feature = std::make_shared<const LiveTileFeature>(FeatureType::Point, + geometries, + properties); + + auto tile_it = annotationTiles.find(tileID); + if (tile_it != annotationTiles.end()) { + // get point layer & add feature + auto layer = tile_it->second.second->getMutableLayer(util::ANNOTATIONS_POINTS_LAYER_ID); + layer->addFeature(feature); + // record annotation association with tile + tile_it->second.first.push_back(annotationID); + } else { + // create point layer & add feature + util::ptr<LiveTileLayer> layer = std::make_shared<LiveTileLayer>(); + layer->addFeature(feature); + // create tile & record annotation association + auto tile_pos = annotationTiles.emplace(tileID, std::make_pair(std::vector<uint32_t>({ annotationID }), util::make_unique<LiveTile>())); + // add point layer to tile + tile_pos.first->second.second->addLayer(util::ANNOTATIONS_POINTS_LAYER_ID, layer); + } + + // record annotation association with tile feature + anno_it.first->second->tileFeatures.emplace(tileID, std::vector<std::weak_ptr<const LiveTileFeature>>({ feature })); + + z2 /= 2; + x /= 2; + y /= 2; + } + + annotationIDs.push_back(annotationID); + } + + return std::make_pair(affectedTiles, annotationIDs); +} + +std::vector<Tile::ID> AnnotationManager::removeAnnotations(std::vector<uint32_t> ids) { + std::vector<Tile::ID> affectedTiles; + + for (auto& annotationID : ids) { + auto annotation_it = annotations.find(annotationID); + if (annotation_it != annotations.end()) { + auto& annotation = annotation_it->second; + for (auto& tile_it : annotationTiles) { + auto features_it = annotation->tileFeatures.find(tile_it.first); + if (features_it != annotation->tileFeatures.end()) { + auto layer = tile_it.second.second->getMutableLayer(util::ANNOTATIONS_POINTS_LAYER_ID); + auto& features = features_it->second; + layer->removeFeature(features[0]); + affectedTiles.push_back(tile_it.first); + } + } + annotations.erase(annotationID); + } + } + + return affectedTiles; +} + +std::vector<uint32_t> AnnotationManager::getAnnotationsInBounds(LatLngBounds queryBounds, const Map& map) const { + uint8_t z = map.getMaxZoom(); + uint32_t z2 = 1 << z; + vec2<double> swPoint = projectPoint(queryBounds.sw); + vec2<double> nePoint = projectPoint(queryBounds.ne); + + // tiles number y from top down + Tile::ID nwTile(z, swPoint.x * z2, nePoint.y * z2); + Tile::ID seTile(z, nePoint.x * z2, swPoint.y * z2); + + std::vector<uint32_t> matchingAnnotations; + + for (auto& tile : annotationTiles) { + Tile::ID id = tile.first; + if (id.z == z) { + if (id.x >= nwTile.x && id.x <= seTile.x && id.y >= nwTile.y && id.y <= seTile.y) { + if (id.x > nwTile.x && id.x < seTile.x && id.y > nwTile.y && id.y < seTile.y) { + // trivial accept; grab all of the tile's annotations + std::copy(tile.second.first.begin(), tile.second.first.end(), std::back_inserter(matchingAnnotations)); + } else { + // check tile's annotations' bounding boxes + std::copy_if(tile.second.first.begin(), tile.second.first.end(), + std::back_inserter(matchingAnnotations), [&](const uint32_t annotationID) -> bool { + LatLngBounds annoBounds = this->annotations.find(annotationID)->second->getBounds(); + return (annoBounds.sw.latitude >= queryBounds.sw.latitude && + annoBounds.ne.latitude <= queryBounds.ne.latitude && + annoBounds.sw.longitude >= queryBounds.sw.longitude && + annoBounds.ne.longitude <= queryBounds.ne.longitude); + }); + } + } + } + } + + return matchingAnnotations; +} + +LatLngBounds AnnotationManager::getBoundsForAnnotations(std::vector<uint32_t> ids) const { + LatLngBounds bounds; + for (auto id : ids) { + auto annotation_it = annotations.find(id); + if (annotation_it != annotations.end()) { + bounds.extend(annotation_it->second->getPoint()); + } + } + + return bounds; +} + +const std::unique_ptr<LiveTile>& AnnotationManager::getTile(Tile::ID const& id) { + std::lock_guard<std::mutex> lock(mtx); + + auto tile_it = annotationTiles.find(id); + if (tile_it != annotationTiles.end()) { + return tile_it->second.second; + } + return nullTile; +} diff --git a/src/mbgl/map/geometry_tile.hpp b/src/mbgl/map/geometry_tile.hpp index 3df0661fbf..18222b622b 100644 --- a/src/mbgl/map/geometry_tile.hpp +++ b/src/mbgl/map/geometry_tile.hpp @@ -23,22 +23,22 @@ enum class FeatureType : uint8_t { typedef std::vector<std::vector<Coordinate>> GeometryCollection; -class GeometryTileFeature : public mbgl::util::noncopyable { +class GeometryTileFeature : private util::noncopyable { public: virtual FeatureType getType() const = 0; virtual mapbox::util::optional<Value> getValue(const std::string& key) const = 0; virtual GeometryCollection getGeometries() const = 0; }; -class GeometryTileLayer : public mbgl::util::noncopyable { +class GeometryTileLayer : private util::noncopyable { public: virtual std::size_t featureCount() const = 0; - virtual util::ptr<const GeometryTileFeature> feature(std::size_t i) const = 0; + virtual util::ptr<const GeometryTileFeature> feature(std::size_t) const = 0; }; -class GeometryTile : public mbgl::util::noncopyable { +class GeometryTile : private util::noncopyable { public: - virtual util::ptr<const GeometryTileLayer> getLayer(const std::string&) const = 0; + virtual util::ptr<GeometryTileLayer> getLayer(const std::string&) const = 0; }; class GeometryTileFeatureExtractor { diff --git a/src/mbgl/map/live_tile.cpp b/src/mbgl/map/live_tile.cpp new file mode 100644 index 0000000000..06337af184 --- /dev/null +++ b/src/mbgl/map/live_tile.cpp @@ -0,0 +1,56 @@ +#include <mbgl/map/live_tile.hpp> +#include <mbgl/util/constants.hpp> + +namespace mbgl { + +LiveTileFeature::LiveTileFeature(FeatureType type_, GeometryCollection geometries_, std::map<std::string, std::string> properties_) + : type(type_), + properties(properties_), + geometries(geometries_) {} + +mapbox::util::optional<Value> LiveTileFeature::getValue(const std::string& key) const { + auto it = properties.find(key); + if (it != properties.end()) { + return mapbox::util::optional<Value>(it->second); + } + return mapbox::util::optional<Value>(); +} + +LiveTileLayer::LiveTileLayer() {} + +void LiveTileLayer::prepareToAddFeatures(size_t count) { + features.reserve(features.size() + count); +} + +void LiveTileLayer::addFeature(util::ptr<const LiveTileFeature> feature) { + features.push_back(std::move(feature)); +} + +void LiveTileLayer::removeFeature(util::ptr<const LiveTileFeature> feature) { + for (auto it = features.begin(); it != features.end(); ++it) { + if (feature == *it) { + features.erase(it); + return; + } + } +} + +LiveTile::LiveTile() {} + +void LiveTile::addLayer(const std::string& name, util::ptr<LiveTileLayer> layer) { + layers.emplace(name, std::move(layer)); +} + +util::ptr<GeometryTileLayer> LiveTile::getLayer(const std::string& name) const { + return getMutableLayer(name); +} + +util::ptr<LiveTileLayer> LiveTile::getMutableLayer(const std::string& name) const { + auto layer_it = layers.find(name); + if (layer_it != layers.end()) { + return layer_it->second; + } + return nullptr; +} + +} diff --git a/src/mbgl/map/live_tile.hpp b/src/mbgl/map/live_tile.hpp new file mode 100644 index 0000000000..019c9da740 --- /dev/null +++ b/src/mbgl/map/live_tile.hpp @@ -0,0 +1,53 @@ +#ifndef MBGL_MAP_LIVE_TILE +#define MBGL_MAP_LIVE_TILE + +#include <map> + +#include <mbgl/map/geometry_tile.hpp> + +namespace mbgl { + +class LiveTileFeature : public GeometryTileFeature { +public: + LiveTileFeature(FeatureType, GeometryCollection, std::map<std::string, std::string> properties = {{}}); + + FeatureType getType() const override { return type; } + mapbox::util::optional<Value> getValue(const std::string&) const override; + GeometryCollection getGeometries() const override { return geometries; } + +private: + FeatureType type = FeatureType::Unknown; + std::map<std::string, std::string> properties; + GeometryCollection geometries; +}; + + class LiveTileLayer : public GeometryTileLayer { +public: + LiveTileLayer(); + + void prepareToAddFeatures(size_t count); + void addFeature(util::ptr<const LiveTileFeature>); + void removeFeature(util::ptr<const LiveTileFeature>); + std::size_t featureCount() const override { return features.size(); } + util::ptr<const GeometryTileFeature> feature(std::size_t i) const override { return features[i]; } + +private: + std::vector<util::ptr<const LiveTileFeature>> features; +}; + +class LiveTile : public GeometryTile { +public: + LiveTile(); + + void addLayer(const std::string&, util::ptr<LiveTileLayer>); + util::ptr<GeometryTileLayer> getLayer(const std::string&) const override; + util::ptr<LiveTileLayer> getMutableLayer(const std::string&) const; + bool operator()(const LiveTile&) const { return layers.size() > 0; } + +private: + std::map<std::string, util::ptr<LiveTileLayer>> layers; +}; + +} + +#endif diff --git a/src/mbgl/map/live_tile_data.cpp b/src/mbgl/map/live_tile_data.cpp new file mode 100644 index 0000000000..34743f02ce --- /dev/null +++ b/src/mbgl/map/live_tile_data.cpp @@ -0,0 +1,67 @@ +#include <mbgl/map/annotation.hpp> +#include <mbgl/map/live_tile_data.hpp> +#include <mbgl/map/tile_parser.hpp> +#include <mbgl/style/style_source.hpp> +#include <mbgl/map/vector_tile.hpp> +#include <mbgl/platform/log.hpp> + +using namespace mbgl; + +LiveTileData::LiveTileData(Tile::ID const& id_, + util::ptr<AnnotationManager> annotationManager_, + float mapMaxZoom, + util::ptr<Style> style_, + GlyphAtlas& glyphAtlas_, + GlyphStore& glyphStore_, + SpriteAtlas& spriteAtlas_, + util::ptr<Sprite> sprite_, + const SourceInfo& source_, + Environment& env_) + : VectorTileData::VectorTileData(id_, mapMaxZoom, style_, glyphAtlas_, glyphStore_, + spriteAtlas_, sprite_, source_, env_), + annotationManager(annotationManager_) { + // live features are always ready + state = State::loaded; +} + +LiveTileData::~LiveTileData() {} + +void LiveTileData::parse() { + if (state != State::loaded) { + return; + } + + try { + if (!style) { + throw std::runtime_error("style isn't present in LiveTileData object anymore"); + } + + if (source.type == SourceType::Annotations) { + const std::unique_ptr<LiveTile>& tile = annotationManager->getTile(id); + + if (tile) { + // Parsing creates state that is encapsulated in TileParser. While parsing, + // the TileParser object writes results into this objects. All other state + // is going to be discarded afterwards. + TileParser parser(*tile, *this, style, glyphAtlas, glyphStore, spriteAtlas, sprite); + + // Clear the style so that we don't have a cycle in the shared_ptr references. + style.reset(); + + parser.parse(); + } else { + state = State::obsolete; + } + } else { + throw std::runtime_error("unknown live tile source type"); + } + } catch (const std::exception& ex) { + Log::Error(Event::ParseTile, "Live-parsing [%d/%d/%d] failed: %s", id.z, id.x, id.y, ex.what()); + state = State::obsolete; + return; + } + + if (state != State::obsolete) { + state = State::parsed; + } +} diff --git a/src/mbgl/map/live_tile_data.hpp b/src/mbgl/map/live_tile_data.hpp new file mode 100644 index 0000000000..11530ef847 --- /dev/null +++ b/src/mbgl/map/live_tile_data.hpp @@ -0,0 +1,32 @@ +#ifndef MBGL_MAP_LIVE_TILE_DATA +#define MBGL_MAP_LIVE_TILE_DATA + +#include <mbgl/map/vector_tile_data.hpp> + +namespace mbgl { + +class AnnotationManager; + +class LiveTileData : public VectorTileData { +public: + LiveTileData(Tile::ID const&, + util::ptr<AnnotationManager>, + float mapMaxZoom, + util::ptr<Style>, + GlyphAtlas&, + GlyphStore&, + SpriteAtlas&, + util::ptr<Sprite>, + const SourceInfo&, + Environment&); + ~LiveTileData(); + + void parse() override; + +private: + util::ptr<AnnotationManager> annotationManager; +}; + +} + +#endif diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index d12afc9143..2dea2deac1 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -4,6 +4,7 @@ #include <mbgl/platform/platform.hpp> #include <mbgl/map/source.hpp> #include <mbgl/renderer/painter.hpp> +#include <mbgl/map/annotation.hpp> #include <mbgl/map/sprite.hpp> #include <mbgl/util/transition.hpp> #include <mbgl/util/math.hpp> @@ -70,7 +71,8 @@ Map::Map(View& view_, FileSource& fileSource_) spriteAtlas(util::make_unique<SpriteAtlas>(512, 512)), lineAtlas(util::make_unique<LineAtlas>(512, 512)), texturePool(std::make_shared<TexturePool>()), - painter(util::make_unique<Painter>(*spriteAtlas, *glyphAtlas, *lineAtlas)) + painter(util::make_unique<Painter>(*spriteAtlas, *glyphAtlas, *lineAtlas)), + annotationManager(util::make_unique<AnnotationManager>()) { view.initialize(this); } @@ -536,6 +538,57 @@ const std::string &Map::getAccessToken() const { return accessToken; } +#pragma mark - Annotations + +void Map::setDefaultPointAnnotationSymbol(std::string& symbol) { + assert(std::this_thread::get_id() == mainThread); + annotationManager->setDefaultPointAnnotationSymbol(symbol); +} + +uint32_t Map::addPointAnnotation(LatLng point, std::string& symbol) { + assert(std::this_thread::get_id() == mainThread); + std::vector<LatLng> points({ point }); + std::vector<std::string> symbols({ symbol }); + return addPointAnnotations(points, symbols)[0]; +} + +std::vector<uint32_t> Map::addPointAnnotations(std::vector<LatLng> points, std::vector<std::string>& symbols) { + assert(std::this_thread::get_id() == mainThread); + auto result = annotationManager->addPointAnnotations(points, symbols, *this); + updateAnnotationTiles(result.first); + return result.second; +} + +void Map::removeAnnotation(uint32_t annotation) { + assert(std::this_thread::get_id() == mainThread); + removeAnnotations({ annotation }); +} + +void Map::removeAnnotations(std::vector<uint32_t> annotations) { + assert(std::this_thread::get_id() == mainThread); + auto result = annotationManager->removeAnnotations(annotations); + updateAnnotationTiles(result); +} + +std::vector<uint32_t> Map::getAnnotationsInBounds(LatLngBounds bounds) const { + assert(std::this_thread::get_id() == mainThread); + return annotationManager->getAnnotationsInBounds(bounds, *this); +} + +LatLngBounds Map::getBoundsForAnnotations(std::vector<uint32_t> annotations) const { + assert(std::this_thread::get_id() == mainThread); + return annotationManager->getBoundsForAnnotations(annotations); +} + +void Map::updateAnnotationTiles(std::vector<Tile::ID>& ids) { + for (const auto &source : activeSources) { + if (source->info.type == SourceType::Annotations) { + source->source->invalidateTiles(*this, ids); + return; + } + } +} + #pragma mark - Toggles void Map::setDebug(bool value) { @@ -643,6 +696,7 @@ void Map::updateSources(const util::ptr<StyleLayerGroup> &group) { if (layer->bucket && layer->bucket->style_source) { (*activeSources.emplace(layer->bucket->style_source).first)->enabled = true; } + } } diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 447f25d4b7..982b084e17 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -21,6 +21,7 @@ #include <mbgl/map/vector_tile_data.hpp> #include <mbgl/map/raster_tile_data.hpp> +#include <mbgl/map/live_tile_data.hpp> #include <algorithm> @@ -190,13 +191,22 @@ TileData::State Source::addTile(Map &map, Environment &env, uv::worker &worker, glyphAtlas, glyphStore, spriteAtlas, sprite, info, env); + new_tile.data->request(worker, map.getState().getPixelRatio(), callback); } else if (info.type == SourceType::Raster) { new_tile.data = std::make_shared<RasterTileData>(normalized_id, texturePool, info, env); + new_tile.data->request(worker, map.getState().getPixelRatio(), callback); + } else if (info.type == SourceType::Annotations) { + util::ptr<AnnotationManager> annotationManager = map.getAnnotationManager(); + new_tile.data = std::make_shared<LiveTileData>(normalized_id, + annotationManager, + map.getMaxZoom(), style, + glyphAtlas, glyphStore, + spriteAtlas, sprite, + info, env); + new_tile.data->reparse(worker, callback); } else { throw std::runtime_error("source type not implemented"); } - - new_tile.data->request(worker, map.getState().getPixelRatio(), callback); tile_data.emplace(new_tile.data->id, new_tile.data); } @@ -368,4 +378,12 @@ void Source::update(Map &map, updated = map.getTime(); } +void Source::invalidateTiles(Map& map, std::vector<Tile::ID>& ids) { + for (auto& id : ids) { + tiles.erase(id); + tile_data.erase(id); + } + map.triggerUpdate(); +} + } diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp index 061908b89d..211713015c 100644 --- a/src/mbgl/map/source.hpp +++ b/src/mbgl/map/source.hpp @@ -37,6 +37,7 @@ public: void load(Map &, Environment &); void update(Map &, Environment &, uv::worker &, util::ptr<Style>, GlyphAtlas &, GlyphStore &, SpriteAtlas &, util::ptr<Sprite>, TexturePool &, std::function<void()> callback); + void invalidateTiles(Map&, std::vector<Tile::ID>&); void updateMatrices(const mat4 &projMatrix, const TransformState &transform); void drawClippingMasks(Painter &painter); diff --git a/src/mbgl/map/tile_parser.cpp b/src/mbgl/map/tile_parser.cpp index 0540c7d7d3..5c91c310ec 100644 --- a/src/mbgl/map/tile_parser.cpp +++ b/src/mbgl/map/tile_parser.cpp @@ -17,7 +17,6 @@ #include <mbgl/text/collision.hpp> #include <mbgl/text/glyph.hpp> #include <mbgl/map/map.hpp> - #include <mbgl/util/std.hpp> #include <mbgl/util/utf.hpp> @@ -30,14 +29,14 @@ namespace mbgl { // its header file. TileParser::~TileParser() = default; -TileParser::TileParser(const std::string& rawData_, +TileParser::TileParser(const GeometryTile& geometryTile_, VectorTileData& tile_, const util::ptr<const Style>& style_, GlyphAtlas& glyphAtlas_, GlyphStore& glyphStore_, SpriteAtlas& spriteAtlas_, const util::ptr<Sprite>& sprite_) - : vectorTile(pbf((const uint8_t *)rawData_.data(), rawData_.size())), + : geometryTile(geometryTile_), tile(tile_), style(style_), glyphAtlas(glyphAtlas_), @@ -188,7 +187,7 @@ std::unique_ptr<Bucket> TileParser::createBucket(const StyleBucket &bucketDesc) if (tile.id.z >= std::ceil(bucketDesc.max_zoom)) return nullptr; if (bucketDesc.visibility == mbgl::VisibilityType::None) return nullptr; - auto layer = vectorTile.getLayer(bucketDesc.source_layer); + auto layer = geometryTile.getLayer(bucketDesc.source_layer); if (layer) { if (bucketDesc.type == StyleLayerType::Fill) { return createFillBucket(*layer, bucketDesc); diff --git a/src/mbgl/map/tile_parser.hpp b/src/mbgl/map/tile_parser.hpp index e7c05e1b1e..0ad42fdc91 100644 --- a/src/mbgl/map/tile_parser.hpp +++ b/src/mbgl/map/tile_parser.hpp @@ -9,6 +9,7 @@ #include <mbgl/text/glyph.hpp> #include <mbgl/util/ptr.hpp> #include <mbgl/util/noncopyable.hpp> + #include <cstdint> #include <iosfwd> #include <string> @@ -16,7 +17,6 @@ namespace mbgl { class Bucket; -class TexturePool; class FontStack; class GlyphAtlas; class GlyphStore; @@ -31,12 +31,10 @@ class StyleLayoutSymbol; class StyleLayerGroup; class VectorTileData; class Collision; -class TexturePool; -class TileParser : private util::noncopyable -{ +class TileParser : private util::noncopyable { public: - TileParser(const std::string& rawData, + TileParser(const GeometryTile& geometryTile, VectorTileData& tile, const util::ptr<const Style>& style, GlyphAtlas& glyphAtlas, @@ -61,7 +59,7 @@ private: void addBucketGeometries(Bucket&, const GeometryTileLayer&, const FilterExpression&); private: - const VectorTile vectorTile; + const GeometryTile& geometryTile; VectorTileData& tile; // Cross-thread shared data. diff --git a/src/mbgl/map/vector_tile.cpp b/src/mbgl/map/vector_tile.cpp index bf10f8706e..c0d860b179 100644 --- a/src/mbgl/map/vector_tile.cpp +++ b/src/mbgl/map/vector_tile.cpp @@ -133,7 +133,7 @@ VectorTile::VectorTile(pbf tile_pbf) { } } -util::ptr<const GeometryTileLayer> VectorTile::getLayer(const std::string& name) const { +util::ptr<GeometryTileLayer> VectorTile::getLayer(const std::string& name) const { auto layer_it = layers.find(name); if (layer_it != layers.end()) { return layer_it->second; diff --git a/src/mbgl/map/vector_tile.hpp b/src/mbgl/map/vector_tile.hpp index 6685bb613e..f6a2d615bc 100644 --- a/src/mbgl/map/vector_tile.hpp +++ b/src/mbgl/map/vector_tile.hpp @@ -48,10 +48,10 @@ class VectorTile : public GeometryTile { public: VectorTile(pbf); - util::ptr<const GeometryTileLayer> getLayer(const std::string&) const override; + util::ptr<GeometryTileLayer> getLayer(const std::string&) const override; private: - std::unordered_map<std::string, util::ptr<const GeometryTileLayer>> layers; + std::unordered_map<std::string, util::ptr<GeometryTileLayer>> layers; }; } diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index e165863bec..3e318b0856 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -1,20 +1,24 @@ #include <mbgl/map/vector_tile_data.hpp> #include <mbgl/map/tile_parser.hpp> #include <mbgl/util/std.hpp> -#include <mbgl/map/map.hpp> #include <mbgl/style/style_layer.hpp> #include <mbgl/style/style_bucket.hpp> #include <mbgl/style/style_source.hpp> #include <mbgl/geometry/glyph_atlas.hpp> #include <mbgl/platform/log.hpp> +#include <mbgl/util/pbf.hpp> using namespace mbgl; VectorTileData::VectorTileData(Tile::ID const& id_, - float mapMaxZoom, util::ptr<Style> style_, - GlyphAtlas& glyphAtlas_, GlyphStore& glyphStore_, - SpriteAtlas& spriteAtlas_, util::ptr<Sprite> sprite_, - const SourceInfo& source_, Environment &env_) + float mapMaxZoom, + util::ptr<Style> style_, + GlyphAtlas& glyphAtlas_, + GlyphStore& glyphStore_, + SpriteAtlas& spriteAtlas_, + util::ptr<Sprite> sprite_, + const SourceInfo& source_, + Environment& env_) : TileData(id_, source_, env_), glyphAtlas(glyphAtlas_), glyphStore(glyphStore_), @@ -28,7 +32,6 @@ VectorTileData::~VectorTileData() { glyphAtlas.removeGlyphs(reinterpret_cast<uintptr_t>(this)); } - void VectorTileData::parse() { if (state != State::loaded) { return; @@ -42,9 +45,10 @@ void VectorTileData::parse() { // Parsing creates state that is encapsulated in TileParser. While parsing, // the TileParser object writes results into this objects. All other state // is going to be discarded afterwards. - TileParser parser(data, *this, style, - glyphAtlas, glyphStore, - spriteAtlas, sprite); + VectorTile vectorTile(pbf((const uint8_t *)data.data(), data.size())); + const VectorTile* vt = &vectorTile; + TileParser parser(*vt, *this, style, glyphAtlas, glyphStore, spriteAtlas, sprite); + // Clear the style so that we don't have a cycle in the shared_ptr references. style.reset(); diff --git a/src/mbgl/map/vector_tile_data.hpp b/src/mbgl/map/vector_tile_data.hpp index 1c48fc5f23..e097c9bc59 100644 --- a/src/mbgl/map/vector_tile_data.hpp +++ b/src/mbgl/map/vector_tile_data.hpp @@ -30,8 +30,15 @@ class VectorTileData : public TileData { friend class TileParser; public: - VectorTileData(Tile::ID const &, float mapMaxZoom, util::ptr<Style>, GlyphAtlas &, GlyphStore &, - SpriteAtlas &, util::ptr<Sprite>, const SourceInfo &, Environment &); + VectorTileData(Tile::ID const&, + float mapMaxZoom, + util::ptr<Style>, + GlyphAtlas&, + GlyphStore&, + SpriteAtlas&, + util::ptr<Sprite>, + const SourceInfo&, + Environment&); ~VectorTileData(); void parse() override; diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp index 25bf9bf665..f2bd8e6c88 100644 --- a/src/mbgl/style/style_parser.cpp +++ b/src/mbgl/style/style_parser.cpp @@ -29,6 +29,37 @@ void StyleParser::parse(JSVal document) { if (document.HasMember("layers")) { root = createLayers(document["layers"]); parseLayers(); + + // create point annotations layer + // + std::string id = util::ANNOTATIONS_POINTS_LAYER_ID; + + std::map<ClassID, ClassProperties> paints; + util::ptr<StyleLayer> annotations = std::make_shared<StyleLayer>(id, std::move(paints)); + annotations->type = StyleLayerType::Symbol; + layers.emplace(id, std::pair<JSVal, util::ptr<StyleLayer>> { JSVal(id), annotations }); + root->layers.emplace_back(annotations); + + util::ptr<StyleBucket> pointBucket = std::make_shared<StyleBucket>(annotations->type); + pointBucket->name = annotations->id; + pointBucket->source_layer = annotations->id; + + rapidjson::Document d; + rapidjson::Value iconImage(rapidjson::kObjectType); + iconImage.AddMember("icon-image", "{sprite}", d.GetAllocator()); + parseLayout(iconImage, pointBucket); + rapidjson::Value iconOverlap(rapidjson::kObjectType); + iconOverlap.AddMember("icon-allow-overlap", true, d.GetAllocator()); + parseLayout(iconOverlap, pointBucket); + + SourceInfo& info = sources.emplace(id, std::make_shared<StyleSource>()).first->second->info; + info.type = SourceType::Annotations; + + auto source_it = sources.find(id); + pointBucket->style_source = source_it->second; + annotations->bucket = pointBucket; + // + // end point annotations } if (document.HasMember("sprite")) { diff --git a/src/mbgl/style/types.hpp b/src/mbgl/style/types.hpp index 78938a2823..3b24d63998 100644 --- a/src/mbgl/style/types.hpp +++ b/src/mbgl/style/types.hpp @@ -48,7 +48,8 @@ enum class SourceType : uint8_t { Vector, Raster, GeoJSON, - Video + Video, + Annotations }; MBGL_DEFINE_ENUM_CLASS(SourceTypeClass, SourceType, { @@ -56,6 +57,7 @@ MBGL_DEFINE_ENUM_CLASS(SourceTypeClass, SourceType, { { SourceType::Raster, "raster" }, { SourceType::GeoJSON, "geojson" }, { SourceType::Video, "video" }, + { SourceType::Annotations, "annotations" }, }); // ------------------------------------------------------------------------------------------------- diff --git a/src/mbgl/util/constants.cpp b/src/mbgl/util/constants.cpp index ccdbeba23a..ae5b21ddc4 100644 --- a/src/mbgl/util/constants.cpp +++ b/src/mbgl/util/constants.cpp @@ -8,6 +8,8 @@ const double mbgl::util::M2PI = 2 * M_PI; const double mbgl::util::EARTH_RADIUS_M = 6378137; const double mbgl::util::LATITUDE_MAX = 85.05112878; +const std::string mbgl::util::ANNOTATIONS_POINTS_LAYER_ID = "com.mapbox.annotations.points"; + #if defined(DEBUG) const bool mbgl::debug::tileParseWarnings = false; const bool mbgl::debug::styleParseWarnings = false; |