summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJustin R. Miller <incanus@codesorcery.net>2015-06-15 18:30:39 -0700
committerJustin R. Miller <incanus@codesorcery.net>2015-06-15 18:30:39 -0700
commitbd0bf294bf1e350b184e54a824430c911dd66b9b (patch)
treed7c643cf197a8263fb1880ce73d034da253efe4c /src
parente75e538ddbb1dad0baad02576df86f6b8eb1510f (diff)
downloadqtlocation-mapboxgl-bd0bf294bf1e350b184e54a824430c911dd66b9b.tar.gz
squash of #1655: shape annotations support for core & iOS
Diffstat (limited to 'src')
-rw-r--r--src/mbgl/map/annotation.cpp582
-rw-r--r--src/mbgl/map/annotation.hpp69
-rw-r--r--src/mbgl/map/live_tile.cpp7
-rw-r--r--src/mbgl/map/live_tile.hpp7
-rw-r--r--src/mbgl/map/map.cpp24
-rw-r--r--src/mbgl/map/map_context.cpp114
-rw-r--r--src/mbgl/map/map_context.hpp6
-rw-r--r--src/mbgl/map/source.cpp13
-rw-r--r--src/mbgl/map/source.hpp4
-rw-r--r--src/mbgl/style/style_parser.cpp46
-rw-r--r--src/mbgl/style/style_properties.cpp1
-rw-r--r--src/mbgl/style/style_properties.hpp115
-rw-r--r--src/mbgl/style/types.hpp210
m---------src/mbgl/util/geojsonvt0
14 files changed, 696 insertions, 502 deletions
diff --git a/src/mbgl/map/annotation.cpp b/src/mbgl/map/annotation.cpp
index 6df49ec647..c946264593 100644
--- a/src/mbgl/map/annotation.cpp
+++ b/src/mbgl/map/annotation.cpp
@@ -4,6 +4,7 @@
#include <mbgl/map/live_tile.hpp>
#include <mbgl/map/map_data.hpp>
#include <mbgl/util/constants.hpp>
+#include <mbgl/util/geojsonvt/geojsonvt_convert.hpp>
#include <mbgl/util/ptr.hpp>
#include <algorithm>
@@ -11,35 +12,15 @@
namespace mbgl {
-enum class AnnotationType : uint8_t {
- Point,
- Shape
-};
-
-using AnnotationSegment = std::vector<LatLng>;
-using AnnotationSegments = std::vector<AnnotationSegment>;
-
-class Annotation : private util::noncopyable {
- friend class AnnotationManager;
-public:
- Annotation(AnnotationType, const AnnotationSegments&);
-
-private:
- LatLng getPoint() const;
- LatLngBounds getBounds() const { return bounds; }
-
-private:
- const AnnotationType type = AnnotationType::Point;
- const AnnotationSegments geometry;
- std::unordered_map<TileID, std::weak_ptr<const LiveTileFeature>, TileID::Hash> tileFeatures;
- const LatLngBounds bounds;
-};
-
-Annotation::Annotation(AnnotationType type_, const AnnotationSegments& geometry_)
- : type(type_),
+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 {
@@ -67,6 +48,16 @@ AnnotationManager::~AnnotationManager() {
// Annotation so we can't destruct the object with just the header file.
}
+void AnnotationManager::markStaleTiles(std::unordered_set<TileID, TileID::Hash> ids) {
+ std::lock_guard<std::mutex> lock(mtx);
+ std::copy(ids.begin(), ids.end(), std::inserter(staleTiles, staleTiles.begin()));
+}
+
+std::unordered_set<TileID, TileID::Hash> AnnotationManager::resetStaleTiles() {
+ std::lock_guard<std::mutex> lock(mtx);
+ return std::move(staleTiles);
+}
+
void AnnotationManager::setDefaultPointAnnotationSymbol(const std::string& symbol) {
std::lock_guard<std::mutex> lock(mtx);
defaultPointAnnotationSymbol = symbol;
@@ -77,118 +68,314 @@ uint32_t AnnotationManager::nextID() {
}
vec2<double> AnnotationManager::projectPoint(const LatLng& point) {
+ // Clamp to the latitude limits of Mercator.
+ const double constrainedLatitude = std::fmin(std::fmax(point.latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX);
+
// Project a coordinate into unit space in a square map.
- const double sine = std::sin(point.latitude * M_PI / 180.0);
+ 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 };
}
-std::pair<std::vector<TileID>, AnnotationIDs>
-AnnotationManager::addPointAnnotations(const std::vector<LatLng>& points,
- const std::vector<std::string>& symbols,
- const MapData& data) {
+std::pair<std::unordered_set<TileID, TileID::Hash>, AnnotationIDs>
+AnnotationManager::addAnnotations(const AnnotationType type,
+ const std::vector<AnnotationSegments>& segments,
+ const std::vector<StyleProperties>& styleProperties,
+ const AnnotationsProperties& annotationsProperties,
+ const MapData& data) {
std::lock_guard<std::mutex> lock(mtx);
+ assert(type != AnnotationType::Any);
+
// 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 uint16_t extent = 4096;
+ AnnotationIDs annotationIDs;
+ annotationIDs.reserve((type == AnnotationType::Shape ?
+ segments.size() : // shapes
+ segments[0][0].size())); // points
+
+ std::unordered_set<TileID, TileID::Hash> affectedTiles;
+
+ const uint8_t maxZoom = data.transform.getMaxZoom();
+
+ for (size_t s = 0; s < segments.size(); ++s) {
+
+ if (type == AnnotationType::Point) {
- std::vector<uint32_t> annotationIDs;
- annotationIDs.reserve(points.size());
+ for (size_t l = 0; l < segments[s].size(); ++l) {
- std::vector<TileID> affectedTiles;
+ for (size_t p = 0; p < segments[s][l].size(); ++p) {
- for (size_t i = 0; i < points.size(); ++i) {
- const uint32_t annotationID = nextID();
+ auto& point = segments[s][l][p];
- // track the annotation global ID and its geometry
- auto anno_it = annotations.emplace(
- annotationID,
- std::make_unique<Annotation>(AnnotationType::Point,
- AnnotationSegments({ { points[i] } })));
+ // projection conversion into unit space
+ const auto pp = projectPoint(point);
+
+ const uint32_t pointAnnotationID = nextID();
+
+ // at render time we style the point according to its {sprite} field
+ std::unordered_map<std::string, std::string> pointFeatureProperties;
+ const std::string& symbol = annotationsProperties.at("symbols")[p];
+ if (symbol.length()) {
+ pointFeatureProperties.emplace("sprite", symbol);
+ } else {
+ pointFeatureProperties.emplace("sprite", defaultPointAnnotationSymbol);
+ }
+
+ // add individual point tile feature
+ auto featureAffectedTiles = addTileFeature(
+ pointAnnotationID,
+ AnnotationSegments({{ point }}),
+ std::vector<std::vector<vec2<double>>>({{ pp }}),
+ AnnotationType::Point,
+ {{ }},
+ pointFeatureProperties,
+ maxZoom
+ );
+
+ std::copy(featureAffectedTiles.begin(), featureAffectedTiles.end(), std::inserter(affectedTiles, affectedTiles.begin()));
+
+ annotationIDs.push_back(pointAnnotationID);
+ }
+ }
+ } else {
+
+ const uint32_t shapeAnnotationID = nextID();
+
+ // current shape tiles are on-the-fly, so we don't get any "affected tiles"
+ // and just expire all annotation tiles for shape adds
+
+ addTileFeature(
+ shapeAnnotationID,
+ segments[s],
+ {{ }},
+ AnnotationType::Shape,
+ styleProperties[s],
+ {{ }},
+ maxZoom
+ );
+
+ annotationIDs.push_back(shapeAnnotationID);
+ }
+ }
+
+ // Tile:IDs that need refreshed and the annotation identifiers held onto by the client.
+ return std::make_pair(affectedTiles, annotationIDs);
+}
- const uint8_t maxZoom = data.transform.getMaxZoom();
+std::unordered_set<TileID, TileID::Hash>
+AnnotationManager::addTileFeature(const uint32_t annotationID,
+ const AnnotationSegments& segments,
+ const std::vector<std::vector<vec2<double>>>& projectedFeature,
+ const AnnotationType& type,
+ const StyleProperties& styleProperties,
+ const std::unordered_map<std::string, std::string>& featureProperties,
+ const uint8_t maxZoom) {
- // side length of map at this zoom
+ assert(type != AnnotationType::Any);
+
+ // track the annotation global ID and its original geometry
+ auto anno_it = annotations.emplace(annotationID,
+ std::make_unique<Annotation>(type, segments, styleProperties));
+
+ std::unordered_set<TileID, TileID::Hash> affectedTiles;
+
+ if (type == AnnotationType::Shape) {
+
+ 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 < segments[0].size(); ++i) { // first segment for now (no holes)
+ const double constraintedLatitude = std::fmin(std::fmax(segments[0][i].latitude, -util::LATITUDE_MAX), util::LATITUDE_MAX);
+ points.push_back(LonLat(segments[0][i].longitude, constraintedLatitude));
+ }
+
+ ProjectedFeatureType featureType;
+
+ if (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));
+
+ } else {
+
+ // side length of map at max zoom
uint32_t z2 = 1 << maxZoom;
- // projection conversion into unit space
- const vec2<double> p = projectPoint(points[i]);
+ const uint16_t extent = 4096;
- uint32_t x = p.x * z2;
- uint32_t y = p.y * z2;
+ uint32_t x = 0;
+ uint32_t y = 0;
for (int8_t z = maxZoom; z >= 0; z--) {
- affectedTiles.emplace_back(z, x, y, z);
- TileID tileID = affectedTiles.back();
-
- // calculate tile coordinate
- const Coordinate coordinate(extent * (p.x * z2 - x), extent * (p.y * z2 - y));
-
- const GeometryCollection geometries({ { { { coordinate } } } });
-
- // at render time we style the annotation according to its {sprite} field
- const 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 = tiles.find(tileID);
- if (tile_it != tiles.end()) {
- //
- // We have this tile created already. Add this feature to it.
- //
- // get point layer & add feature
- auto layer =
- tile_it->second.second->getMutableLayer(layerID);
- layer->addFeature(feature);
- // record annotation association with tile
- tile_it->second.first.insert(annotationID);
+
+ std::unordered_map<TileID, GeometryCollection, TileID::Hash> featureTiles;
+
+ if (type == AnnotationType::Point) {
+ auto& pp = projectedFeature[0][0];
+
+ x = pp.x * z2;
+ y = pp.y * z2;
+
+ const Coordinate coordinate(extent * (pp.x * z2 - x), extent * (pp.y * z2 - y));
+
+ GeometryCollection geometries = {{ {{ coordinate }} }};
+
+ featureTiles.emplace(TileID(z, x, y, z), geometries);
} else {
- //
- // We need to create a new tile for this feature.
- //
- // create point layer & add feature
- util::ptr<LiveTileLayer> layer = std::make_shared<LiveTileLayer>();
- layer->addFeature(feature);
- // create tile & record annotation association
- auto tile_pos = tiles.emplace(
- tileID, std::make_pair(std::unordered_set<uint32_t>({ annotationID }),
- std::make_unique<LiveTile>()));
- // add point layer to tile
- tile_pos.first->second.second->addLayer(layerID, layer);
+ for (size_t l = 0; l < projectedFeature.size(); ++l) {
+
+ std::vector<Coordinate> line;
+
+ for (size_t p = 0; p < projectedFeature[l].size(); ++p) {
+
+ auto& pp = projectedFeature[l][p];
+
+ x = pp.x * z2;
+ y = pp.y * z2;
+
+ const Coordinate coordinate(extent * (pp.x * z2 - x), extent * (pp.y * z2 - y));
+
+ auto tile_it = featureTiles.find(TileID(z, x, y, z));
+
+ if (tile_it != featureTiles.end()) {
+ GeometryCollection& geometries = featureTiles.find(TileID(z, x, y, z))->second;
+ if (geometries.size()) {
+ geometries.back().push_back(coordinate);
+ } else {
+ geometries.push_back({{ coordinate }});
+ }
+ } else {
+ GeometryCollection geometries = {{ {{ coordinate }} }};
+ featureTiles.emplace(TileID(z, x, y, z), geometries);
+ }
+ }
+ }
}
- // 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.
- anno_it.first->second->tileFeatures.emplace(
- tileID, std::weak_ptr<const LiveTileFeature>(feature));
+ for (auto& featureTile : featureTiles) {
+ // determine feature type
+ FeatureType featureType;
+ if (type == AnnotationType::Point) {
+ featureType = FeatureType::Point;
+ } else if (styleProperties.is<LineProperties>()) {
+ featureType = FeatureType::LineString;
+ } else if (styleProperties.is<FillProperties>()) {
+ featureType = FeatureType::Polygon;
+ } else {
+ throw std::runtime_error("Invalid feature type");
+ }
+
+ // create tile feature
+ auto feature = std::make_shared<const LiveTileFeature>(
+ featureType,
+ featureTile.second,
+ featureProperties
+ );
+
+ // check for tile & create if necessary
+ auto tile_pos = tiles.emplace(featureTile.first,
+ 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 = "";
+ if (type == AnnotationType::Point) {
+ layerID = PointLayerID;
+ } else {
+ layerID = ShapeLayerID + "." + std::to_string(annotationID);
+ }
+ 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.
+ anno_it.first->second->tilePointFeatures.emplace(featureTile.first, std::weak_ptr<const LiveTileFeature>(feature));
+
+ // track affected tile
+ affectedTiles.insert(featureTile.first);
+ }
// get ready for the next-lower zoom number
z2 /= 2;
x /= 2;
y /= 2;
}
-
- annotationIDs.push_back(annotationID);
}
- // Tile:IDs that need refreshed and the annotation identifiers held onto by the client.
- return std::make_pair(affectedTiles, annotationIDs);
+ return affectedTiles;
+}
+
+std::pair<std::unordered_set<TileID, TileID::Hash>, AnnotationIDs>
+AnnotationManager::addPointAnnotations(const AnnotationSegment& points,
+ const AnnotationsProperties& annotationsProperties,
+ const MapData& data) {
+ return addAnnotations(AnnotationType::Point,
+ {{ points }},
+ {{ }},
+ annotationsProperties,
+ data);
}
-std::vector<TileID> AnnotationManager::removeAnnotations(const AnnotationIDs& ids,
- const MapData& data) {
+std::pair<std::unordered_set<TileID, TileID::Hash>, AnnotationIDs>
+AnnotationManager::addShapeAnnotations(const std::vector<AnnotationSegments>& shapes,
+ const std::vector<StyleProperties>& styleProperties,
+ const AnnotationsProperties& annotationsProperties,
+ const MapData& data) {
+ return addAnnotations(AnnotationType::Shape,
+ shapes,
+ styleProperties,
+ annotationsProperties,
+ data);
+}
+
+std::unordered_set<TileID, TileID::Hash> AnnotationManager::removeAnnotations(const AnnotationIDs& ids,
+ const MapData& data) {
std::lock_guard<std::mutex> lock(mtx);
- std::vector<TileID> affectedTiles;
+ std::unordered_set<TileID, TileID::Hash> affectedTiles;
std::vector<uint32_t> z2s;
const uint8_t zoomCount = data.transform.getMaxZoom() + 1;
@@ -207,25 +394,44 @@ std::vector<TileID> AnnotationManager::removeAnnotations(const AnnotationIDs& id
const auto& annotation_it = annotations.find(annotationID);
if (annotation_it != annotations.end()) {
const auto& annotation = annotation_it->second;
- // 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->tileFeatures.find(tid);
- if (features_it != annotation->tileFeatures.end()) {
- const auto& layer =
- tiles[tid].second->getMutableLayer(layerID);
- layer->removeFeature(features_it->second);
- affectedTiles.push_back(tid);
+ // 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(PointLayerID);
+ layer->removeFeature(features_it->second);
+ affectedTiles.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(ShapeLayerID + "." + std::to_string(annotationID));
+ affectedTiles.insert(tile_it->first);
+ }
}
+
+ // 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);
}
}
@@ -234,8 +440,18 @@ std::vector<TileID> AnnotationManager::removeAnnotations(const AnnotationIDs& id
return affectedTiles;
}
-std::vector<uint32_t> AnnotationManager::getAnnotationsInBounds(const LatLngBounds& queryBounds,
- const MapData& data) const {
+const StyleProperties AnnotationManager::getAnnotationStyleProperties(uint32_t annotationID) const {
+ std::lock_guard<std::mutex> lock(mtx);
+
+ auto anno_it = annotations.find(annotationID);
+ assert(anno_it != annotations.end());
+
+ return anno_it->second->styleProperties;
+}
+
+AnnotationIDs AnnotationManager::getAnnotationsInBounds(const LatLngBounds& queryBounds,
+ const MapData& data,
+ const AnnotationType& type) const {
std::lock_guard<std::mutex> lock(mtx);
const uint8_t z = data.transform.getMaxZoom();
@@ -247,7 +463,7 @@ std::vector<uint32_t> AnnotationManager::getAnnotationsInBounds(const LatLngBoun
const TileID nwTile(z, swPoint.x * z2, nePoint.y * z2, z);
const TileID seTile(z, nePoint.x * z2, swPoint.y * z2, z);
- std::vector<uint32_t> matchingAnnotations;
+ std::unordered_set<uint32_t> matchingAnnotations;
for (auto& tile : tiles) {
TileID id = tile.first;
@@ -255,32 +471,50 @@ std::vector<uint32_t> AnnotationManager::getAnnotationsInBounds(const LatLngBoun
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.
- std::copy(tile.second.first.begin(), tile.second.first.end(),
- std::back_inserter(matchingAnnotations));
+ // 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::back_inserter(matchingAnnotations),
+ std::inserter(matchingAnnotations, matchingAnnotations.begin()),
[&](const uint32_t annotationID) -> bool {
const auto it = annotations.find(annotationID);
if (it != annotations.end()) {
- const LatLngBounds annoBounds = it->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);
- } else {
- return false;
+ // 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 matchingAnnotations;
+ return AnnotationIDs(matchingAnnotations.begin(), matchingAnnotations.end());
}
LatLngBounds AnnotationManager::getBoundsForAnnotations(const AnnotationIDs& ids) const {
@@ -290,7 +524,7 @@ LatLngBounds AnnotationManager::getBoundsForAnnotations(const AnnotationIDs& ids
for (auto id : ids) {
const auto annotation_it = annotations.find(id);
if (annotation_it != annotations.end()) {
- bounds.extend(annotation_it->second->getPoint());
+ bounds.extend(annotation_it->second->getBounds());
}
}
@@ -300,13 +534,89 @@ LatLngBounds AnnotationManager::getBoundsForAnnotations(const AnnotationIDs& ids
const LiveTile* AnnotationManager::getTile(const TileID& id) {
std::lock_guard<std::mutex> lock(mtx);
- const auto tile_it = tiles.find(id);
- if (tile_it != tiles.end()) {
- return tile_it->second.second.get();
+ // 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.size()) {
+ // 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.size()) {
+
+ // create shape tile layers from GeoJSONVT queries
+ for (auto& tiler_it : shapeTilers) {
+ const auto annotationID = tiler_it.first;
+ const std::string layerID = ShapeLayerID + "." + std::to_string(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) {
+
+ // shape exists on this tile; let's make a layer
+ renderLayer = std::make_shared<LiveTileLayer>();
+
+ // convert the features and add to render layer
+ for (auto& shapeFeature : shapeTile.features) {
+
+ using namespace mapbox::util::geojsonvt;
+
+ 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);
+ }
+ }
+ }
}
- return nullptr;
+
+ return renderTile;
}
-const std::string AnnotationManager::layerID = "com.mapbox.annotations.points";
+const std::string AnnotationManager::PointLayerID = "com.mapbox.annotations.points";
+const std::string AnnotationManager::ShapeLayerID = "com.mapbox.annotations.shape";
}
diff --git a/src/mbgl/map/annotation.hpp b/src/mbgl/map/annotation.hpp
index 0c9a078e57..213ff608a0 100644
--- a/src/mbgl/map/annotation.hpp
+++ b/src/mbgl/map/annotation.hpp
@@ -1,8 +1,13 @@
#ifndef MBGL_MAP_ANNOTATIONS
#define MBGL_MAP_ANNOTATIONS
+#include <mbgl/map/map.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/util/geo.hpp>
+#include <mbgl/util/geojsonvt/geojsonvt.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/vec.hpp>
@@ -18,35 +23,87 @@ namespace mbgl {
class Annotation;
class Map;
class LiveTile;
+class LiveTileFeature;
class MapData;
-using AnnotationIDs = std::vector<uint32_t>;
+using AnnotationsProperties = std::unordered_map<std::string, std::vector<std::string>>;
+
+using GeoJSONVT = mapbox::util::geojsonvt::GeoJSONVT;
+
+class Annotation : private util::noncopyable {
+ friend class AnnotationManager;
+public:
+ Annotation(AnnotationType, const AnnotationSegments&, const StyleProperties&);
+
+public:
+ const StyleProperties styleProperties;
+
+private:
+ LatLng getPoint() const;
+ LatLngBounds getBounds() const { return bounds; }
+
+private:
+ const AnnotationType type = AnnotationType::Point;
+ const AnnotationSegments geometry;
+ std::unordered_map<TileID, std::weak_ptr<const LiveTileFeature>, TileID::Hash> tilePointFeatures;
+ const LatLngBounds bounds;
+};
class AnnotationManager : private util::noncopyable {
public:
AnnotationManager();
~AnnotationManager();
+ void markStaleTiles(std::unordered_set<TileID, TileID::Hash>);
+ std::unordered_set<TileID, TileID::Hash> resetStaleTiles();
+
void setDefaultPointAnnotationSymbol(const std::string& symbol);
- std::pair<std::vector<TileID>, AnnotationIDs> addPointAnnotations(
- const std::vector<LatLng>&, const std::vector<std::string>& symbols, const MapData&);
- std::vector<TileID> removeAnnotations(const AnnotationIDs&, const MapData&);
- AnnotationIDs getAnnotationsInBounds(const LatLngBounds&, const MapData&) const;
+ std::pair<std::unordered_set<TileID, TileID::Hash>, AnnotationIDs> addPointAnnotations(
+ const AnnotationSegment&,
+ const AnnotationsProperties&,
+ const MapData&);
+ std::pair<std::unordered_set<TileID, TileID::Hash>, AnnotationIDs> addShapeAnnotations(
+ const std::vector<AnnotationSegments>&,
+ const std::vector<StyleProperties>&,
+ const AnnotationsProperties&,
+ const MapData&);
+ std::unordered_set<TileID, TileID::Hash> removeAnnotations(const AnnotationIDs&, const MapData&);
+ AnnotationIDs getOrderedShapeAnnotations() const { return orderedShapeAnnotations; }
+ const StyleProperties getAnnotationStyleProperties(uint32_t) const;
+ AnnotationIDs getAnnotationsInBounds(const LatLngBounds&, const MapData&, const AnnotationType& = AnnotationType::Any) const;
LatLngBounds getBoundsForAnnotations(const AnnotationIDs&) const;
const LiveTile* getTile(const TileID& id);
- static const std::string layerID;
+ static const std::string PointLayerID;
+ static const std::string ShapeLayerID;
private:
inline uint32_t nextID();
static vec2<double> projectPoint(const LatLng& point);
+ std::pair<std::unordered_set<TileID, TileID::Hash>, AnnotationIDs> addAnnotations(
+ const AnnotationType,
+ const std::vector<AnnotationSegments>&,
+ const std::vector<StyleProperties>&,
+ const AnnotationsProperties&,
+ const MapData&);
+ std::unordered_set<TileID, TileID::Hash> addTileFeature(
+ const uint32_t annotationID,
+ const AnnotationSegments&,
+ const std::vector<std::vector<vec2<double>>>& projectedFeature,
+ const AnnotationType&,
+ const StyleProperties&,
+ const std::unordered_map<std::string, std::string>& featureProperties,
+ const uint8_t maxZoom);
private:
mutable std::mutex mtx;
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> staleTiles;
uint32_t nextID_ = 0;
};
diff --git a/src/mbgl/map/live_tile.cpp b/src/mbgl/map/live_tile.cpp
index 06337af184..f7a70f7d46 100644
--- a/src/mbgl/map/live_tile.cpp
+++ b/src/mbgl/map/live_tile.cpp
@@ -3,7 +3,8 @@
namespace mbgl {
-LiveTileFeature::LiveTileFeature(FeatureType type_, GeometryCollection geometries_, std::map<std::string, std::string> properties_)
+LiveTileFeature::LiveTileFeature(FeatureType type_, GeometryCollection geometries_,
+ std::unordered_map<std::string, std::string> properties_)
: type(type_),
properties(properties_),
geometries(geometries_) {}
@@ -41,6 +42,10 @@ 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);
}
diff --git a/src/mbgl/map/live_tile.hpp b/src/mbgl/map/live_tile.hpp
index b13b5a1f66..5b4c2d1c16 100644
--- a/src/mbgl/map/live_tile.hpp
+++ b/src/mbgl/map/live_tile.hpp
@@ -2,6 +2,7 @@
#define MBGL_MAP_LIVE_TILE
#include <map>
+#include <unordered_map>
#include <mbgl/map/geometry_tile.hpp>
@@ -9,7 +10,8 @@ namespace mbgl {
class LiveTileFeature : public GeometryTileFeature {
public:
- LiveTileFeature(FeatureType, GeometryCollection, std::map<std::string, std::string> properties = {{}});
+ 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;
@@ -17,7 +19,7 @@ public:
private:
FeatureType type = FeatureType::Unknown;
- std::map<std::string, std::string> properties;
+ std::unordered_map<std::string, std::string> properties;
GeometryCollection geometries;
};
@@ -40,6 +42,7 @@ 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;
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 47c9472d59..8d5b544191 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -6,6 +6,8 @@
#include <mbgl/util/projection.hpp>
#include <mbgl/util/thread.hpp>
+#include <unordered_map>
+
namespace mbgl {
Map::Map(View& view, FileSource& fileSource, MapMode mode)
@@ -239,8 +241,22 @@ uint32_t Map::addPointAnnotation(const LatLng& point, const std::string& symbol)
return addPointAnnotations({ point }, { symbol }).front();
}
-std::vector<uint32_t> Map::addPointAnnotations(const std::vector<LatLng>& points, const std::vector<std::string>& symbols) {
- auto result = data->annotationManager.addPointAnnotations(points, symbols, *data);
+AnnotationIDs Map::addPointAnnotations(const AnnotationSegment& points,
+ const std::vector<std::string>& symbols) {
+ AnnotationsProperties properties = { { "symbols", symbols } };
+ auto result = data->annotationManager.addPointAnnotations(points, properties, *data);
+ context->invoke(&MapContext::updateAnnotationTiles, result.first);
+ return result.second;
+}
+
+uint32_t Map::addShapeAnnotation(const AnnotationSegments& shape,
+ const StyleProperties& styleProperties) {
+ return addShapeAnnotations({ shape }, { styleProperties }).front();
+}
+
+AnnotationIDs Map::addShapeAnnotations(const std::vector<AnnotationSegments>& shapes,
+ const std::vector<StyleProperties>& styleProperties) {
+ auto result = data->annotationManager.addShapeAnnotations(shapes, styleProperties, {{}}, *data);
context->invoke(&MapContext::updateAnnotationTiles, result.first);
return result.second;
}
@@ -254,8 +270,8 @@ void Map::removeAnnotations(const std::vector<uint32_t>& annotations) {
context->invoke(&MapContext::updateAnnotationTiles, result);
}
-std::vector<uint32_t> Map::getAnnotationsInBounds(const LatLngBounds& bounds) {
- return data->annotationManager.getAnnotationsInBounds(bounds, *data);
+std::vector<uint32_t> Map::getAnnotationsInBounds(const LatLngBounds& bounds, const AnnotationType& type) {
+ return data->annotationManager.getAnnotationsInBounds(bounds, *data, type);
}
LatLngBounds Map::getBoundsForAnnotations(const std::vector<uint32_t>& annotations) {
diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp
index c349bdd155..bd288a5cda 100644
--- a/src/mbgl/map/map_context.cpp
+++ b/src/mbgl/map/map_context.cpp
@@ -3,6 +3,7 @@
#include <mbgl/map/view.hpp>
#include <mbgl/map/environment.hpp>
#include <mbgl/map/still_image.hpp>
+#include <mbgl/map/annotation.hpp>
#include <mbgl/platform/log.hpp>
@@ -12,12 +13,16 @@
#include <mbgl/storage/response.hpp>
#include <mbgl/style/style.hpp>
+#include <mbgl/style/style_bucket.hpp>
+#include <mbgl/style/style_layer.hpp>
#include <mbgl/util/uv_detail.hpp>
#include <mbgl/util/worker.hpp>
#include <mbgl/util/texture_pool.hpp>
#include <mbgl/util/exception.hpp>
+#include <algorithm>
+
namespace mbgl {
MapContext::MapContext(uv_loop_t* loop, View& view_, FileSource& fileSource, MapData& data_)
@@ -112,6 +117,11 @@ void MapContext::loadStyleJSON(const std::string& json, const std::string& base)
style->setObserver(this);
triggerUpdate(Update::Zoom);
+
+ auto staleTiles = data.annotationManager.resetStaleTiles();
+ if (staleTiles.size()) {
+ updateAnnotationTiles(staleTiles);
+ }
}
void MapContext::updateTiles() {
@@ -120,15 +130,111 @@ void MapContext::updateTiles() {
style->update(data, transformState, *texturePool);
}
-void MapContext::updateAnnotationTiles(const std::vector<TileID>& ids) {
+void MapContext::updateAnnotationTiles(const std::unordered_set<TileID, TileID::Hash>& ids) {
assert(Environment::currentlyOn(ThreadType::Map));
+
+ data.annotationManager.markStaleTiles(ids);
+
if (!style) return;
+
+ // grab existing, single shape annotations source
+ const auto& shapeID = AnnotationManager::ShapeLayerID;
+
+ const auto source_it = std::find_if(style->sources.begin(), style->sources.end(),
+ [&shapeID](util::ptr<Source> source) {
+ return (source->info.source_id == shapeID);
+ });
+ assert(source_it != style->sources.end());
+ source_it->get()->enabled = true;
+
+ // create (if necessary) layers and buckets for each shape
+ for (const auto &shapeAnnotationID : data.annotationManager.getOrderedShapeAnnotations()) {
+ const std::string shapeLayerID = shapeID + "." + std::to_string(shapeAnnotationID);
+
+ const auto layer_it = std::find_if(style->layers.begin(), style->layers.end(),
+ [&shapeLayerID](util::ptr<StyleLayer> layer) {
+ return (layer->id == shapeLayerID);
+ });
+
+ if (layer_it == style->layers.end()) {
+ // query shape styling
+ auto& shapeStyle = data.annotationManager.getAnnotationStyleProperties(shapeAnnotationID);
+
+ // apply shape paint properties
+ ClassProperties paintProperties;
+
+ if (shapeStyle.is<LineProperties>()) {
+ // opacity
+ PropertyValue lineOpacity = ConstantFunction<float>(shapeStyle.get<LineProperties>().opacity);
+ paintProperties.set(PropertyKey::LineOpacity, lineOpacity);
+
+ // line width
+ PropertyValue lineWidth = ConstantFunction<float>(shapeStyle.get<LineProperties>().width);
+ paintProperties.set(PropertyKey::LineWidth, lineWidth);
+
+ // stroke color
+ PropertyValue strokeColor = ConstantFunction<Color>(shapeStyle.get<LineProperties>().color);
+ paintProperties.set(PropertyKey::LineColor, strokeColor);
+ } else if (shapeStyle.is<FillProperties>()) {
+ // opacity
+ PropertyValue fillOpacity = ConstantFunction<float>(shapeStyle.get<FillProperties>().opacity);
+ paintProperties.set(PropertyKey::FillOpacity, fillOpacity);
+
+ // fill color
+ PropertyValue fillColor = ConstantFunction<Color>(shapeStyle.get<FillProperties>().fill_color);
+ paintProperties.set(PropertyKey::FillColor, fillColor);
+
+ // stroke color
+ PropertyValue strokeColor = ConstantFunction<Color>(shapeStyle.get<FillProperties>().stroke_color);
+ paintProperties.set(PropertyKey::FillOutlineColor, strokeColor);
+ }
+
+ std::map<ClassID, ClassProperties> shapePaints;
+ shapePaints.emplace(ClassID::Default, std::move(paintProperties));
+
+ // create shape layer
+ util::ptr<StyleLayer> shapeLayer = std::make_shared<StyleLayer>(shapeLayerID, std::move(shapePaints));
+ shapeLayer->type = (shapeStyle.is<LineProperties>() ? StyleLayerType::Line : StyleLayerType::Fill);
+
+ // add to end of other shape layers just before (last) point layer
+ style->layers.emplace((style->layers.end() - 2), shapeLayer);
+
+ // create shape bucket & connect to source
+ util::ptr<StyleBucket> shapeBucket = std::make_shared<StyleBucket>(shapeLayer->type);
+ shapeBucket->name = shapeLayer->id;
+ shapeBucket->source_layer = shapeLayer->id;
+ shapeBucket->source = *source_it;
+
+ // apply line layout properties to bucket
+ if (shapeStyle.is<LineProperties>()) {
+ shapeBucket->layout.set(PropertyKey::LineJoin, ConstantFunction<JoinType>(JoinType::Round));
+ }
+
+ // connect layer to bucket
+ shapeLayer->bucket = shapeBucket;
+ }
+ }
+
+ // invalidate annotations layer tiles
for (const auto &source : style->sources) {
if (source->info.type == SourceType::Annotations) {
source->invalidateTiles(ids);
}
}
- triggerUpdate();
+
+ cascadeClasses();
+
+ triggerUpdate(Update::Classes);
+
+ data.annotationManager.resetStaleTiles();
+}
+
+void MapContext::cascadeClasses() {
+ style->cascade(data.getClasses());
+}
+
+void MapContext::recalculateStyle(TimePoint now) {
+ style->recalculate(transformState.getNormalizedZoom(), now);
}
void MapContext::update() {
@@ -146,12 +252,12 @@ void MapContext::update() {
}
if (updated & static_cast<UpdateType>(Update::Classes)) {
- style->cascade(data.getClasses());
+ cascadeClasses();
}
if (updated & static_cast<UpdateType>(Update::Classes) ||
updated & static_cast<UpdateType>(Update::Zoom)) {
- style->recalculate(transformState.getNormalizedZoom(), now);
+ recalculateStyle(now);
}
updateTiles();
diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp
index 81e757c4cf..16fdea1820 100644
--- a/src/mbgl/map/map_context.hpp
+++ b/src/mbgl/map/map_context.hpp
@@ -49,7 +49,7 @@ public:
std::string getStyleJSON() const { return styleJSON; }
double getTopOffsetPixelsForAnnotationSymbol(const std::string& symbol);
- void updateAnnotationTiles(const std::vector<TileID>&);
+ void updateAnnotationTiles(const std::unordered_set<TileID, TileID::Hash>&);
void setSourceTileCacheSize(size_t size);
void onLowMemory();
@@ -63,6 +63,10 @@ public:
private:
void updateTiles();
+ // Style-related updates.
+ void cascadeClasses();
+ void recalculateStyle(TimePoint);
+
// Update the state indicated by the accumulated Update flags, then render.
void update();
diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp
index 97adacad6d..7fb015c1da 100644
--- a/src/mbgl/map/source.cpp
+++ b/src/mbgl/map/source.cpp
@@ -521,11 +521,16 @@ bool Source::update(MapData& data,
return allTilesUpdated;
}
-void Source::invalidateTiles(const std::vector<TileID>& ids) {
+void Source::invalidateTiles(const std::unordered_set<TileID, TileID::Hash>& ids) {
cache.clear();
- for (auto& id : ids) {
- tiles.erase(id);
- tile_data.erase(id);
+ if (ids.size()) {
+ for (auto& id : ids) {
+ tiles.erase(id);
+ tile_data.erase(id);
+ }
+ } else {
+ tiles.clear();
+ tile_data.clear();
}
updateTilePtrs();
}
diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp
index be869559b5..aea8939c45 100644
--- a/src/mbgl/map/source.hpp
+++ b/src/mbgl/map/source.hpp
@@ -17,6 +17,7 @@
#include <forward_list>
#include <iosfwd>
#include <map>
+#include <unordered_set>
namespace mbgl {
@@ -46,6 +47,7 @@ public:
std::string attribution;
std::array<float, 3> center = {{0, 0, 0}};
std::array<float, 4> bounds = {{-180, -90, 180, 90}};
+ std::string source_id = "";
void parseTileJSONProperties(const rapidjson::Value&);
std::string tileURL(const TileID& id, float pixelRatio) const;
@@ -86,7 +88,7 @@ public:
TexturePool&,
bool shouldReparsePartialTiles);
- void invalidateTiles(const std::vector<TileID>&);
+ void invalidateTiles(const std::unordered_set<TileID, TileID::Hash>&);
void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
void drawClippingMasks(Painter &painter);
diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp
index 83a113f885..c2aa115fa4 100644
--- a/src/mbgl/style/style_parser.cpp
+++ b/src/mbgl/style/style_parser.cpp
@@ -36,20 +36,30 @@ void StyleParser::parse(JSVal document) {
if (document.HasMember("layers")) {
parseLayers(document["layers"]);
+ // create shape annotations source
+ const std::string& shapeID = AnnotationManager::ShapeLayerID;
+
+ util::ptr<Source> shapeAnnotationsSource = std::make_shared<Source>();
+ sourcesMap.emplace(shapeID, shapeAnnotationsSource);
+ sources.emplace_back(shapeAnnotationsSource);
+ shapeAnnotationsSource->info.type = SourceType::Annotations;
+ shapeAnnotationsSource->info.source_id = shapeID;
+
// create point annotations layer
- //
- const std::string& id = AnnotationManager::layerID;
+ const std::string& pointID = AnnotationManager::PointLayerID;
- std::map<ClassID, ClassProperties> paints;
- util::ptr<StyleLayer> annotations = std::make_shared<StyleLayer>(id, std::move(paints));
- annotations->type = StyleLayerType::Symbol;
- layersMap.emplace(id, std::pair<JSVal, util::ptr<StyleLayer>> { JSVal(id), annotations });
- layers.emplace_back(annotations);
+ std::map<ClassID, ClassProperties> pointPaints;
+ util::ptr<StyleLayer> pointAnnotationsLayer = std::make_shared<StyleLayer>(pointID, std::move(pointPaints));
+ pointAnnotationsLayer->type = StyleLayerType::Symbol;
+ layersMap.emplace(pointID, std::pair<JSVal, util::ptr<StyleLayer>> { JSVal(pointID), pointAnnotationsLayer });
+ layers.emplace_back(pointAnnotationsLayer);
- util::ptr<StyleBucket> pointBucket = std::make_shared<StyleBucket>(annotations->type);
- pointBucket->name = annotations->id;
- pointBucket->source_layer = annotations->id;
+ // create point annotations symbol bucket
+ util::ptr<StyleBucket> pointBucket = std::make_shared<StyleBucket>(pointAnnotationsLayer->type);
+ pointBucket->name = pointAnnotationsLayer->id;
+ pointBucket->source_layer = pointAnnotationsLayer->id;
+ // build up point annotations style
rapidjson::Document d;
rapidjson::Value iconImage(rapidjson::kObjectType);
iconImage.AddMember("icon-image", "{sprite}", d.GetAllocator());
@@ -58,14 +68,14 @@ void StyleParser::parse(JSVal document) {
iconOverlap.AddMember("icon-allow-overlap", true, d.GetAllocator());
parseLayout(iconOverlap, pointBucket);
- util::ptr<Source> source = std::make_shared<Source>();
- sourcesMap.emplace(id, source);
- sources.emplace_back(source);
- source->info.type = SourceType::Annotations;
- pointBucket->source = source;
- annotations->bucket = pointBucket;
- //
- // end point annotations
+ // create point annotations source & connect to bucket & layer
+ util::ptr<Source> pointAnnotationsSource = std::make_shared<Source>();
+ sourcesMap.emplace(pointID, pointAnnotationsSource);
+ sources.emplace_back(pointAnnotationsSource);
+ pointAnnotationsSource->info.type = SourceType::Annotations;
+ pointAnnotationsSource->info.source_id = pointID;
+ pointBucket->source = pointAnnotationsSource;
+ pointAnnotationsLayer->bucket = pointBucket;
}
if (document.HasMember("sprite")) {
diff --git a/src/mbgl/style/style_properties.cpp b/src/mbgl/style/style_properties.cpp
index 29730fb85b..3c5b525c1d 100644
--- a/src/mbgl/style/style_properties.cpp
+++ b/src/mbgl/style/style_properties.cpp
@@ -1,4 +1,5 @@
#include <mbgl/style/style_properties.hpp>
+#include <mbgl/style/piecewisefunction_properties.hpp>
namespace mbgl {
diff --git a/src/mbgl/style/style_properties.hpp b/src/mbgl/style/style_properties.hpp
deleted file mode 100644
index 8e8619fb99..0000000000
--- a/src/mbgl/style/style_properties.hpp
+++ /dev/null
@@ -1,115 +0,0 @@
-#ifndef MBGL_STYLE_STYLE_PROPERTIES
-#define MBGL_STYLE_STYLE_PROPERTIES
-
-#include <mbgl/util/variant.hpp>
-#include <mbgl/style/types.hpp>
-#include <mbgl/style/piecewisefunction_properties.hpp>
-
-#include <array>
-#include <string>
-#include <type_traits>
-#include <memory>
-#include <vector>
-
-namespace mbgl {
-
-struct FillProperties {
- FillProperties() {}
- bool antialias = true;
- float opacity = 1.0f;
- Color fill_color = {{ 0, 0, 0, 1 }};
- Color stroke_color = {{ 0, 0, 0, -1 }};
- std::array<float, 2> translate = {{ 0, 0 }};
- TranslateAnchorType translateAnchor = TranslateAnchorType::Map;
- Faded<std::string> image;
-
- inline bool isVisible() const {
- return opacity > 0 && (fill_color[3] > 0 || stroke_color[3] > 0);
- }
-};
-
-struct LineProperties {
- inline LineProperties() {}
- float opacity = 1.0f;
- Color color = {{ 0, 0, 0, 1 }};
- std::array<float, 2> translate = {{ 0, 0 }};
- TranslateAnchorType translateAnchor = TranslateAnchorType::Map;
- float width = 1;
- float gap_width = 0;
- float blur = 0;
- Faded<std::vector<float>> dash_array;
- float dash_line_width = 1;
- Faded<std::string> image;
-
- inline bool isVisible() const {
- return opacity > 0 && color[3] > 0 && width > 0;
- }
-};
-
-struct SymbolProperties {
- inline SymbolProperties() {}
-
- struct {
- float opacity = 1.0f;
- float size = 1.0f;
- Color color = {{ 0, 0, 0, 1 }};
- Color halo_color = {{ 0, 0, 0, 0 }};
- float halo_width = 0.0f;
- float halo_blur = 0.0f;
- std::array<float, 2> translate = {{ 0, 0 }};
- TranslateAnchorType translate_anchor = TranslateAnchorType::Map;
- } icon;
-
- struct {
- float opacity = 1.0f;
- float size = 16.0f;
- Color color = {{ 0, 0, 0, 1 }};
- Color halo_color = {{ 0, 0, 0, 0 }};
- float halo_width = 0.0f;
- float halo_blur = 0.0f;
- std::array<float, 2> translate = {{ 0, 0 }};
- TranslateAnchorType translate_anchor = TranslateAnchorType::Map;
- } text;
-
- inline bool isVisible() const {
- return (icon.opacity > 0 && (icon.color[3] > 0 || icon.halo_color[3] > 0) && icon.size > 0) ||
- (text.opacity > 0 && (text.color[3] > 0 || text.halo_color[3] > 0) && text.size > 0);
- }
-};
-
-struct RasterProperties {
- inline RasterProperties() {}
- float opacity = 1.0f;
- float hue_rotate = 0.0f;
- std::array<float, 2> brightness = {{ 0, 1 }};
- float saturation = 0.0f;
- float contrast = 0.0f;
- float fade = 0.0f;
-
- inline bool isVisible() const {
- return opacity > 0;
- }
-};
-
-struct BackgroundProperties {
- inline BackgroundProperties() {}
- float opacity = 1.0f;
- Color color = {{ 0, 0, 0, 1 }};
- Faded<std::string> image;
-};
-
-typedef mapbox::util::variant<
- FillProperties,
- LineProperties,
- SymbolProperties,
- RasterProperties,
- BackgroundProperties,
- std::false_type
-> StyleProperties;
-
-template <typename T>
-const T &defaultStyleProperties();
-
-}
-
-#endif
diff --git a/src/mbgl/style/types.hpp b/src/mbgl/style/types.hpp
deleted file mode 100644
index f6ffcd6865..0000000000
--- a/src/mbgl/style/types.hpp
+++ /dev/null
@@ -1,210 +0,0 @@
-#ifndef MBGL_STYLE_TYPES
-#define MBGL_STYLE_TYPES
-
-#include <mbgl/util/enum.hpp>
-
-#include <string>
-#include <array>
-
-namespace mbgl {
-
-// Stores a premultiplied color, with all four channels ranging from 0..1
-typedef std::array<float, 4> Color;
-
-
-template <typename T>
-struct Faded {
- T from;
- float fromScale;
- T to;
- float toScale;
- float t;
-};
-
-// -------------------------------------------------------------------------------------------------
-
-enum class StyleLayerType : uint8_t {
- Unknown,
- Fill,
- Line,
- Symbol,
- Raster,
- Background
-};
-
-MBGL_DEFINE_ENUM_CLASS(StyleLayerTypeClass, StyleLayerType, {
- { StyleLayerType::Unknown, "unknown" },
- { StyleLayerType::Fill, "fill" },
- { StyleLayerType::Line, "line" },
- { StyleLayerType::Symbol, "symbol" },
- { StyleLayerType::Raster, "raster" },
- { StyleLayerType::Background, "background" },
- { StyleLayerType(-1), "unknown" },
-});
-
-// -------------------------------------------------------------------------------------------------
-
-enum class SourceType : uint8_t {
- Vector,
- Raster,
- GeoJSON,
- Video,
- Annotations
-};
-
-MBGL_DEFINE_ENUM_CLASS(SourceTypeClass, SourceType, {
- { SourceType::Vector, "vector" },
- { SourceType::Raster, "raster" },
- { SourceType::GeoJSON, "geojson" },
- { SourceType::Video, "video" },
- { SourceType::Annotations, "annotations" },
-});
-
-// -------------------------------------------------------------------------------------------------
-
-enum class VisibilityType : bool {
- Visible,
- None,
-};
-
-MBGL_DEFINE_ENUM_CLASS(VisibilityTypeClass, VisibilityType, {
- { VisibilityType::Visible, "visible" },
- { VisibilityType::None, "none" },
-});
-
-// -------------------------------------------------------------------------------------------------
-
-enum class CapType : uint8_t {
- Round,
- Butt,
- Square,
-};
-
-MBGL_DEFINE_ENUM_CLASS(CapTypeClass, CapType, {
- { CapType::Round, "round" },
- { CapType::Butt, "butt" },
- { CapType::Square, "square" },
-});
-
-// -------------------------------------------------------------------------------------------------
-
-enum class JoinType : uint8_t {
- Miter,
- Bevel,
- Round,
- FlipBevel
-};
-
-MBGL_DEFINE_ENUM_CLASS(JoinTypeClass, JoinType, {
- { JoinType::Miter, "miter" },
- { JoinType::Bevel, "bevel" },
- { JoinType::Round, "round" },
- { JoinType::FlipBevel, "flipbevel" },
-});
-
-// -------------------------------------------------------------------------------------------------
-
-enum class TranslateAnchorType : bool {
- Map,
- Viewport
-};
-
-MBGL_DEFINE_ENUM_CLASS(TranslateAnchorTypeClass, TranslateAnchorType, {
- { TranslateAnchorType::Map, "map" },
- { TranslateAnchorType::Viewport, "viewport" },
-});
-
-// -------------------------------------------------------------------------------------------------
-
-enum class RotateAnchorType : bool {
- Map,
- Viewport,
-};
-
-MBGL_DEFINE_ENUM_CLASS(RotateAnchorTypeClass, RotateAnchorType, {
- { RotateAnchorType::Map, "map" },
- { RotateAnchorType::Viewport, "viewport" },
-});
-
-// -------------------------------------------------------------------------------------------------
-
-enum class PlacementType : bool {
- Point,
- Line,
-};
-
-MBGL_DEFINE_ENUM_CLASS(PlacementTypeClass, PlacementType, {
- { PlacementType::Point, "point" },
- { PlacementType::Line, "line" },
-});
-
-// -------------------------------------------------------------------------------------------------
-
-enum class RotationAlignmentType : bool {
- Map,
- Viewport,
-};
-
-MBGL_DEFINE_ENUM_CLASS(RotationAlignmentTypeClass, RotationAlignmentType, {
- { RotationAlignmentType::Map, "map" },
- { RotationAlignmentType::Viewport, "viewport" },
-});
-
-// -------------------------------------------------------------------------------------------------
-
-enum class TextJustifyType : uint8_t {
- Center,
- Left,
- Right
-};
-
-MBGL_DEFINE_ENUM_CLASS(TextJustifyTypeClass, TextJustifyType, {
- { TextJustifyType::Center, "center" },
- { TextJustifyType::Left, "left" },
- { TextJustifyType::Right, "right" },
-});
-
-// -------------------------------------------------------------------------------------------------
-
-enum class TextAnchorType : uint8_t {
- Center,
- Left,
- Right,
- Top,
- Bottom,
- TopLeft,
- TopRight,
- BottomLeft,
- BottomRight
-};
-
-MBGL_DEFINE_ENUM_CLASS(TextAnchorTypeClass, TextAnchorType, {
- { TextAnchorType::Center, "center" },
- { TextAnchorType::Left, "left" },
- { TextAnchorType::Right, "right" },
- { TextAnchorType::Top, "top" },
- { TextAnchorType::Bottom, "bottom" },
- { TextAnchorType::TopLeft, "top-left" },
- { TextAnchorType::TopRight, "top-right" },
- { TextAnchorType::BottomLeft, "bottom-left" },
- { TextAnchorType::BottomRight, "bottom-right" }
-});
-
-// -------------------------------------------------------------------------------------------------
-
-enum class TextTransformType : uint8_t {
- None,
- Uppercase,
- Lowercase,
-};
-
-MBGL_DEFINE_ENUM_CLASS(TextTransformTypeClass, TextTransformType, {
- { TextTransformType::None, "none" },
- { TextTransformType::Uppercase, "uppercase" },
- { TextTransformType::Lowercase, "lowercase" },
-});
-
-}
-
-#endif
-
diff --git a/src/mbgl/util/geojsonvt b/src/mbgl/util/geojsonvt
new file mode 160000
+Subproject ed99a6290fa42107a982e7f3675aae49d29026b