diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2015-10-22 13:11:25 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2015-10-22 15:27:53 -0700 |
commit | c46a8254c46acb0da3719e20e99c87b11e998da2 (patch) | |
tree | 635f8c3e3d878ff3e025a8175a3509a1ec4d6df7 | |
parent | 4f509288b7c671db96555a24a4f490311adfc13a (diff) | |
download | qtlocation-mapboxgl-c46a8254c46acb0da3719e20e99c87b11e998da2.tar.gz |
[core] Style-sourced shape annotation properties
This introduces the possibility to source the type and style properties
of a shape annotation from a designated layer in the style.
-rw-r--r-- | include/mbgl/annotation/shape_annotation.hpp | 11 | ||||
-rw-r--r-- | src/mbgl/annotation/shape_annotation_impl.cpp | 139 | ||||
-rw-r--r-- | src/mbgl/annotation/shape_annotation_impl.hpp | 8 | ||||
-rw-r--r-- | src/mbgl/style/class_properties.hpp | 4 | ||||
-rw-r--r-- | test/api/annotations.cpp | 15 | ||||
-rw-r--r-- | test/fixtures/api/annotation.json | 19 |
6 files changed, 129 insertions, 67 deletions
diff --git a/include/mbgl/annotation/shape_annotation.hpp b/include/mbgl/annotation/shape_annotation.hpp index 5e6a13149a..90f2a96dd0 100644 --- a/include/mbgl/annotation/shape_annotation.hpp +++ b/include/mbgl/annotation/shape_annotation.hpp @@ -15,14 +15,17 @@ using AnnotationSegments = std::vector<AnnotationSegment>; class ShapeAnnotation { public: - using Properties = mapbox::util::variant<FillPaintProperties, LinePaintProperties>; + using Properties = mapbox::util::variant< + FillPaintProperties, // creates a fill annotation + LinePaintProperties, // creates a line annotation + std::string>; // creates an annotation whose type and properties are sourced from a style layer - inline ShapeAnnotation(const AnnotationSegments& segments_, const Properties& styleProperties_) - : segments(segments_), styleProperties(styleProperties_) { + ShapeAnnotation(const AnnotationSegments& segments_, const Properties& properties_) + : segments(segments_), properties(properties_) { } const AnnotationSegments segments; - const Properties styleProperties; + const Properties properties; }; } diff --git a/src/mbgl/annotation/shape_annotation_impl.cpp b/src/mbgl/annotation/shape_annotation_impl.cpp index 5b3c07fbc9..4ab9958fdf 100644 --- a/src/mbgl/annotation/shape_annotation_impl.cpp +++ b/src/mbgl/annotation/shape_annotation_impl.cpp @@ -15,92 +15,115 @@ using namespace mapbox::util::geojsonvt; ShapeAnnotationImpl::ShapeAnnotationImpl(const AnnotationID id_, const ShapeAnnotation& shape_, - const uint8_t maxZoom) + 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<FillPaintProperties>()) { - 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) {} + maxZoom(maxZoom_) { +} void ShapeAnnotationImpl::updateStyle(Style& style) { if (style.getLayer(layerID)) return; - if (shape.styleProperties.is<LinePaintProperties>()) { - const LinePaintProperties& properties = shape.styleProperties.get<LinePaintProperties>(); + std::unique_ptr<StyleLayer> layer; - std::unique_ptr<LineLayer> layer = std::make_unique<LineLayer>(); - layer->id = layerID; - layer->type = StyleLayerType::Line; + if (shape.properties.is<LinePaintProperties>()) { + layer = createLineLayer(); + const LinePaintProperties& properties = shape.properties.get<LinePaintProperties>(); ClassProperties paintProperties; paintProperties.set(PropertyKey::LineOpacity, ConstantFunction<float>(properties.opacity)); paintProperties.set(PropertyKey::LineWidth, ConstantFunction<float>(properties.width)); paintProperties.set(PropertyKey::LineColor, ConstantFunction<Color>(properties.color)); layer->styles.emplace(ClassID::Default, std::move(paintProperties)); - layer->bucket = std::make_shared<StyleBucket>(layer->type); - layer->bucket->name = layer->id; - layer->bucket->source = AnnotationManager::SourceID; - layer->bucket->source_layer = layer->id; - layer->bucket->layout.set(PropertyKey::LineJoin, ConstantFunction<JoinType>(JoinType::Round)); - - style.addLayer(std::move(layer), AnnotationManager::PointLayerID); - - } else if (shape.styleProperties.is<FillPaintProperties>()) { - const FillPaintProperties& properties = shape.styleProperties.get<FillPaintProperties>(); - - std::unique_ptr<FillLayer> layer = std::make_unique<FillLayer>(); - layer->id = layerID; - layer->type = StyleLayerType::Fill; + } else if (shape.properties.is<FillPaintProperties>()) { + layer = createFillLayer(); + const FillPaintProperties& properties = shape.properties.get<FillPaintProperties>(); ClassProperties paintProperties; paintProperties.set(PropertyKey::FillOpacity, ConstantFunction<float>(properties.opacity)); paintProperties.set(PropertyKey::FillColor, ConstantFunction<Color>(properties.fill_color)); paintProperties.set(PropertyKey::FillOutlineColor, ConstantFunction<Color>(properties.stroke_color)); layer->styles.emplace(ClassID::Default, std::move(paintProperties)); - layer->bucket = std::make_shared<StyleBucket>(layer->type); - layer->bucket->name = layer->id; - layer->bucket->source = AnnotationManager::SourceID; - layer->bucket->source_layer = layer->id; + } else { + const StyleLayer* sourceLayer = style.getLayer(shape.properties.get<std::string>()); + if (!sourceLayer) return; + + switch (sourceLayer->type) { + case StyleLayerType::Line: + layer = createLineLayer(); + break; + + case StyleLayerType::Fill: + layer = createFillLayer(); + break; - style.addLayer(std::move(layer), AnnotationManager::PointLayerID); + default: + return; + } + + layer->styles = sourceLayer->styles; + layer->bucket->layout = sourceLayer->bucket->layout; } + + layer->bucket->name = layer->id; + layer->bucket->source = AnnotationManager::SourceID; + layer->bucket->source_layer = layer->id; + + style.addLayer(std::move(layer), AnnotationManager::PointLayerID); +} + +std::unique_ptr<StyleLayer> ShapeAnnotationImpl::createLineLayer() { + type = ProjectedFeatureType::LineString; + std::unique_ptr<LineLayer> layer = std::make_unique<LineLayer>(); + layer->id = layerID; + layer->type = StyleLayerType::Line; + layer->bucket = std::make_shared<StyleBucket>(layer->type); + layer->bucket->layout.set(PropertyKey::LineJoin, ConstantFunction<JoinType>(JoinType::Round)); + return std::move(layer); +} + +std::unique_ptr<StyleLayer> ShapeAnnotationImpl::createFillLayer() { + type = ProjectedFeatureType::Polygon; + std::unique_ptr<FillLayer> layer = std::make_unique<FillLayer>(); + layer->id = layerID; + layer->type = StyleLayerType::Fill; + layer->bucket = std::make_shared<StyleBucket>(layer->type); + return std::move(layer); } void ShapeAnnotationImpl::updateTile(const TileID& tileID, AnnotationTile& tile) { - const auto& shapeTile = shapeTiler.getTile(tileID.z, tileID.x, tileID.y); + if (!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)); + } + + if (type == ProjectedFeatureType::Polygon && + (points.front().lon != points.back().lon || points.front().lat != points.back().lat)) { + points.push_back(LonLat(points.front().lon, points.front().lat)); + } + + ProjectedGeometryContainer ring = Convert::project(points, tolerance); + rings.members.push_back(ring); + + std::vector<ProjectedFeature> features; + features.push_back(Convert::create(Tags(), type, rings)); + + shapeTiler = std::make_unique<mapbox::util::geojsonvt::GeoJSONVT>(features, maxZoom, 4, 100, 10); + } + + const auto& shapeTile = shapeTiler->getTile(tileID.z, tileID.x, tileID.y); if (!shapeTile) return; diff --git a/src/mbgl/annotation/shape_annotation_impl.hpp b/src/mbgl/annotation/shape_annotation_impl.hpp index 4cf6c23f61..1b1dacf370 100644 --- a/src/mbgl/annotation/shape_annotation_impl.hpp +++ b/src/mbgl/annotation/shape_annotation_impl.hpp @@ -13,6 +13,7 @@ namespace mbgl { class Style; +class StyleLayer; class AnnotationTile; class ShapeAnnotationImpl { @@ -30,7 +31,12 @@ public: const ShapeAnnotation shape; private: - mapbox::util::geojsonvt::GeoJSONVT shapeTiler; + std::unique_ptr<StyleLayer> createLineLayer(); + std::unique_ptr<StyleLayer> createFillLayer(); + + const uint8_t maxZoom; + mapbox::util::geojsonvt::ProjectedFeatureType type; + std::unique_ptr<mapbox::util::geojsonvt::GeoJSONVT> shapeTiler; }; } diff --git a/src/mbgl/style/class_properties.hpp b/src/mbgl/style/class_properties.hpp index 888a90c5d7..0f147fdda6 100644 --- a/src/mbgl/style/class_properties.hpp +++ b/src/mbgl/style/class_properties.hpp @@ -11,10 +11,6 @@ namespace mbgl { class ClassProperties { public: - inline ClassProperties() {} - inline ClassProperties(ClassProperties &&properties_) - : properties(std::move(properties_.properties)) {} - inline void set(PropertyKey key, const PropertyValue &value) { properties.emplace(key, value); } diff --git a/test/api/annotations.cpp b/test/api/annotations.cpp index 415b2ddb69..a9667c4343 100644 --- a/test/api/annotations.cpp +++ b/test/api/annotations.cpp @@ -75,6 +75,21 @@ TEST(Annotations, FillAnnotation) { util::write_file("test/output/fill_annotation.png", renderPNG(map)); } +TEST(Annotations, StyleSourcedShapeAnnotation) { + auto display = std::make_shared<mbgl::HeadlessDisplay>(); + HeadlessView view(display, 1); + DefaultFileSource fileSource(nullptr); + + Map map(view, fileSource, MapMode::Still); + map.setStyleJSON(util::read_file("test/fixtures/api/annotation.json"), ""); + + AnnotationSegments segments = {{ {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }}; + + map.addShapeAnnotation(ShapeAnnotation(segments, "annotation")); + + util::write_file("test/output/style_sourced_shape_annotation.png", renderPNG(map)); +} + TEST(Annotations, AddMultiple) { auto display = std::make_shared<mbgl::HeadlessDisplay>(); HeadlessView view(display, 1); diff --git a/test/fixtures/api/annotation.json b/test/fixtures/api/annotation.json new file mode 100644 index 0000000000..75fcfca41f --- /dev/null +++ b/test/fixtures/api/annotation.json @@ -0,0 +1,19 @@ +{ + "version": 8, + "sources": { + "fake": { + "type": "vector", + "url": "asset://TEST_DATA/fixtures/tiles/streets.json" + } + }, + "layers": [{ + "id": "annotation", + "type": "fill", + "source": "fake", + "source-layer": "fake", + "paint": { + "fill-color": "rgba(255,0,0,1)" + } + }], + "sprite": "asset://TEST_DATA/fixtures/resources/sprite" +} |