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
16namespace mbgl {
17
18using namespace style;
19
20const std::string AnnotationManager::SourceID = "com.mapbox.annotations";
21const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points";
22const std::string AnnotationManager::ShapeLayerID = "com.mapbox.annotations.shape.";
23
24AnnotationManager::AnnotationManager(Style& style_)
25 : style(style_) {
26};
27
28AnnotationManager::~AnnotationManager() = default;
29
30void AnnotationManager::setStyle(Style& style_) {
31 style = style_;
32}
33
34void AnnotationManager::onStyleLoaded() {
35 updateStyle();
36}
37
38AnnotationID 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
48bool 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
56void AnnotationManager::removeAnnotation(const AnnotationID& id) {
57 std::lock_guard<std::mutex> lock(mutex);
58 remove(id);
59 dirty = true;
60}
61
62void 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
68void 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
74void 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
80void 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
97void 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
109void 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
121void 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
134std::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
156void 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
190void 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
200void 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
206void 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".
213static std::string prefixedImageID(const std::string& id) {
214 return AnnotationManager::SourceID + "." + id;
215}
216
217void 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
226void 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
233double 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

source code of qtlocation/src/3rdparty/mapbox-gl-native/src/mbgl/annotation/annotation_manager.cpp