summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2015-10-14 18:08:02 -0700
committerJohn Firebaugh <john.firebaugh@gmail.com>2015-10-20 13:54:19 -0700
commitc5b95032a5cb9d3c7c39a7a74656f33de1c68d6e (patch)
tree6c73190d5f86b40c55e810bc244d30766051acdc
parent597b2b48511b68c7a6494386b414da479c436bd7 (diff)
downloadqtlocation-mapboxgl-c5b95032a5cb9d3c7c39a7a74656f33de1c68d6e.tar.gz
[core] Annotation refactor
-rw-r--r--android/cpp/jni.cpp2
-rw-r--r--include/mbgl/annotation/annotation.hpp6
-rw-r--r--include/mbgl/map/map.hpp6
-rw-r--r--include/mbgl/util/geo.hpp4
-rw-r--r--platform/ios/MGLMapView.mm5
-rw-r--r--src/mbgl/annotation/annotation_manager.cpp537
-rw-r--r--src/mbgl/annotation/annotation_manager.hpp49
-rw-r--r--src/mbgl/annotation/annotation_tile.cpp28
-rw-r--r--src/mbgl/annotation/annotation_tile.hpp43
-rw-r--r--src/mbgl/annotation/point_annotation_impl.cpp32
-rw-r--r--src/mbgl/annotation/point_annotation_impl.hpp72
-rw-r--r--src/mbgl/annotation/shape_annotation_impl.cpp137
-rw-r--r--src/mbgl/annotation/shape_annotation_impl.hpp36
-rw-r--r--src/mbgl/map/live_tile.cpp61
-rw-r--r--src/mbgl/map/live_tile.hpp55
-rw-r--r--src/mbgl/map/live_tile_data.cpp6
-rw-r--r--src/mbgl/map/live_tile_data.hpp6
-rw-r--r--src/mbgl/map/map.cpp10
-rw-r--r--src/mbgl/map/source.cpp12
-rw-r--r--src/mbgl/map/source.hpp1
-rw-r--r--src/mbgl/util/geo.cpp12
-rw-r--r--src/mbgl/util/worker.cpp6
-rw-r--r--src/mbgl/util/worker.hpp4
23 files changed, 464 insertions, 666 deletions
diff --git a/android/cpp/jni.cpp b/android/cpp/jni.cpp
index d5fcd34e57..7397c6f5df 100644
--- a/android/cpp/jni.cpp
+++ b/android/cpp/jni.cpp
@@ -1096,7 +1096,7 @@ jlongArray JNICALL nativeGetAnnotationsInBounds(JNIEnv *env, jobject obj, jlong
bounds.ne = { neLat, neLon };
// assume only points for now
- std::vector<uint32_t> annotations = nativeMapView->getMap().getAnnotationsInBounds(bounds, mbgl::AnnotationType::Point);
+ std::vector<uint32_t> annotations = nativeMapView->getMap().getPointAnnotationsInBounds(bounds);
return std_vector_uint_to_jobject(env, annotations);
}
diff --git a/include/mbgl/annotation/annotation.hpp b/include/mbgl/annotation/annotation.hpp
index fd21cd5f6a..b3e3ab52b6 100644
--- a/include/mbgl/annotation/annotation.hpp
+++ b/include/mbgl/annotation/annotation.hpp
@@ -6,12 +6,6 @@
namespace mbgl {
-enum class AnnotationType : uint8_t {
- Any = 0,
- Point = 1 << 0,
- Shape = 1 << 1,
-};
-
using AnnotationID = uint32_t;
using AnnotationIDs = std::vector<AnnotationID>;
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
index 8a381cda65..70807f126f 100644
--- a/include/mbgl/map/map.hpp
+++ b/include/mbgl/map/map.hpp
@@ -135,9 +135,6 @@ public:
const LatLng latLngForPixel(const vec2<double> pixel) const;
// Annotations
- void setDefaultPointAnnotationSymbol(const std::string&);
- double getTopOffsetPixelsForAnnotationSymbol(const std::string&);
-
AnnotationID addPointAnnotation(const PointAnnotation&);
AnnotationIDs addPointAnnotations(const std::vector<PointAnnotation>&);
@@ -147,8 +144,9 @@ public:
void removeAnnotation(AnnotationID);
void removeAnnotations(const AnnotationIDs&);
- AnnotationIDs getAnnotationsInBounds(const LatLngBounds&, const AnnotationType& = AnnotationType::Any);
+ AnnotationIDs getPointAnnotationsInBounds(const LatLngBounds&);
LatLngBounds getBoundsForAnnotations(const AnnotationIDs&);
+ double getTopOffsetPixelsForAnnotationSymbol(const std::string&);
// Sprites
void setSprite(const std::string&, std::shared_ptr<const SpriteImage>);
diff --git a/include/mbgl/util/geo.hpp b/include/mbgl/util/geo.hpp
index 1f073ded8f..307134f666 100644
--- a/include/mbgl/util/geo.hpp
+++ b/include/mbgl/util/geo.hpp
@@ -1,6 +1,8 @@
#ifndef MBGL_UTIL_GEO
#define MBGL_UTIL_GEO
+#include <mbgl/util/vec.hpp>
+
namespace mbgl {
class TileID;
@@ -14,6 +16,8 @@ struct LatLng {
// Constructs a LatLng object with the top left position of the specified tile.
LatLng(const TileID& id);
+
+ vec2<double> project() const;
};
struct ProjectedMeters {
diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm
index 163f3c6c7f..4810e0b44b 100644
--- a/platform/ios/MGLMapView.mm
+++ b/platform/ios/MGLMapView.mm
@@ -285,9 +285,6 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
_annotationImages = [NSMutableDictionary dictionary];
- std::string defaultSymbolName([MGLDefaultStyleMarkerSymbolName UTF8String]);
- _mbglMap->setDefaultPointAnnotationSymbol(defaultSymbolName);
-
// setup logo bug
//
UIImage *logo = [[MGLMapView resourceImageNamed:@"mapbox.png"] imageWithAlignmentRectInsets:UIEdgeInsetsMake(1.5, 4, 3.5, 2)];
@@ -1159,7 +1156,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration)
tapBounds.extend(MGLLatLngFromLocationCoordinate2D(coordinate));
// query for nearby annotations
- std::vector<uint32_t> nearbyAnnotations = _mbglMap->getAnnotationsInBounds(tapBounds, mbgl::AnnotationType::Point);
+ std::vector<uint32_t> nearbyAnnotations = _mbglMap->getPointAnnotationsInBounds(tapBounds);
int32_t newSelectedAnnotationID = -1;
diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp
index 786ca42433..5e589bf289 100644
--- a/src/mbgl/annotation/annotation_manager.cpp
+++ b/src/mbgl/annotation/annotation_manager.cpp
@@ -1,490 +1,126 @@
#include <mbgl/annotation/annotation_manager.hpp>
-#include <mbgl/annotation/point_annotation.hpp>
-#include <mbgl/annotation/shape_annotation.hpp>
-#include <mbgl/map/tile_id.hpp>
-#include <mbgl/map/live_tile.hpp>
-#include <mbgl/util/constants.hpp>
-#include <mbgl/util/geojsonvt/geojsonvt_convert.hpp>
-#include <mbgl/util/ptr.hpp>
-#include <mbgl/util/string.hpp>
+#include <mbgl/annotation/annotation_tile.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/style/style_layer.hpp>
-#include <algorithm>
+#include <boost/function_output_iterator.hpp>
namespace mbgl {
-class Annotation : private util::noncopyable {
-public:
- Annotation(AnnotationType, const AnnotationSegments&, const StyleProperties&);
+const std::string AnnotationManager::SourceID = "com.mapbox.annotations";
+const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points";
- const StyleProperties styleProperties;
-
- LatLng getPoint() const;
- LatLngBounds getBounds() const { return bounds; }
-
- const AnnotationType type = AnnotationType::Point;
- const AnnotationSegments geometry;
- std::unordered_map<TileID, std::weak_ptr<const LiveTileFeature>, TileID::Hash> tilePointFeatures;
- const LatLngBounds bounds;
-};
-
-Annotation::Annotation(AnnotationType type_,
- const AnnotationSegments& geometry_,
- const StyleProperties& styleProperties_)
- : styleProperties(styleProperties_),
- type(type_),
- geometry(geometry_),
- bounds([this] {
- LatLngBounds bounds_;
- assert(type != AnnotationType::Any);
- if (type == AnnotationType::Point) {
- bounds_ = { getPoint(), getPoint() };
- } else {
- for (auto& segment : geometry) {
- for (auto& point : segment) {
- bounds_.extend(point);
- }
- }
- }
- return bounds_;
- }()) {
-}
-
-LatLng Annotation::getPoint() const {
- // Return the first line's first point. Shortcut for point annotations.
- assert(!geometry.empty());
- assert(!geometry[0].empty());
- return geometry[0][0];
-}
-
-AnnotationManager::AnnotationManager() {}
-
-AnnotationManager::~AnnotationManager() {
- // leave this here because the header file doesn't have a definition of
- // Annotation so we can't destruct the object with just the header file.
-}
-
-void AnnotationManager::setDefaultPointAnnotationSymbol(const std::string& symbol) {
- defaultPointAnnotationSymbol = symbol;
-}
-
-uint32_t AnnotationManager::nextID() {
- return nextID_++;
-}
-
-vec2<double> AnnotationManager::projectPoint(const LatLng& point) {
- // Clamp to the latitude limits of Mercator.
- const double constrainedLatitude = ::fmin(::fmax(point.latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX);
-
- // Project a coordinate into unit space in a square map.
- const double sine = std::sin(constrainedLatitude * M_PI / 180.0);
- const double x = point.longitude / 360.0 + 0.5;
- const double y = 0.5 - 0.25 * std::log((1.0 + sine) / (1.0 - sine)) / M_PI;
- return { x, y };
-}
-
-uint32_t
-AnnotationManager::addShapeAnnotation(const ShapeAnnotation& shape, const uint8_t maxZoom) {
- const uint32_t annotationID = nextID();
-
- annotations.emplace(annotationID, std::make_unique<Annotation>(
- AnnotationType::Shape,
- shape.segments,
- shape.styleProperties));
-
- orderedShapeAnnotations.push_back(annotationID);
-
- using namespace mapbox::util::geojsonvt;
-
- const uint32_t z2 = 1 << maxZoom;
- const double baseTolerance = 3;
- const uint16_t extent = 4096;
-
- const double tolerance = baseTolerance / (z2 * extent);
-
- ProjectedGeometryContainer rings;
-
- std::vector<LonLat> points;
-
- for (size_t i = 0; i < shape.segments[0].size(); ++i) { // first segment for now (no holes)
- const double constraintedLatitude = ::fmin(::fmax(shape.segments[0][i].latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX);
- points.push_back(LonLat(shape.segments[0][i].longitude, constraintedLatitude));
- }
-
- ProjectedFeatureType featureType;
-
- if (shape.styleProperties.is<FillProperties>()) {
- featureType = ProjectedFeatureType::Polygon;
-
- if (points.front().lon != points.back().lon || points.front().lat != points.back().lat) {
- points.push_back(LonLat(points.front().lon, points.front().lat));
- }
- } else {
- featureType = ProjectedFeatureType::LineString;
- }
-
- ProjectedGeometryContainer ring = Convert::project(points, tolerance);
- rings.members.push_back(ring);
-
- std::vector<ProjectedFeature> features;
- features.push_back(Convert::create(Tags(), featureType, rings));
-
- shapeTilers.emplace(annotationID, std::make_unique<GeoJSONVT>(features, maxZoom, 4, 100, 10));
-
- return annotationID;
-}
-
-uint32_t
-AnnotationManager::addPointAnnotation(const PointAnnotation& point, const uint8_t maxZoom) {
- // We pre-generate tiles to contain each annotation up to the map's max zoom.
- // We do this for fast rendering without projection conversions on the fly, as well as
- // to simplify bounding box queries of annotations later. Tiles get invalidated when
- // annotations are added or removed in order to refresh the map render without
- // touching the base map underneath.
-
- const uint32_t annotationID = nextID();
-
- // at render time we style the point according to its {sprite} field
- std::unordered_map<std::string, std::string> featureProperties;
- if (point.icon.length()) {
- featureProperties.emplace("sprite", point.icon);
- } else {
- featureProperties.emplace("sprite", defaultPointAnnotationSymbol);
- }
-
- std::unique_ptr<Annotation> annotation = std::make_unique<Annotation>(
- AnnotationType::Point,
- AnnotationSegments({{ point.position }}),
- StyleProperties({{ }}));
-
- const uint16_t extent = 4096;
-
- // projection conversion into unit space
- vec2<double> pp = projectPoint(point.position);
-
- for (int8_t z = maxZoom; z >= 0; z--) {
- uint32_t z2 = 1 << z;
- uint32_t x = pp.x * z2;
- uint32_t y = pp.y * z2;
-
- const Coordinate coordinate(extent * (pp.x * z2 - x), extent * (pp.y * z2 - y));
-
- GeometryCollection geometries = {{ {{ coordinate }} }};
- TileID featureTileID = TileID(z, x, y, z);
-
- auto feature = std::make_shared<const LiveTileFeature>(FeatureType::Point, geometries, featureProperties);
-
- // check for tile & create if necessary
- auto tile_pos = tiles.emplace(featureTileID,
- std::make_pair(std::unordered_set<uint32_t>({ annotationID }),
- std::make_unique<LiveTile>()));
-
- // check for annotation layer & create if necessary
- util::ptr<LiveTileLayer> layer;
- std::string layerID = PointSourceID;
-
- if (tile_pos.second || tile_pos.first->second.second->getMutableLayer(layerID) == nullptr) {
- layer = std::make_shared<LiveTileLayer>();
- tile_pos.first->second.second->addLayer(layerID, layer);
- } else {
- layer = tile_pos.first->second.second->getMutableLayer(layerID);
-
- // associate annotation with tile
- tile_pos.first->second.first.insert(annotationID);
- }
-
- // add feature to layer
- layer->addFeature(feature);
-
- // Record annotation association with tile and tile feature. This is used to determine stale tiles,
- // as well as to remove the feature from the tile upon annotation deletion.
- annotation->tilePointFeatures.emplace(featureTileID, std::weak_ptr<const LiveTileFeature>(feature));
-
- // track affected tile
- stalePointTileIDs.insert(featureTileID);
- }
-
- annotations.emplace(annotationID, std::move(annotation));
-
- return annotationID;
-}
+AnnotationManager::AnnotationManager() = default;
+AnnotationManager::~AnnotationManager() = default;
AnnotationIDs
-AnnotationManager::addPointAnnotations(const std::vector<PointAnnotation>& points,
- const uint8_t maxZoom) {
+AnnotationManager::addPointAnnotations(const std::vector<PointAnnotation>& points, const uint8_t) {
AnnotationIDs annotationIDs;
annotationIDs.reserve(points.size());
for (const auto& point : points) {
- annotationIDs.push_back(addPointAnnotation(point, maxZoom));
+ const uint32_t annotationID = nextID++;
+ auto annotation = std::make_shared<PointAnnotationImpl>(annotationID, point);
+ pointTree.insert(annotation);
+ pointAnnotations.emplace(annotationID, annotation);
+ annotationIDs.push_back(annotationID);
}
return annotationIDs;
}
AnnotationIDs
-AnnotationManager::addShapeAnnotations(const std::vector<ShapeAnnotation>& shapes,
- const uint8_t maxZoom) {
+AnnotationManager::addShapeAnnotations(const std::vector<ShapeAnnotation>& shapes, const uint8_t maxZoom) {
AnnotationIDs annotationIDs;
annotationIDs.reserve(shapes.size());
for (const auto& shape : shapes) {
- annotationIDs.push_back(addShapeAnnotation(shape, maxZoom));
+ const uint32_t annotationID = nextID++;
+ shapeAnnotations.emplace(annotationID,
+ std::make_unique<ShapeAnnotationImpl>(annotationID, shape, maxZoom));
+ annotationIDs.push_back(annotationID);
}
return annotationIDs;
}
-void AnnotationManager::removeAnnotations(const AnnotationIDs& ids, const uint8_t maxZoom) {
- std::vector<uint32_t> z2s;
- const uint8_t zoomCount = maxZoom + 1;
- z2s.reserve(zoomCount);
- for (uint8_t z = 0; z < zoomCount; ++z) {
- z2s.emplace_back(1<< z);
- }
-
- LatLng latLng;
- vec2<double> p;
- uint32_t x, y;
-
- // iterate annotation id's passed
- for (const auto& annotationID : ids) {
- // grab annotation object
- const auto& annotation_it = annotations.find(annotationID);
- if (annotation_it != annotations.end()) {
- const auto& annotation = annotation_it->second;
- // remove feature(s) from relevant tiles
- if (annotation->type == AnnotationType::Point) {
- // calculate annotation's affected tile for each zoom
- for (uint8_t z = 0; z < zoomCount; ++z) {
- latLng = annotation->getPoint();
- p = projectPoint(latLng);
- x = z2s[z] * p.x;
- y = z2s[z] * p.y;
- TileID tid(z, x, y, z);
- // erase annotation from tile's list
- auto& tileAnnotations = tiles[tid].first;
- tileAnnotations.erase(annotationID);
- // remove annotation's features from tile
- const auto& features_it = annotation->tilePointFeatures.find(tid);
- if (features_it != annotation->tilePointFeatures.end()) {
- // points share a layer; remove feature
- auto layer = tiles[tid].second->getMutableLayer(PointSourceID);
- layer->removeFeature(features_it->second);
- stalePointTileIDs.insert(tid);
- }
- }
- } else {
- // remove shape layer from tiles if relevant
- for (auto tile_it = tiles.begin(); tile_it != tiles.end(); ++tile_it) {
- if (tile_it->second.first.count(annotationID)) {
- tile_it->second.second->removeLayer(ShapeSourceID + "." + util::toString(annotationID));
- }
- }
-
- // clear shape from render order
- auto shape_it = std::find(orderedShapeAnnotations.begin(), orderedShapeAnnotations.end(), annotationID);
- orderedShapeAnnotations.erase(shape_it);
-
- // clear shape tiler
- shapeTilers.erase(annotationID);
- }
-
- annotations.erase(annotationID);
+void AnnotationManager::removeAnnotations(const AnnotationIDs& ids) {
+ for (const auto& id : ids) {
+ if (pointAnnotations.find(id) != pointAnnotations.end()) {
+ pointTree.remove(pointAnnotations.at(id));
+ pointAnnotations.erase(id);
+ } else if (shapeAnnotations.find(id) != shapeAnnotations.end()) {
+ // TODO: remove style layer
+ shapeAnnotations.erase(id);
}
}
}
-AnnotationIDs AnnotationManager::getAnnotationsInBounds(const LatLngBounds& queryBounds,
- const uint8_t maxZoom,
- const AnnotationType& type) const {
- const uint8_t z = maxZoom;
- const uint32_t z2 = 1 << z;
- const vec2<double> swPoint = projectPoint(queryBounds.sw);
- const vec2<double> nePoint = projectPoint(queryBounds.ne);
+AnnotationIDs AnnotationManager::getPointAnnotationsInBounds(const LatLngBounds& bounds) const {
+ AnnotationIDs result;
- // tiles number y from top down
- const TileID nwTile(z, swPoint.x * z2, nePoint.y * z2, z);
- const TileID seTile(z, nePoint.x * z2, swPoint.y * z2, z);
+ pointTree.query(boost::geometry::index::intersects(bounds),
+ boost::make_function_output_iterator([&](const auto& val){
+ result.push_back(val->id);
+ }));
- std::unordered_set<uint32_t> matchingAnnotations;
-
- for (auto& tile : tiles) {
- TileID 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; this tile is completely inside the query bounds, so
- // we'll return all of its annotations that match type (if specified).
- if (type != AnnotationType::Any) {
- std::copy_if(tile.second.first.begin(), tile.second.first.end(),
- std::inserter(matchingAnnotations, matchingAnnotations.begin()),
- [&](const uint32_t annotationID) -> bool {
- const auto it = annotations.find(annotationID);
- if (it != annotations.end()) {
- return (it->second->type == type);
- } else {
- return false;
- }
- });
- } else {
- std::copy(tile.second.first.begin(), tile.second.first.end(),
- std::inserter(matchingAnnotations, matchingAnnotations.begin()));
- }
- } else {
- // This tile is intersected by the query bounds. We need to check the
- // tile's annotations' bounding boxes individually.
- std::copy_if(tile.second.first.begin(), tile.second.first.end(),
- std::inserter(matchingAnnotations, matchingAnnotations.begin()),
- [&](const uint32_t annotationID) -> bool {
- const auto it = annotations.find(annotationID);
- if (it != annotations.end()) {
- // check type
- if (type != AnnotationType::Any && it->second->type != type) {
- return false;
- }
-
- // check bounds
- if (it->second->type == AnnotationType::Point) {
- return queryBounds.contains(it->second->getPoint());
- } else if (it->second->type == AnnotationType::Shape) {
- return queryBounds.intersects(it->second->getBounds());
- }
- }
- return false;
- });
- }
- }
- }
- }
-
- return AnnotationIDs(matchingAnnotations.begin(), matchingAnnotations.end());
+ return result;
}
LatLngBounds AnnotationManager::getBoundsForAnnotations(const AnnotationIDs& ids) const {
- LatLngBounds bounds;
- for (auto id : ids) {
- const auto annotation_it = annotations.find(id);
- if (annotation_it != annotations.end()) {
- bounds.extend(annotation_it->second->getBounds());
+ LatLngBounds result;
+
+ for (const auto& id : ids) {
+ if (pointAnnotations.find(id) != pointAnnotations.end()) {
+ result.extend(pointAnnotations.at(id)->bounds());
+ } else if (shapeAnnotations.find(id) != shapeAnnotations.end()) {
+ result.extend(shapeAnnotations.at(id)->bounds());
}
}
- return bounds;
+ return result;
}
-const LiveTile* AnnotationManager::getTile(const TileID& id) {
- // look up any existing annotation tile
- LiveTile *renderTile = nullptr;
- const auto tile_lookup_it = tiles.find(id);
- if (tile_lookup_it != tiles.end()) {
- // it exists and may have annotations already
- renderTile = tile_lookup_it->second.second.get();
- } else if (!orderedShapeAnnotations.empty()) {
- // it needs created, but only for on-demand shapes
- renderTile = tiles.emplace(id,
- std::make_pair(std::unordered_set<uint32_t>(), std::make_unique<LiveTile>())
- ).first->second.second.get();
- }
-
- if (renderTile != nullptr && !orderedShapeAnnotations.empty()) {
-
- // create shape tile layers from GeoJSONVT queries
- for (auto& tiler_it : shapeTilers) {
- const auto annotationID = tiler_it.first;
- const std::string layerID = ShapeSourceID + "." + util::toString(annotationID);
-
- // check for existing render layer
- auto renderLayer = renderTile->getMutableLayer(layerID);
-
- if (renderLayer == nullptr) {
- // we might need to create a tile layer for this shape
- const auto& shapeTile = tiler_it.second->getTile(id.z, id.x, id.y);
-
- if (shapeTile) {
+std::unique_ptr<AnnotationTile> AnnotationManager::getTile(const TileID& tileID) {
+ auto tile = std::make_unique<AnnotationTile>();
- // shape exists on this tile; let's make a layer
- renderLayer = std::make_shared<LiveTileLayer>();
+ AnnotationTileLayer& pointLayer = *tile->layers.emplace(
+ PointLayerID,
+ std::make_unique<AnnotationTileLayer>()).first->second;
- // convert the features and add to render layer
- for (auto& shapeFeature : shapeTile.features) {
+ LatLngBounds tileBounds(tileID);
- using namespace mapbox::util::geojsonvt;
+ pointTree.query(boost::geometry::index::intersects(tileBounds),
+ boost::make_function_output_iterator([&](const auto& val){
+ val->updateLayer(tileID, pointLayer);
+ }));
- FeatureType renderType = FeatureType::Unknown;
-
- if (shapeFeature.type == TileFeatureType::LineString) {
- renderType = FeatureType::LineString;
- } else if (shapeFeature.type == TileFeatureType::Polygon) {
- renderType = FeatureType::Polygon;
- }
-
- assert(renderType != FeatureType::Unknown);
-
- GeometryCollection renderGeometry;
-
- for (auto& shapeGeometry : shapeFeature.geometry) {
-
- std::vector<Coordinate> renderLine;
-
- auto& shapeRing = shapeGeometry.get<TileRing>();
-
- for (auto& shapePoint : shapeRing.points) {
- renderLine.emplace_back(shapePoint.x, shapePoint.y);
- }
-
- renderGeometry.push_back(renderLine);
- }
-
- auto renderFeature = std::make_shared<LiveTileFeature>(renderType, renderGeometry);
-
- renderLayer->addFeature(renderFeature);
- }
-
- // move the layer to the render tile
- renderTile->addLayer(layerID, renderLayer);
-
- // associate the annotation with the tile
- auto tile_update_it = tiles.find(id);
- assert(tile_update_it != tiles.end());
- tile_update_it->second.first.insert(annotationID);
- }
- }
- }
+ for (const auto& shape : shapeAnnotations) {
+ shape.second->updateTile(tileID, *tile);
}
- return renderTile;
+ return tile;
}
void AnnotationManager::updateStyle(Style& style) {
- // Create shape source
- if (!style.getSource(ShapeSourceID)) {
- std::unique_ptr<Source> shapeSource = std::make_unique<Source>();
- shapeSource->info.type = SourceType::Annotations;
- shapeSource->info.source_id = ShapeSourceID;
- shapeSource->enabled = true;
- style.addSource(std::move(shapeSource));
- }
-
- // Create point source and singular layer and bucket
- if (!style.getSource(PointSourceID)) {
- std::unique_ptr<Source> pointSource = std::make_unique<Source>();
- pointSource->info.type = SourceType::Annotations;
- pointSource->info.source_id = PointSourceID;
- pointSource->enabled = true;
- style.addSource(std::move(pointSource));
+ // Create annotation source, point layer, and point bucket
+ if (!style.getSource(SourceID)) {
+ std::unique_ptr<Source> source = std::make_unique<Source>();
+ source->info.type = SourceType::Annotations;
+ source->info.source_id = SourceID;
+ source->enabled = true;
+ style.addSource(std::move(source));
std::map<ClassID, ClassProperties> pointPaints;
pointPaints.emplace(ClassID::Default, ClassProperties());
- std::unique_ptr<StyleLayer> pointLayer = std::make_unique<StyleLayer>(PointSourceID, std::move(pointPaints));
+ std::unique_ptr<StyleLayer> pointLayer = std::make_unique<StyleLayer>(PointLayerID, std::move(pointPaints));
pointLayer->type = StyleLayerType::Symbol;
util::ptr<StyleBucket> pointBucket = std::make_shared<StyleBucket>(pointLayer->type);
pointBucket->name = pointLayer->id;
- pointBucket->source = PointSourceID;
- pointBucket->source_layer = pointLayer->id;
+ pointBucket->source = SourceID;
+ pointBucket->source_layer = PointLayerID;
pointBucket->layout.set(PropertyKey::IconImage, ConstantFunction<std::string>("{sprite}"));
pointBucket->layout.set(PropertyKey::IconAllowOverlap, ConstantFunction<bool>(true));
@@ -492,52 +128,11 @@ void AnnotationManager::updateStyle(Style& style) {
style.addLayer(std::move(pointLayer));
}
- // Create new shape layers and buckets
- for (const auto& shapeID : orderedShapeAnnotations) {
- const std::string shapeLayerID = ShapeSourceID + "." + util::toString(shapeID);
- if (style.getLayer(shapeLayerID)) {
- continue;
- }
-
- const StyleProperties& shapeStyle = annotations.at(shapeID)->styleProperties;
- ClassProperties paintProperties;
-
- if (shapeStyle.is<LineProperties>()) {
- const LineProperties& lineProperties = shapeStyle.get<LineProperties>();
- paintProperties.set(PropertyKey::LineOpacity, ConstantFunction<float>(lineProperties.opacity));
- paintProperties.set(PropertyKey::LineWidth, ConstantFunction<float>(lineProperties.width));
- paintProperties.set(PropertyKey::LineColor, ConstantFunction<Color>(lineProperties.color));
- } else if (shapeStyle.is<FillProperties>()) {
- const FillProperties& fillProperties = shapeStyle.get<FillProperties>();
- paintProperties.set(PropertyKey::FillOpacity, ConstantFunction<float>(fillProperties.opacity));
- paintProperties.set(PropertyKey::FillColor, ConstantFunction<Color>(fillProperties.fill_color));
- paintProperties.set(PropertyKey::FillOutlineColor, ConstantFunction<Color>(fillProperties.stroke_color));
- }
-
- std::map<ClassID, ClassProperties> shapePaints;
- shapePaints.emplace(ClassID::Default, std::move(paintProperties));
- std::unique_ptr<StyleLayer> shapeLayer = std::make_unique<StyleLayer>(shapeLayerID, std::move(shapePaints));
- shapeLayer->type = (shapeStyle.is<LineProperties>() ? StyleLayerType::Line : StyleLayerType::Fill);
-
- util::ptr<StyleBucket> shapeBucket = std::make_shared<StyleBucket>(shapeLayer->type);
- shapeBucket->name = shapeLayer->id;
- shapeBucket->source = ShapeSourceID;
- shapeBucket->source_layer = shapeLayer->id;
- if (shapeStyle.is<LineProperties>()) {
- shapeBucket->layout.set(PropertyKey::LineJoin, ConstantFunction<JoinType>(JoinType::Round));
- }
-
- shapeLayer->bucket = shapeBucket;
- style.addLayer(std::move(shapeLayer), PointSourceID);
+ for (const auto& shape : shapeAnnotations) {
+ shape.second->updateStyle(style);
}
- style.getSource(PointSourceID)->invalidateTiles(stalePointTileIDs);
- style.getSource(ShapeSourceID)->invalidateTiles();
-
- stalePointTileIDs.clear();
+ style.getSource(SourceID)->invalidateTiles();
}
-const std::string AnnotationManager::PointSourceID = "com.mapbox.annotations.points";
-const std::string AnnotationManager::ShapeSourceID = "com.mapbox.annotations.shape";
-
}
diff --git a/src/mbgl/annotation/annotation_manager.hpp b/src/mbgl/annotation/annotation_manager.hpp
index 2173442da8..1251585b00 100644
--- a/src/mbgl/annotation/annotation_manager.hpp
+++ b/src/mbgl/annotation/annotation_manager.hpp
@@ -1,66 +1,45 @@
-#ifndef MBGL_MAP_ANNOTATIONS
-#define MBGL_MAP_ANNOTATIONS
+#ifndef MBGL_ANNOTATION_MANAGER
+#define MBGL_ANNOTATION_MANAGER
#include <mbgl/annotation/annotation.hpp>
-#include <mbgl/map/geometry_tile.hpp>
-#include <mbgl/map/tile_id.hpp>
-#include <mbgl/style/style_properties.hpp>
-#include <mbgl/style/types.hpp>
+#include <mbgl/annotation/point_annotation_impl.hpp>
+#include <mbgl/annotation/shape_annotation_impl.hpp>
#include <mbgl/util/geo.hpp>
-#include <mbgl/util/geojsonvt/geojsonvt.hpp>
#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/vec.hpp>
#include <string>
#include <vector>
-#include <memory>
-#include <unordered_map>
-#include <unordered_set>
namespace mbgl {
-class Annotation;
class PointAnnotation;
class ShapeAnnotation;
-class LiveTile;
+class AnnotationTile;
class Style;
-using GeoJSONVT = mapbox::util::geojsonvt::GeoJSONVT;
-
class AnnotationManager : private util::noncopyable {
public:
AnnotationManager();
~AnnotationManager();
- void setDefaultPointAnnotationSymbol(const std::string& symbol);
-
AnnotationIDs addPointAnnotations(const std::vector<PointAnnotation>&, const uint8_t maxZoom);
AnnotationIDs addShapeAnnotations(const std::vector<ShapeAnnotation>&, const uint8_t maxZoom);
- void removeAnnotations(const AnnotationIDs&, const uint8_t maxZoom);
+ void removeAnnotations(const AnnotationIDs&);
- AnnotationIDs getAnnotationsInBounds(const LatLngBounds&, const uint8_t maxZoom, const AnnotationType& = AnnotationType::Any) const;
+ AnnotationIDs getPointAnnotationsInBounds(const LatLngBounds&) const;
LatLngBounds getBoundsForAnnotations(const AnnotationIDs&) const;
void updateStyle(Style&);
- const LiveTile* getTile(const TileID& id);
+ std::unique_ptr<AnnotationTile> getTile(const TileID&);
- static const std::string PointSourceID;
- static const std::string ShapeSourceID;
+ static const std::string SourceID;
+ static const std::string PointLayerID;
private:
- inline uint32_t nextID();
- static vec2<double> projectPoint(const LatLng& point);
-
- uint32_t addShapeAnnotation(const ShapeAnnotation&, const uint8_t maxZoom);
- uint32_t addPointAnnotation(const PointAnnotation&, const uint8_t maxZoom);
-
- std::string defaultPointAnnotationSymbol;
- std::unordered_map<uint32_t, std::unique_ptr<Annotation>> annotations;
- std::vector<uint32_t> orderedShapeAnnotations;
- std::unordered_map<TileID, std::pair<std::unordered_set<uint32_t>, std::unique_ptr<LiveTile>>, TileID::Hash> tiles;
- std::unordered_map<uint32_t, std::unique_ptr<GeoJSONVT>> shapeTilers;
- std::unordered_set<TileID, TileID::Hash> stalePointTileIDs;
- uint32_t nextID_ = 0;
+ AnnotationID nextID = 0;
+ PointAnnotationImpl::Tree pointTree;
+ PointAnnotationImpl::Map pointAnnotations;
+ ShapeAnnotationImpl::Map shapeAnnotations;
};
}
diff --git a/src/mbgl/annotation/annotation_tile.cpp b/src/mbgl/annotation/annotation_tile.cpp
new file mode 100644
index 0000000000..71a6870cdb
--- /dev/null
+++ b/src/mbgl/annotation/annotation_tile.cpp
@@ -0,0 +1,28 @@
+#include <mbgl/annotation/annotation_tile.hpp>
+#include <mbgl/util/constants.hpp>
+
+namespace mbgl {
+
+AnnotationTileFeature::AnnotationTileFeature(FeatureType type_, GeometryCollection geometries_,
+ std::unordered_map<std::string, std::string> properties_)
+ : type(type_),
+ properties(properties_),
+ geometries(geometries_) {}
+
+mapbox::util::optional<Value> AnnotationTileFeature::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>();
+}
+
+util::ptr<GeometryTileLayer> AnnotationTile::getLayer(const std::string& name) const {
+ auto it = layers.find(name);
+ if (it != layers.end()) {
+ return it->second;
+ }
+ return nullptr;
+}
+
+}
diff --git a/src/mbgl/annotation/annotation_tile.hpp b/src/mbgl/annotation/annotation_tile.hpp
new file mode 100644
index 0000000000..bb7ec5d047
--- /dev/null
+++ b/src/mbgl/annotation/annotation_tile.hpp
@@ -0,0 +1,43 @@
+#ifndef MBGL_ANNOTATION_TILE
+#define MBGL_ANNOTATION_TILE
+
+#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/map/tile_id.hpp>
+
+#include <map>
+#include <unordered_map>
+
+namespace mbgl {
+
+class AnnotationTileFeature : public GeometryTileFeature {
+public:
+ AnnotationTileFeature(FeatureType, GeometryCollection,
+ std::unordered_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; }
+
+ const FeatureType type;
+ const std::unordered_map<std::string, std::string> properties;
+ const GeometryCollection geometries;
+};
+
+class AnnotationTileLayer : public GeometryTileLayer {
+public:
+ std::size_t featureCount() const override { return features.size(); }
+ util::ptr<const GeometryTileFeature> getFeature(std::size_t i) const override { return features[i]; }
+
+ std::vector<util::ptr<const AnnotationTileFeature>> features;
+};
+
+class AnnotationTile : public GeometryTile {
+public:
+ util::ptr<GeometryTileLayer> getLayer(const std::string&) const override;
+
+ std::map<std::string, util::ptr<AnnotationTileLayer>> layers;
+};
+
+}
+
+#endif
diff --git a/src/mbgl/annotation/point_annotation_impl.cpp b/src/mbgl/annotation/point_annotation_impl.cpp
new file mode 100644
index 0000000000..a5f4ac269e
--- /dev/null
+++ b/src/mbgl/annotation/point_annotation_impl.cpp
@@ -0,0 +1,32 @@
+#include <mbgl/annotation/point_annotation_impl.hpp>
+#include <mbgl/annotation/annotation_tile.hpp>
+
+namespace mbgl {
+
+PointAnnotationImpl::PointAnnotationImpl(const AnnotationID id_, const PointAnnotation& point_)
+: id(id_),
+ point(point_) {
+}
+
+void PointAnnotationImpl::updateLayer(const TileID& tileID, AnnotationTileLayer& layer) const {
+ std::unordered_map<std::string, std::string> featureProperties;
+ featureProperties.emplace("sprite", point.icon.empty() ? std::string("default_marker") : point.icon);
+
+ const uint16_t extent = 4096;
+ const vec2<double> pp = point.position.project();
+ const uint32_t z2 = 1 << tileID.z;
+ const uint32_t x = pp.x * z2;
+ const uint32_t y = pp.y * z2;
+ const Coordinate coordinate(extent * (pp.x * z2 - x), extent * (pp.y * z2 - y));
+
+ layer.features.emplace_back(
+ std::make_shared<const AnnotationTileFeature>(FeatureType::Point,
+ GeometryCollection {{ {{ coordinate }} }},
+ featureProperties));
+}
+
+LatLngBounds PointAnnotationImpl::bounds() const {
+ return LatLngBounds(point.position, point.position);
+}
+
+}
diff --git a/src/mbgl/annotation/point_annotation_impl.hpp b/src/mbgl/annotation/point_annotation_impl.hpp
new file mode 100644
index 0000000000..2977caf577
--- /dev/null
+++ b/src/mbgl/annotation/point_annotation_impl.hpp
@@ -0,0 +1,72 @@
+#ifndef MBGL_POINT_ANNOTATION_IMPL
+#define MBGL_POINT_ANNOTATION_IMPL
+
+#include <mbgl/annotation/annotation.hpp>
+#include <mbgl/annotation/point_annotation.hpp>
+#include <mbgl/util/geo.hpp>
+
+#include <string>
+
+#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 <boost/geometry.hpp>
+#include <boost/geometry/geometries/point.hpp>
+#include <boost/geometry/geometries/box.hpp>
+#include <boost/geometry/geometries/register/point.hpp>
+#include <boost/geometry/geometries/register/box.hpp>
+#include <boost/geometry/index/rtree.hpp>
+#pragma GCC diagnostic pop
+
+// 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)
+
+namespace mbgl {
+
+class AnnotationTileLayer;
+
+class PointAnnotationImpl {
+public:
+ using Map = std::map<AnnotationID, std::shared_ptr<PointAnnotationImpl>>;
+ using Tree = boost::geometry::index::rtree<std::shared_ptr<const PointAnnotationImpl>, boost::geometry::index::rstar<16, 4>>;
+
+ PointAnnotationImpl(const AnnotationID, const PointAnnotation&);
+
+ LatLngBounds bounds() const;
+ void updateLayer(const TileID&, AnnotationTileLayer&) const;
+
+ const AnnotationID id;
+ const PointAnnotation point;
+};
+
+}
+
+// Tell Boost Geometry how to access a std::shared_ptr<mbgl::PointAnnotation> object.
+namespace boost {
+namespace geometry {
+namespace index {
+
+template <>
+struct indexable<std::shared_ptr<const mbgl::PointAnnotationImpl>> {
+ using result_type = const mbgl::LatLng&;
+ inline const mbgl::LatLng& operator()(const std::shared_ptr<const mbgl::PointAnnotationImpl>& v) const {
+ return v->point.position;
+ }
+};
+
+} // end namespace index
+} // end namespace geometry
+} // end namespace boost
+
+#endif
diff --git a/src/mbgl/annotation/shape_annotation_impl.cpp b/src/mbgl/annotation/shape_annotation_impl.cpp
new file mode 100644
index 0000000000..e17509d669
--- /dev/null
+++ b/src/mbgl/annotation/shape_annotation_impl.cpp
@@ -0,0 +1,137 @@
+#include <mbgl/annotation/shape_annotation_impl.hpp>
+#include <mbgl/annotation/annotation_manager.hpp>
+#include <mbgl/annotation/annotation_tile.hpp>
+#include <mbgl/util/geojsonvt/geojsonvt_convert.hpp>
+#include <mbgl/util/constants.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/style/style_bucket.hpp>
+#include <mbgl/style/style_layer.hpp>
+
+namespace mbgl {
+
+using namespace mapbox::util::geojsonvt;
+
+ShapeAnnotationImpl::ShapeAnnotationImpl(const AnnotationID id_,
+ const ShapeAnnotation& shape_,
+ const uint8_t maxZoom)
+: id(id_),
+ layerID("com.mapbox.annotations.shape." + util::toString(id)),
+ shape(shape_),
+ shapeTiler(([&] {
+ const double baseTolerance = 3;
+ const uint16_t extent = 4096;
+ const double tolerance = baseTolerance / ((1 << maxZoom) * extent);
+
+ ProjectedGeometryContainer rings;
+ std::vector<LonLat> points;
+
+ for (size_t i = 0; i < shape.segments[0].size(); ++i) { // first segment for now (no holes)
+ const double constraintedLatitude = ::fmin(::fmax(shape.segments[0][i].latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX);
+ points.push_back(LonLat(shape.segments[0][i].longitude, constraintedLatitude));
+ }
+
+ ProjectedFeatureType featureType;
+
+ if (shape.styleProperties.is<FillProperties>()) {
+ featureType = ProjectedFeatureType::Polygon;
+
+ if (points.front().lon != points.back().lon || points.front().lat != points.back().lat) {
+ points.push_back(LonLat(points.front().lon, points.front().lat));
+ }
+ } else {
+ featureType = ProjectedFeatureType::LineString;
+ }
+
+ ProjectedGeometryContainer ring = Convert::project(points, tolerance);
+ rings.members.push_back(ring);
+
+ std::vector<ProjectedFeature> features;
+ features.push_back(Convert::create(Tags(), featureType, rings));
+ return features;
+ })(), maxZoom, 4, 100, 10) {}
+
+void ShapeAnnotationImpl::updateStyle(Style& style) {
+ if (style.getLayer(layerID))
+ return;
+
+ ClassProperties paintProperties;
+
+ if (shape.styleProperties.is<LineProperties>()) {
+ const LineProperties& lineProperties = shape.styleProperties.get<LineProperties>();
+ paintProperties.set(PropertyKey::LineOpacity, ConstantFunction<float>(lineProperties.opacity));
+ paintProperties.set(PropertyKey::LineWidth, ConstantFunction<float>(lineProperties.width));
+ paintProperties.set(PropertyKey::LineColor, ConstantFunction<Color>(lineProperties.color));
+ } else if (shape.styleProperties.is<FillProperties>()) {
+ const FillProperties& fillProperties = shape.styleProperties.get<FillProperties>();
+ paintProperties.set(PropertyKey::FillOpacity, ConstantFunction<float>(fillProperties.opacity));
+ paintProperties.set(PropertyKey::FillColor, ConstantFunction<Color>(fillProperties.fill_color));
+ paintProperties.set(PropertyKey::FillOutlineColor, ConstantFunction<Color>(fillProperties.stroke_color));
+ }
+
+ std::map<ClassID, ClassProperties> shapePaints;
+ shapePaints.emplace(ClassID::Default, std::move(paintProperties));
+ std::unique_ptr<StyleLayer> shapeLayer = std::make_unique<StyleLayer>(layerID, std::move(shapePaints));
+ shapeLayer->type = (shape.styleProperties.is<LineProperties>() ? StyleLayerType::Line : StyleLayerType::Fill);
+
+ util::ptr<StyleBucket> shapeBucket = std::make_shared<StyleBucket>(shapeLayer->type);
+ shapeBucket->name = shapeLayer->id;
+ shapeBucket->source = AnnotationManager::SourceID;
+ shapeBucket->source_layer = shapeLayer->id;
+ if (shape.styleProperties.is<LineProperties>()) {
+ shapeBucket->layout.set(PropertyKey::LineJoin, ConstantFunction<JoinType>(JoinType::Round));
+ }
+
+ shapeLayer->bucket = shapeBucket;
+ style.addLayer(std::move(shapeLayer), AnnotationManager::PointLayerID);
+}
+
+void ShapeAnnotationImpl::updateTile(const TileID& tileID, AnnotationTile& tile) {
+ const auto& shapeTile = shapeTiler.getTile(tileID.z, tileID.x, tileID.y);
+ if (!shapeTile)
+ return;
+
+ AnnotationTileLayer& layer = *tile.layers.emplace(layerID,
+ std::make_unique<AnnotationTileLayer>()).first->second;
+
+ for (auto& shapeFeature : shapeTile.features) {
+ FeatureType featureType = FeatureType::Unknown;
+
+ if (shapeFeature.type == TileFeatureType::LineString) {
+ featureType = FeatureType::LineString;
+ } else if (shapeFeature.type == TileFeatureType::Polygon) {
+ featureType = FeatureType::Polygon;
+ }
+
+ assert(featureType != FeatureType::Unknown);
+
+ GeometryCollection renderGeometry;
+ for (auto& shapeGeometry : shapeFeature.geometry) {
+ std::vector<Coordinate> renderLine;
+ auto& shapeRing = shapeGeometry.get<TileRing>();
+
+ for (auto& shapePoint : shapeRing.points) {
+ renderLine.emplace_back(shapePoint.x, shapePoint.y);
+ }
+
+ renderGeometry.push_back(renderLine);
+ }
+
+ layer.features.emplace_back(
+ std::make_shared<AnnotationTileFeature>(featureType, renderGeometry));
+ }
+}
+
+LatLngBounds ShapeAnnotationImpl::bounds() const {
+ LatLngBounds result;
+
+ for (const auto& segment : shape.segments) {
+ for (const auto& point : segment) {
+ result.extend(point);
+ }
+ }
+
+ return result;
+}
+
+}
diff --git a/src/mbgl/annotation/shape_annotation_impl.hpp b/src/mbgl/annotation/shape_annotation_impl.hpp
new file mode 100644
index 0000000000..6e00a50e39
--- /dev/null
+++ b/src/mbgl/annotation/shape_annotation_impl.hpp
@@ -0,0 +1,36 @@
+#ifndef MBGL_SHAPE_ANNOTATION_IMPL
+#define MBGL_SHAPE_ANNOTATION_IMPL
+
+#include <mbgl/annotation/annotation.hpp>
+#include <mbgl/annotation/shape_annotation.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/geojsonvt/geojsonvt.hpp>
+
+#include <string>
+#include <map>
+
+namespace mbgl {
+
+class Style;
+class AnnotationTile;
+
+class ShapeAnnotationImpl {
+public:
+ using Map = std::map<AnnotationID, std::unique_ptr<ShapeAnnotationImpl>>;
+
+ ShapeAnnotationImpl(const AnnotationID, const ShapeAnnotation&, const uint8_t maxZoom);
+
+ LatLngBounds bounds() const;
+ void updateStyle(Style&);
+ void updateTile(const TileID&, AnnotationTile&);
+
+private:
+ const AnnotationID id;
+ const std::string layerID;
+ const ShapeAnnotation shape;
+ mapbox::util::geojsonvt::GeoJSONVT shapeTiler;
+};
+
+}
+
+#endif
diff --git a/src/mbgl/map/live_tile.cpp b/src/mbgl/map/live_tile.cpp
deleted file mode 100644
index f7a70f7d46..0000000000
--- a/src/mbgl/map/live_tile.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#include <mbgl/map/live_tile.hpp>
-#include <mbgl/util/constants.hpp>
-
-namespace mbgl {
-
-LiveTileFeature::LiveTileFeature(FeatureType type_, GeometryCollection geometries_,
- std::unordered_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));
-}
-
-void LiveTile::removeLayer(const std::string& name) {
- layers.erase(name);
-}
-
-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
deleted file mode 100644
index 5b4c2d1c16..0000000000
--- a/src/mbgl/map/live_tile.hpp
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef MBGL_MAP_LIVE_TILE
-#define MBGL_MAP_LIVE_TILE
-
-#include <map>
-#include <unordered_map>
-
-#include <mbgl/map/geometry_tile.hpp>
-
-namespace mbgl {
-
-class LiveTileFeature : public GeometryTileFeature {
-public:
- LiveTileFeature(FeatureType, GeometryCollection,
- std::unordered_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::unordered_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> getFeature(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>);
- void removeLayer(const std::string&);
- util::ptr<GeometryTileLayer> getLayer(const std::string&) const override;
- util::ptr<LiveTileLayer> getMutableLayer(const std::string&) const;
-
-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
index 15a1c6a3f4..f6e14fad10 100644
--- a/src/mbgl/map/live_tile_data.cpp
+++ b/src/mbgl/map/live_tile_data.cpp
@@ -1,5 +1,5 @@
#include <mbgl/map/live_tile_data.hpp>
-#include <mbgl/map/live_tile.hpp>
+#include <mbgl/annotation/annotation_tile.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/map/source.hpp>
#include <mbgl/text/collision_tile.hpp>
@@ -12,7 +12,7 @@
using namespace mbgl;
LiveTileData::LiveTileData(const TileID& id_,
- const LiveTile* tile_,
+ std::unique_ptr<AnnotationTile> tile_,
Style& style_,
const SourceInfo& source_,
std::function<void()> callback)
@@ -24,7 +24,7 @@ LiveTileData::LiveTileData(const TileID& id_,
style_.layers,
state,
std::make_unique<CollisionTile>(0, 0, false)),
- tile(tile_) {
+ tile(std::move(tile_)) {
state = State::loaded;
if (!tile) {
diff --git a/src/mbgl/map/live_tile_data.hpp b/src/mbgl/map/live_tile_data.hpp
index c6507bbc3e..6be9fa73df 100644
--- a/src/mbgl/map/live_tile_data.hpp
+++ b/src/mbgl/map/live_tile_data.hpp
@@ -9,12 +9,12 @@ namespace mbgl {
class Style;
class SourceInfo;
class WorkRequest;
-class LiveTile;
+class AnnotationTile;
class LiveTileData : public TileData {
public:
LiveTileData(const TileID&,
- const LiveTile*,
+ std::unique_ptr<AnnotationTile>,
Style&,
const SourceInfo&,
std::function<void ()> callback);
@@ -30,7 +30,7 @@ private:
TileWorker tileWorker;
std::unique_ptr<WorkRequest> workRequest;
bool parsing = false;
- const LiveTile* tile;
+ std::unique_ptr<AnnotationTile> tile;
};
}
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 2fce648f2e..4b6c9c8085 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -341,10 +341,6 @@ const LatLng Map::latLngForPixel(const vec2<double> pixel) const {
#pragma mark - Annotations
-void Map::setDefaultPointAnnotationSymbol(const std::string& symbol) {
- data->getAnnotationManager()->setDefaultPointAnnotationSymbol(symbol);
-}
-
double Map::getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol) {
return context->invokeSync<double>(&MapContext::getTopOffsetPixelsForAnnotationSymbol, symbol);
}
@@ -374,12 +370,12 @@ void Map::removeAnnotation(AnnotationID annotation) {
}
void Map::removeAnnotations(const AnnotationIDs& annotations) {
- data->getAnnotationManager()->removeAnnotations(annotations, getMaxZoom());
+ data->getAnnotationManager()->removeAnnotations(annotations);
update(Update::Annotations);
}
-AnnotationIDs Map::getAnnotationsInBounds(const LatLngBounds& bounds, const AnnotationType& type) {
- return data->getAnnotationManager()->getAnnotationsInBounds(bounds, getMaxZoom(), type);
+AnnotationIDs Map::getPointAnnotationsInBounds(const LatLngBounds& bounds) {
+ return data->getAnnotationManager()->getPointAnnotationsInBounds(bounds);
}
LatLngBounds Map::getBoundsForAnnotations(const AnnotationIDs& annotations) {
diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp
index 0f42796e41..49e1d81610 100644
--- a/src/mbgl/map/source.cpp
+++ b/src/mbgl/map/source.cpp
@@ -23,6 +23,7 @@
#include <mbgl/map/vector_tile_data.hpp>
#include <mbgl/map/raster_tile_data.hpp>
#include <mbgl/map/live_tile_data.hpp>
+#include <mbgl/annotation/annotation_tile.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/gl/debugging.hpp>
@@ -295,7 +296,7 @@ TileData::State Source::addTile(MapData& data,
new_tile.data = tileData;
} else if (info.type == SourceType::Annotations) {
new_tile.data = std::make_shared<LiveTileData>(normalized_id,
- data.getAnnotationManager()->getTile(normalized_id), style, info, callback);
+ data.getAnnotationManager()->getTile(normalized_id), style, info, callback);
} else {
throw std::runtime_error("source type not implemented");
}
@@ -515,15 +516,6 @@ bool Source::update(MapData& data,
return allTilesUpdated;
}
-void Source::invalidateTiles(const std::unordered_set<TileID, TileID::Hash>& ids) {
- cache.clear();
- for (const auto& id : ids) {
- tiles.erase(id);
- tile_data.erase(id);
- }
- updateTilePtrs();
-}
-
void Source::invalidateTiles() {
cache.clear();
tiles.clear();
diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp
index 421f819640..fceb5962a4 100644
--- a/src/mbgl/map/source.hpp
+++ b/src/mbgl/map/source.hpp
@@ -77,7 +77,6 @@ public:
TexturePool&,
bool shouldReparsePartialTiles);
- void invalidateTiles(const std::unordered_set<TileID, TileID::Hash>&);
void invalidateTiles();
void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
diff --git a/src/mbgl/util/geo.cpp b/src/mbgl/util/geo.cpp
index 21a591cb43..035eb2d20a 100644
--- a/src/mbgl/util/geo.cpp
+++ b/src/mbgl/util/geo.cpp
@@ -1,4 +1,5 @@
#include <mbgl/util/geo.hpp>
+#include <mbgl/util/constants.hpp>
#include <mbgl/map/tile_id.hpp>
#include <cmath>
@@ -11,6 +12,17 @@ LatLng::LatLng(const TileID& id) {
latitude = 180.0 / M_PI * std::atan(0.5 * (std::exp(n) - std::exp(-n)));
}
+vec2<double> LatLng::project() const {
+ // Clamp to the latitude limits of Mercator.
+ const double constrainedLatitude = ::fmin(::fmax(latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX);
+
+ // Project a coordinate into unit space in a square map.
+ const double sine = std::sin(constrainedLatitude * M_PI / 180.0);
+ const double x = longitude / 360.0 + 0.5;
+ const double y = 0.5 - 0.25 * std::log((1.0 + sine) / (1.0 - sine)) / M_PI;
+ return { x, y };
+}
+
LatLngBounds::LatLngBounds(const TileID& id)
: sw(TileID{ id.z, id.x, id.y + 1, id.sourceZ }),
ne(TileID{ id.z, id.x + 1, id.y, id.sourceZ }) {
diff --git a/src/mbgl/util/worker.cpp b/src/mbgl/util/worker.cpp
index b238071bc5..71c930b4ef 100644
--- a/src/mbgl/util/worker.cpp
+++ b/src/mbgl/util/worker.cpp
@@ -3,7 +3,7 @@
#include <mbgl/util/work_request.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/map/vector_tile.hpp>
-#include <mbgl/map/live_tile.hpp>
+#include <mbgl/annotation/annotation_tile.hpp>
#include <mbgl/util/pbf.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
@@ -38,7 +38,7 @@ public:
}
}
- void parseLiveTile(TileWorker* worker, const LiveTile* tile, std::function<void (TileParseResult)> callback) {
+ void parseLiveTile(TileWorker* worker, const AnnotationTile* tile, std::function<void (TileParseResult)> callback) {
try {
callback(worker->parse(*tile));
} catch (const std::exception& ex) {
@@ -71,7 +71,7 @@ std::unique_ptr<WorkRequest> Worker::parseVectorTile(TileWorker& worker, std::st
return threads[current]->invokeWithCallback(&Worker::Impl::parseVectorTile, callback, &worker, data);
}
-std::unique_ptr<WorkRequest> Worker::parseLiveTile(TileWorker& worker, const LiveTile& tile, std::function<void (TileParseResult)> callback) {
+std::unique_ptr<WorkRequest> Worker::parseLiveTile(TileWorker& worker, const AnnotationTile& tile, std::function<void (TileParseResult)> callback) {
current = (current + 1) % threads.size();
return threads[current]->invokeWithCallback(&Worker::Impl::parseLiveTile, callback, &worker, &tile);
}
diff --git a/src/mbgl/util/worker.hpp b/src/mbgl/util/worker.hpp
index 3ecc402ad2..4e63b45abf 100644
--- a/src/mbgl/util/worker.hpp
+++ b/src/mbgl/util/worker.hpp
@@ -12,7 +12,7 @@ namespace mbgl {
class WorkRequest;
class RasterBucket;
-class LiveTile;
+class AnnotationTile;
class Worker : public mbgl::util::noncopyable {
public:
@@ -43,7 +43,7 @@ public:
Request parseLiveTile(
TileWorker&,
- const LiveTile&,
+ const AnnotationTile&,
std::function<void (TileParseResult)> callback);
Request redoPlacement(