diff options
Diffstat (limited to 'src/mbgl/annotation/annotation_manager.cpp')
-rw-r--r-- | src/mbgl/annotation/annotation_manager.cpp | 191 |
1 files changed, 103 insertions, 88 deletions
diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp index 88153f5fb7..1f2d01e9eb 100644 --- a/src/mbgl/annotation/annotation_manager.cpp +++ b/src/mbgl/annotation/annotation_manager.cpp @@ -4,8 +4,8 @@ #include <mbgl/annotation/symbol_annotation_impl.hpp> #include <mbgl/annotation/line_annotation_impl.hpp> #include <mbgl/annotation/fill_annotation_impl.hpp> -#include <mbgl/annotation/style_sourced_annotation_impl.hpp> #include <mbgl/style/style.hpp> +#include <mbgl/style/style_impl.hpp> #include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> #include <mbgl/storage/file_source.hpp> @@ -19,39 +19,42 @@ using namespace style; const std::string AnnotationManager::SourceID = "com.mapbox.annotations"; const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points"; -AnnotationManager::AnnotationManager(float pixelRatio) - : spriteAtlas({ 1024, 1024 }, pixelRatio) { - // This is a special atlas, holding only images added via addIcon, so we always treat it as - // loaded. - spriteAtlas.markAsLoaded(); -} +AnnotationManager::AnnotationManager(Style& style_) + : style(style_) { +}; AnnotationManager::~AnnotationManager() = default; +void AnnotationManager::setStyle(Style& style_) { + style = style_; +} + +void AnnotationManager::onStyleLoaded() { + updateStyle(); +} + AnnotationID AnnotationManager::addAnnotation(const Annotation& annotation, const uint8_t maxZoom) { + std::lock_guard<std::mutex> lock(mutex); AnnotationID id = nextID++; Annotation::visit(annotation, [&] (const auto& annotation_) { this->add(id, annotation_, maxZoom); }); + dirty = true; return id; } -Update AnnotationManager::updateAnnotation(const AnnotationID& id, const Annotation& annotation, const uint8_t maxZoom) { - return Annotation::visit(annotation, [&] (const auto& annotation_) { - return this->update(id, annotation_, maxZoom); +bool AnnotationManager::updateAnnotation(const AnnotationID& id, const Annotation& annotation, const uint8_t maxZoom) { + std::lock_guard<std::mutex> lock(mutex); + Annotation::visit(annotation, [&] (const auto& annotation_) { + this->update(id, annotation_, maxZoom); }); + return dirty; } void AnnotationManager::removeAnnotation(const AnnotationID& id) { - if (symbolAnnotations.find(id) != symbolAnnotations.end()) { - symbolTree.remove(symbolAnnotations.at(id)); - symbolAnnotations.erase(id); - } else if (shapeAnnotations.find(id) != shapeAnnotations.end()) { - obsoleteShapeAnnotationLayers.insert(shapeAnnotations.at(id)->layerID); - shapeAnnotations.erase(id); - } else { - assert(false); // Should never happen - } + std::lock_guard<std::mutex> lock(mutex); + remove(id); + dirty = true; } void AnnotationManager::add(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t) { @@ -63,82 +66,67 @@ void AnnotationManager::add(const AnnotationID& id, const SymbolAnnotation& anno void AnnotationManager::add(const AnnotationID& id, const LineAnnotation& annotation, const uint8_t maxZoom) { ShapeAnnotationImpl& impl = *shapeAnnotations.emplace(id, std::make_unique<LineAnnotationImpl>(id, annotation, maxZoom)).first->second; - obsoleteShapeAnnotationLayers.erase(impl.layerID); + impl.updateStyle(*style.get().impl); } void AnnotationManager::add(const AnnotationID& id, const FillAnnotation& annotation, const uint8_t maxZoom) { ShapeAnnotationImpl& impl = *shapeAnnotations.emplace(id, std::make_unique<FillAnnotationImpl>(id, annotation, maxZoom)).first->second; - obsoleteShapeAnnotationLayers.erase(impl.layerID); -} - -void AnnotationManager::add(const AnnotationID& id, const StyleSourcedAnnotation& annotation, const uint8_t maxZoom) { - ShapeAnnotationImpl& impl = *shapeAnnotations.emplace(id, - std::make_unique<StyleSourcedAnnotationImpl>(id, annotation, maxZoom)).first->second; - obsoleteShapeAnnotationLayers.erase(impl.layerID); + impl.updateStyle(*style.get().impl); } -Update AnnotationManager::update(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t maxZoom) { - Update result = Update::Nothing; - +void AnnotationManager::update(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t maxZoom) { auto it = symbolAnnotations.find(id); if (it == symbolAnnotations.end()) { assert(false); // Attempt to update a non-existent symbol annotation - return result; + return; } const SymbolAnnotation& existing = it->second->annotation; - if (existing.geometry != annotation.geometry) { - result |= Update::AnnotationData; - } - - if (existing.icon != annotation.icon) { - result |= Update::AnnotationData | Update::AnnotationStyle; - } + if (existing.geometry != annotation.geometry || existing.icon != annotation.icon) { + dirty = true; - if (result != Update::Nothing) { - removeAndAdd(id, annotation, maxZoom); + remove(id); + add(id, annotation, maxZoom); } - - return result; } -Update AnnotationManager::update(const AnnotationID& id, const LineAnnotation& annotation, const uint8_t maxZoom) { +void AnnotationManager::update(const AnnotationID& id, const LineAnnotation& annotation, const uint8_t maxZoom) { auto it = shapeAnnotations.find(id); if (it == shapeAnnotations.end()) { assert(false); // Attempt to update a non-existent shape annotation - return Update::Nothing; + return; } - removeAndAdd(id, annotation, maxZoom); - return Update::AnnotationData | Update::AnnotationStyle; -} -Update AnnotationManager::update(const AnnotationID& id, const FillAnnotation& annotation, const uint8_t maxZoom) { - auto it = shapeAnnotations.find(id); - if (it == shapeAnnotations.end()) { - assert(false); // Attempt to update a non-existent shape annotation - return Update::Nothing; - } - removeAndAdd(id, annotation, maxZoom); - return Update::AnnotationData | Update::AnnotationStyle; + shapeAnnotations.erase(it); + add(id, annotation, maxZoom); + dirty = true; } -Update AnnotationManager::update(const AnnotationID& id, const StyleSourcedAnnotation& annotation, const uint8_t maxZoom) { +void AnnotationManager::update(const AnnotationID& id, const FillAnnotation& annotation, const uint8_t maxZoom) { auto it = shapeAnnotations.find(id); if (it == shapeAnnotations.end()) { assert(false); // Attempt to update a non-existent shape annotation - return Update::Nothing; + return; } - removeAndAdd(id, annotation, maxZoom); - return Update::AnnotationData | Update::AnnotationStyle; + + shapeAnnotations.erase(it); + add(id, annotation, maxZoom); + dirty = true; } -void AnnotationManager::removeAndAdd(const AnnotationID& id, const Annotation& annotation, const uint8_t maxZoom) { - removeAnnotation(id); - Annotation::visit(annotation, [&] (const auto& annotation_) { - this->add(id, annotation_, maxZoom); - }); +void AnnotationManager::remove(const AnnotationID& id) { + if (symbolAnnotations.find(id) != symbolAnnotations.end()) { + symbolTree.remove(symbolAnnotations.at(id)); + symbolAnnotations.erase(id); + } else if (shapeAnnotations.find(id) != shapeAnnotations.end()) { + auto it = shapeAnnotations.find(id); + *style.get().impl->removeLayer(it->second->layerID); + shapeAnnotations.erase(it); + } else { + assert(false); // Should never happen + } } std::unique_ptr<AnnotationTileData> AnnotationManager::getTileData(const CanonicalTileID& tileID) { @@ -147,13 +135,13 @@ std::unique_ptr<AnnotationTileData> AnnotationManager::getTileData(const Canonic auto tileData = std::make_unique<AnnotationTileData>(); - AnnotationTileLayer& pointLayer = tileData->layers.emplace(PointLayerID, PointLayerID).first->second; + auto pointLayer = tileData->addLayer(PointLayerID); LatLngBounds tileBounds(tileID); symbolTree.query(boost::geometry::index::intersects(tileBounds), boost::make_function_output_iterator([&](const auto& val){ - val->updateLayer(tileID, pointLayer); + val->updateLayer(tileID, *pointLayer); })); for (const auto& shape : shapeAnnotations) { @@ -163,60 +151,87 @@ std::unique_ptr<AnnotationTileData> AnnotationManager::getTileData(const Canonic return tileData; } -void AnnotationManager::updateStyle(Style& style) { - // Create annotation source, point layer, and point bucket - if (!style.getSource(SourceID)) { - style.addSource(std::make_unique<AnnotationSource>()); +void AnnotationManager::updateStyle() { + // Create annotation source, point layer, and point bucket. We do everything via Style::Impl + // because we don't want annotation mutations to trigger Style::Impl::styleMutated to be set. + if (!style.get().impl->getSource(SourceID)) { + style.get().impl->addSource(std::make_unique<AnnotationSource>()); std::unique_ptr<SymbolLayer> layer = std::make_unique<SymbolLayer>(PointLayerID, SourceID); layer->setSourceLayer(PointLayerID); - layer->setIconImage({"{sprite}"}); + layer->setIconImage({SourceID + ".{sprite}"}); layer->setIconAllowOverlap(true); layer->setIconIgnorePlacement(true); - style.addLayer(std::move(layer)); + style.get().impl->addLayer(std::move(layer)); } + std::lock_guard<std::mutex> lock(mutex); + for (const auto& shape : shapeAnnotations) { - shape.second->updateStyle(style); + shape.second->updateStyle(*style.get().impl); } - for (const auto& layer : obsoleteShapeAnnotationLayers) { - if (style.getLayer(layer)) { - style.removeLayer(layer); - } + for (const auto& image : images) { + // Call addImage even for images we may have previously added, because we must support + // addAnnotationImage being used to update an existing image. Creating a new image is + // relatively cheap, as it copies only the Immutable reference. (We can't keep track + // of which images need to be added because we don't know if the style is the same + // instance as in the last updateStyle call. If it's a new style, we need to add all + // images.) + style.get().impl->addImage(std::make_unique<style::Image>(image.second)); } - - obsoleteShapeAnnotationLayers.clear(); } void AnnotationManager::updateData() { - for (auto& tile : tiles) { - tile->setData(getTileData(tile->id.canonical)); + std::lock_guard<std::mutex> lock(mutex); + if (dirty) { + for (auto& tile : tiles) { + tile->setData(getTileData(tile->id.canonical)); + } + dirty = false; } } void AnnotationManager::addTile(AnnotationTile& tile) { + std::lock_guard<std::mutex> lock(mutex); tiles.insert(&tile); tile.setData(getTileData(tile.id.canonical)); } void AnnotationManager::removeTile(AnnotationTile& tile) { + std::lock_guard<std::mutex> lock(mutex); tiles.erase(&tile); } -void AnnotationManager::addImage(const std::string& id, std::unique_ptr<style::Image> image) { - spriteAtlas.addImage(id, std::move(image)); +// To ensure that annotation images do not collide with images from the style, +// we prefix input image IDs with "com.mapbox.annotations". +static std::string prefixedImageID(const std::string& id) { + return AnnotationManager::SourceID + "." + id; +} + +void AnnotationManager::addImage(std::unique_ptr<style::Image> image) { + std::lock_guard<std::mutex> lock(mutex); + const std::string id = prefixedImageID(image->getID()); + images.erase(id); + auto inserted = images.emplace(id, style::Image(id, image->getImage().clone(), + image->getPixelRatio(), image->isSdf())); + style.get().impl->addImage(std::make_unique<style::Image>(inserted.first->second)); } -void AnnotationManager::removeImage(const std::string& id) { - spriteAtlas.removeImage(id); +void AnnotationManager::removeImage(const std::string& id_) { + std::lock_guard<std::mutex> lock(mutex); + const std::string id = prefixedImageID(id_); + images.erase(id); + style.get().impl->removeImage(id); } -double AnnotationManager::getTopOffsetPixelsForImage(const std::string& id) { - const style::Image* image = spriteAtlas.getImage(id); - return image ? -(image->image.size.height / image->pixelRatio) / 2 : 0; +double AnnotationManager::getTopOffsetPixelsForImage(const std::string& id_) { + std::lock_guard<std::mutex> lock(mutex); + const std::string id = prefixedImageID(id_); + auto it = images.find(id); + return it != images.end() ? -(it->second.getImage().size.height / it->second.getPixelRatio()) / 2 : 0; } } // namespace mbgl |