| 1 | #include <mbgl/annotation/annotation_manager.hpp> |
| 2 | #include <mbgl/annotation/annotation_source.hpp> |
| 3 | #include <mbgl/annotation/annotation_tile.hpp> |
| 4 | #include <mbgl/annotation/symbol_annotation_impl.hpp> |
| 5 | #include <mbgl/annotation/line_annotation_impl.hpp> |
| 6 | #include <mbgl/annotation/fill_annotation_impl.hpp> |
| 7 | #include <mbgl/style/style.hpp> |
| 8 | #include <mbgl/style/style_impl.hpp> |
| 9 | #include <mbgl/style/layers/symbol_layer.hpp> |
| 10 | #include <mbgl/style/layers/symbol_layer_impl.hpp> |
| 11 | #include <mbgl/style/expression/dsl.hpp> |
| 12 | #include <mbgl/storage/file_source.hpp> |
| 13 | |
| 14 | #include <boost/function_output_iterator.hpp> |
| 15 | |
| 16 | namespace mbgl { |
| 17 | |
| 18 | using namespace style; |
| 19 | |
| 20 | const std::string AnnotationManager::SourceID = "com.mapbox.annotations" ; |
| 21 | const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points" ; |
| 22 | const std::string AnnotationManager::ShapeLayerID = "com.mapbox.annotations.shape." ; |
| 23 | |
| 24 | AnnotationManager::AnnotationManager(Style& style_) |
| 25 | : style(style_) { |
| 26 | }; |
| 27 | |
| 28 | AnnotationManager::~AnnotationManager() = default; |
| 29 | |
| 30 | void AnnotationManager::setStyle(Style& style_) { |
| 31 | style = style_; |
| 32 | } |
| 33 | |
| 34 | void AnnotationManager::onStyleLoaded() { |
| 35 | updateStyle(); |
| 36 | } |
| 37 | |
| 38 | AnnotationID AnnotationManager::addAnnotation(const Annotation& annotation) { |
| 39 | std::lock_guard<std::mutex> lock(mutex); |
| 40 | AnnotationID id = nextID++; |
| 41 | Annotation::visit(v: annotation, f: [&] (const auto& annotation_) { |
| 42 | this->add(id, annotation_); |
| 43 | }); |
| 44 | dirty = true; |
| 45 | return id; |
| 46 | } |
| 47 | |
| 48 | bool AnnotationManager::updateAnnotation(const AnnotationID& id, const Annotation& annotation) { |
| 49 | std::lock_guard<std::mutex> lock(mutex); |
| 50 | Annotation::visit(v: annotation, f: [&] (const auto& annotation_) { |
| 51 | this->update(id, annotation_); |
| 52 | }); |
| 53 | return dirty; |
| 54 | } |
| 55 | |
| 56 | void AnnotationManager::removeAnnotation(const AnnotationID& id) { |
| 57 | std::lock_guard<std::mutex> lock(mutex); |
| 58 | remove(id); |
| 59 | dirty = true; |
| 60 | } |
| 61 | |
| 62 | void AnnotationManager::add(const AnnotationID& id, const SymbolAnnotation& annotation) { |
| 63 | auto impl = std::make_shared<SymbolAnnotationImpl>(args: id, args: annotation); |
| 64 | symbolTree.insert(conv_or_rng: impl); |
| 65 | symbolAnnotations.emplace(args: id, args&: impl); |
| 66 | } |
| 67 | |
| 68 | void AnnotationManager::add(const AnnotationID& id, const LineAnnotation& annotation) { |
| 69 | ShapeAnnotationImpl& impl = *shapeAnnotations.emplace(args: id, |
| 70 | args: std::make_unique<LineAnnotationImpl>(args: id, args: annotation)).first->second; |
| 71 | impl.updateStyle(*style.get().impl); |
| 72 | } |
| 73 | |
| 74 | void AnnotationManager::add(const AnnotationID& id, const FillAnnotation& annotation) { |
| 75 | ShapeAnnotationImpl& impl = *shapeAnnotations.emplace(args: id, |
| 76 | args: std::make_unique<FillAnnotationImpl>(args: id, args: annotation)).first->second; |
| 77 | impl.updateStyle(*style.get().impl); |
| 78 | } |
| 79 | |
| 80 | void AnnotationManager::update(const AnnotationID& id, const SymbolAnnotation& annotation) { |
| 81 | auto it = symbolAnnotations.find(x: id); |
| 82 | if (it == symbolAnnotations.end()) { |
| 83 | assert(false); // Attempt to update a non-existent symbol annotation |
| 84 | return; |
| 85 | } |
| 86 | |
| 87 | const SymbolAnnotation& existing = it->second->annotation; |
| 88 | |
| 89 | if (existing.geometry != annotation.geometry || existing.icon != annotation.icon) { |
| 90 | dirty = true; |
| 91 | |
| 92 | remove(id); |
| 93 | add(id, annotation); |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | void AnnotationManager::update(const AnnotationID& id, const LineAnnotation& annotation) { |
| 98 | auto it = shapeAnnotations.find(x: id); |
| 99 | if (it == shapeAnnotations.end()) { |
| 100 | assert(false); // Attempt to update a non-existent shape annotation |
| 101 | return; |
| 102 | } |
| 103 | |
| 104 | shapeAnnotations.erase(position: it); |
| 105 | add(id, annotation); |
| 106 | dirty = true; |
| 107 | } |
| 108 | |
| 109 | void AnnotationManager::update(const AnnotationID& id, const FillAnnotation& annotation) { |
| 110 | auto it = shapeAnnotations.find(x: id); |
| 111 | if (it == shapeAnnotations.end()) { |
| 112 | assert(false); // Attempt to update a non-existent shape annotation |
| 113 | return; |
| 114 | } |
| 115 | |
| 116 | shapeAnnotations.erase(position: it); |
| 117 | add(id, annotation); |
| 118 | dirty = true; |
| 119 | } |
| 120 | |
| 121 | void AnnotationManager::remove(const AnnotationID& id) { |
| 122 | if (symbolAnnotations.find(x: id) != symbolAnnotations.end()) { |
| 123 | symbolTree.remove(conv_or_rng: symbolAnnotations.at(k: id)); |
| 124 | symbolAnnotations.erase(x: id); |
| 125 | } else if (shapeAnnotations.find(x: id) != shapeAnnotations.end()) { |
| 126 | auto it = shapeAnnotations.find(x: id); |
| 127 | *style.get().impl->removeLayer(layerID: it->second->layerID); |
| 128 | shapeAnnotations.erase(position: it); |
| 129 | } else { |
| 130 | assert(false); // Should never happen |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | std::unique_ptr<AnnotationTileData> AnnotationManager::getTileData(const CanonicalTileID& tileID) { |
| 135 | if (symbolAnnotations.empty() && shapeAnnotations.empty()) |
| 136 | return nullptr; |
| 137 | |
| 138 | auto tileData = std::make_unique<AnnotationTileData>(); |
| 139 | |
| 140 | auto pointLayer = tileData->addLayer(PointLayerID); |
| 141 | |
| 142 | LatLngBounds tileBounds(tileID); |
| 143 | |
| 144 | symbolTree.query(predicates: boost::geometry::index::intersects(g: tileBounds), |
| 145 | out_it: boost::make_function_output_iterator(f: [&](const auto& val){ |
| 146 | val->updateLayer(tileID, *pointLayer); |
| 147 | })); |
| 148 | |
| 149 | for (const auto& shape : shapeAnnotations) { |
| 150 | shape.second->updateTileData(tileID, *tileData); |
| 151 | } |
| 152 | |
| 153 | return tileData; |
| 154 | } |
| 155 | |
| 156 | void AnnotationManager::updateStyle() { |
| 157 | // Create annotation source, point layer, and point bucket. We do everything via Style::Impl |
| 158 | // because we don't want annotation mutations to trigger Style::Impl::styleMutated to be set. |
| 159 | if (!style.get().impl->getSource(id: SourceID)) { |
| 160 | style.get().impl->addSource(std::make_unique<AnnotationSource>()); |
| 161 | |
| 162 | std::unique_ptr<SymbolLayer> layer = std::make_unique<SymbolLayer>(args: PointLayerID, args: SourceID); |
| 163 | |
| 164 | using namespace expression::dsl; |
| 165 | layer->setSourceLayer(PointLayerID); |
| 166 | layer->setIconImage(PropertyExpression<std::string>(concat(inputs: vec(args: literal(value: SourceID + "." ), args: toString(get(value: "sprite" )))))); |
| 167 | layer->setIconAllowOverlap(true); |
| 168 | layer->setIconIgnorePlacement(true); |
| 169 | |
| 170 | style.get().impl->addLayer(std::move(layer)); |
| 171 | } |
| 172 | |
| 173 | std::lock_guard<std::mutex> lock(mutex); |
| 174 | |
| 175 | for (const auto& shape : shapeAnnotations) { |
| 176 | shape.second->updateStyle(*style.get().impl); |
| 177 | } |
| 178 | |
| 179 | for (const auto& image : images) { |
| 180 | // Call addImage even for images we may have previously added, because we must support |
| 181 | // addAnnotationImage being used to update an existing image. Creating a new image is |
| 182 | // relatively cheap, as it copies only the Immutable reference. (We can't keep track |
| 183 | // of which images need to be added because we don't know if the style is the same |
| 184 | // instance as in the last updateStyle call. If it's a new style, we need to add all |
| 185 | // images.) |
| 186 | style.get().impl->addImage(std::make_unique<style::Image>(args: image.second)); |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | void AnnotationManager::updateData() { |
| 191 | std::lock_guard<std::mutex> lock(mutex); |
| 192 | if (dirty) { |
| 193 | for (auto& tile : tiles) { |
| 194 | tile->setData(getTileData(tileID: tile->id.canonical)); |
| 195 | } |
| 196 | dirty = false; |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | void AnnotationManager::addTile(AnnotationTile& tile) { |
| 201 | std::lock_guard<std::mutex> lock(mutex); |
| 202 | tiles.insert(x: &tile); |
| 203 | tile.setData(getTileData(tileID: tile.id.canonical)); |
| 204 | } |
| 205 | |
| 206 | void AnnotationManager::removeTile(AnnotationTile& tile) { |
| 207 | std::lock_guard<std::mutex> lock(mutex); |
| 208 | tiles.erase(x: &tile); |
| 209 | } |
| 210 | |
| 211 | // To ensure that annotation images do not collide with images from the style, |
| 212 | // we prefix input image IDs with "com.mapbox.annotations". |
| 213 | static std::string prefixedImageID(const std::string& id) { |
| 214 | return AnnotationManager::SourceID + "." + id; |
| 215 | } |
| 216 | |
| 217 | void AnnotationManager::addImage(std::unique_ptr<style::Image> image) { |
| 218 | std::lock_guard<std::mutex> lock(mutex); |
| 219 | const std::string id = prefixedImageID(id: image->getID()); |
| 220 | images.erase(x: id); |
| 221 | auto inserted = images.emplace(args: id, args: style::Image(id, image->getImage().clone(), |
| 222 | image->getPixelRatio(), image->isSdf())); |
| 223 | style.get().impl->addImage(std::make_unique<style::Image>(args&: inserted.first->second)); |
| 224 | } |
| 225 | |
| 226 | void AnnotationManager::removeImage(const std::string& id_) { |
| 227 | std::lock_guard<std::mutex> lock(mutex); |
| 228 | const std::string id = prefixedImageID(id: id_); |
| 229 | images.erase(x: id); |
| 230 | style.get().impl->removeImage(id); |
| 231 | } |
| 232 | |
| 233 | double AnnotationManager::getTopOffsetPixelsForImage(const std::string& id_) { |
| 234 | std::lock_guard<std::mutex> lock(mutex); |
| 235 | const std::string id = prefixedImageID(id: id_); |
| 236 | auto it = images.find(x: id); |
| 237 | return it != images.end() ? -(it->second.getImage().size.height / it->second.getPixelRatio()) / 2 : 0; |
| 238 | } |
| 239 | |
| 240 | } // namespace mbgl |
| 241 | |