From 0d10d2df1c6d246004e7291511f3aab7a8781d59 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Sat, 4 Mar 2017 18:44:33 -0800 Subject: [PATCH] [core] query source features --- cmake/core-files.cmake | 1 + include/mbgl/map/query.hpp | 5 +++- include/mbgl/style/query.hpp | 24 +++++++++++++++++ include/mbgl/style/source.hpp | 5 ++++ src/mbgl/style/source.cpp | 4 +++ src/mbgl/style/source_impl.cpp | 18 +++++++++++++ src/mbgl/style/source_impl.hpp | 3 +++ src/mbgl/tile/geojson_tile.cpp | 23 +++++++++++++++++ src/mbgl/tile/geojson_tile.hpp | 4 +++ src/mbgl/tile/geometry_tile.cpp | 36 +++++++++++++++++++++++++- src/mbgl/tile/geometry_tile.hpp | 10 ++++++++ src/mbgl/tile/tile.cpp | 5 ++++ src/mbgl/tile/tile.hpp | 5 ++++ test/api/query.test.cpp | 41 ++++++++++++++++++++++++++++++ test/fixtures/api/query_style.json | 9 +++++++ 15 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 include/mbgl/style/query.hpp diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index 805258471..afc45a24c 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -247,6 +247,7 @@ set(MBGL_CORE_FILES include/mbgl/style/filter_evaluator.hpp include/mbgl/style/layer.hpp include/mbgl/style/property_value.hpp + include/mbgl/style/query.hpp include/mbgl/style/source.hpp include/mbgl/style/transition_options.hpp include/mbgl/style/types.hpp diff --git a/include/mbgl/map/query.hpp b/include/mbgl/map/query.hpp index 201484cd8..827424d21 100644 --- a/include/mbgl/map/query.hpp +++ b/include/mbgl/map/query.hpp @@ -3,6 +3,9 @@ #include #include +#include +#include + namespace mbgl { /** @@ -12,7 +15,7 @@ class RenderedQueryOptions { public: /** layerIDs to include in the query */ optional> layerIDs; - + optional filter; }; diff --git a/include/mbgl/style/query.hpp b/include/mbgl/style/query.hpp new file mode 100644 index 000000000..8cb2545ab --- /dev/null +++ b/include/mbgl/style/query.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +#include +#include + +namespace mbgl { +namespace style { + +/** + * Options for query source features + */ +class SourceQueryOptions { +public: + // Required for VectorSource, ignored for GeoJSONSource + optional> sourceLayers; + + optional filter; +}; + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/source.hpp b/include/mbgl/style/source.hpp index 870c81fda..0901bb195 100644 --- a/include/mbgl/style/source.hpp +++ b/include/mbgl/style/source.hpp @@ -1,11 +1,14 @@ #pragma once +#include #include #include #include +#include #include #include +#include namespace mbgl { namespace style { @@ -52,6 +55,8 @@ public: std::unique_ptr copy(const std::string& id) const; optional getAttribution() const; + + std::vector querySourceFeatures(const SourceQueryOptions& options = {}); // Private implementation class Impl; diff --git a/src/mbgl/style/source.cpp b/src/mbgl/style/source.cpp index cfb268006..25c06024d 100644 --- a/src/mbgl/style/source.cpp +++ b/src/mbgl/style/source.cpp @@ -17,6 +17,10 @@ const std::string& Source::getID() const { optional Source::getAttribution() const { return baseImpl->getAttribution(); } + +std::vector Source::querySourceFeatures(const SourceQueryOptions& options) { + return baseImpl->querySourceFeatures(options); +} } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/source_impl.cpp b/src/mbgl/style/source_impl.cpp index f83579d0d..1f8301629 100644 --- a/src/mbgl/style/source_impl.cpp +++ b/src/mbgl/style/source_impl.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -258,6 +259,23 @@ std::unordered_map> Source::Impl::queryRendere return result; } +std::vector Source::Impl::querySourceFeatures(const SourceQueryOptions& options) { + + // Only VectorSource and GeoJSON source supported + if (type != SourceType::GeoJSON && type != SourceType::Vector) { + Log::Warning(Event::General, "Source type not supported"); + return {}; + } + + std::vector result; + + for (const auto& pair : tiles) { + pair.second->querySourceFeatures(result, options); + } + + return result; +} + void Source::Impl::setCacheSize(size_t size) { cache.setSize(size); } diff --git a/src/mbgl/style/source_impl.hpp b/src/mbgl/style/source_impl.hpp index 6e16a31e5..b9707edaa 100644 --- a/src/mbgl/style/source_impl.hpp +++ b/src/mbgl/style/source_impl.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -70,6 +71,8 @@ public: const TransformState& transformState, const RenderedQueryOptions& options) const; + std::vector querySourceFeatures(const SourceQueryOptions&); + void setCacheSize(size_t); void onLowMemory(); diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp index 85d8b7561..5a2a72f50 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -90,5 +91,27 @@ void GeoJSONTile::updateData(const mapbox::geometry::feature_collection } void GeoJSONTile::setNecessity(Necessity) {} + +void GeoJSONTile::querySourceFeatures( + std::vector& result, + const style::SourceQueryOptions& options) { + + // Ignore the sourceLayer, there is only one + auto layer = getData()->getLayer({}); + + if (layer) { + auto featureCount = layer->featureCount(); + for (std::size_t i = 0; i < featureCount; i++) { + auto feature = layer->getFeature(i); + + // Apply filter, if any + if (options.filter && !(*options.filter)(*feature)) { + continue; + } + + result.push_back(convertFeature(*feature, id.canonical)); + } + } +} } // namespace mbgl diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp index 6ddc6ea48..e1d269a9a 100644 --- a/src/mbgl/tile/geojson_tile.hpp +++ b/src/mbgl/tile/geojson_tile.hpp @@ -18,6 +18,10 @@ public: void updateData(const mapbox::geometry::feature_collection&); void setNecessity(Necessity) final; + + void querySourceFeatures( + std::vector& result, + const style::SourceQueryOptions&) override; }; } // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 01f054bdf..37787df9e 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -12,8 +12,11 @@ #include #include #include -#include #include +#include +#include +#include +#include namespace mbgl { @@ -158,4 +161,35 @@ void GeometryTile::queryRenderedFeatures( collisionTile.get()); } +void GeometryTile::querySourceFeatures( + std::vector& result, + const style::SourceQueryOptions& options) { + + // No source layers, specified, nothing to do + if (!options.sourceLayers) { + Log::Warning(Event::General, "At least one sourceLayer required"); + return; + } + + for (auto sourceLayer : *options.sourceLayers) { + // Go throught all sourceLayers, if any + // to gather all the features + auto layer = data->getLayer(sourceLayer); + + if (layer) { + auto featureCount = layer->featureCount(); + for (std::size_t i = 0; i < featureCount; i++) { + auto feature = layer->getFeature(i); + + // Apply filter, if any + if (options.filter && !(*options.filter)(*feature)) { + continue; + } + + result.push_back(convertFeature(*feature, id.canonical)); + } + } + } +} + } // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp index 538ea4fbd..cabe19346 100644 --- a/src/mbgl/tile/geometry_tile.hpp +++ b/src/mbgl/tile/geometry_tile.hpp @@ -21,6 +21,7 @@ namespace style { class Style; class Layer; class UpdateParameters; +class SourceQueryOptions; } // namespace style class GeometryTile : public Tile { @@ -46,6 +47,10 @@ public: const TransformState&, const RenderedQueryOptions& options) override; + void querySourceFeatures( + std::vector& result, + const style::SourceQueryOptions&) override; + void cancel() override; class LayoutResult { @@ -66,6 +71,11 @@ public: void onPlacement(PlacementResult); void onError(std::exception_ptr); + +protected: + const GeometryTileData* getData() { + return data.get(); + } private: const std::string sourceID; diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp index 2f347fb95..4fb8331ae 100644 --- a/src/mbgl/tile/tile.cpp +++ b/src/mbgl/tile/tile.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace mbgl { @@ -35,4 +36,8 @@ void Tile::queryRenderedFeatures( const TransformState&, const RenderedQueryOptions&) {} +void Tile::querySourceFeatures( + std::vector&, + const style::SourceQueryOptions&) {} + } // namespace mbgl diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp index b335d1a5d..613b15f36 100644 --- a/src/mbgl/tile/tile.hpp +++ b/src/mbgl/tile/tile.hpp @@ -25,6 +25,7 @@ class RenderedQueryOptions; namespace style { class Layer; +class SourceQueryOptions; } // namespace style class Tile : private util::noncopyable { @@ -58,6 +59,10 @@ public: const TransformState&, const RenderedQueryOptions& options); + virtual void querySourceFeatures( + std::vector& result, + const style::SourceQueryOptions&); + void setTriedOptional(); // Returns true when the tile source has received a first response, regardless of whether a load diff --git a/test/api/query.test.cpp b/test/api/query.test.cpp index b42046fb4..45e6b1926 100644 --- a/test/api/query.test.cpp +++ b/test/api/query.test.cpp @@ -8,6 +8,7 @@ #include #include #include +#include using namespace mbgl; using namespace mbgl::style; @@ -81,3 +82,43 @@ TEST(Query, QueryRenderedFeaturesFilter) { auto features3 = test.map.queryRenderedFeatures(zz, {{ }, { gtFilter }}); EXPECT_EQ(features3.size(), 1u); } + +TEST(Query, QuerySourceFeatures) { + QueryTest test; + + auto features1 = test.map.getSource("source3")->querySourceFeatures(); + EXPECT_EQ(features1.size(), 1u); +} + +TEST(Query, QuerySourceFeaturesOptionValidation) { + QueryTest test; + + // GeoJSONSource, doesn't require a layer id + auto features = test.map.getSource("source3")->querySourceFeatures(); + ASSERT_EQ(features.size(), 1u); + + // VectorSource, requires a layer id + features = test.map.getSource("source5")->querySourceFeatures(); + ASSERT_EQ(features.size(), 0u); + + // RasterSource, not supported + features = test.map.getSource("source6")->querySourceFeatures(); + ASSERT_EQ(features.size(), 0u); +} + +TEST(Query, QuerySourceFeaturesFilter) { + QueryTest test; + + const EqualsFilter eqFilter = { "key1", std::string("value1") }; + auto features1 = test.map.getSource("source4")->querySourceFeatures({{}, { eqFilter }}); + EXPECT_EQ(features1.size(), 1u); + + const IdentifierNotEqualsFilter idNotEqFilter = { std::string("feature1") }; + auto features2 = test.map.getSource("source4")->querySourceFeatures({{}, { idNotEqFilter }}); + EXPECT_EQ(features2.size(), 0u); + + const GreaterThanFilter gtFilter = { "key2", 1.0 }; + auto features3 = test.map.getSource("source4")->querySourceFeatures({{}, { gtFilter }}); + EXPECT_EQ(features3.size(), 1u); +} + diff --git a/test/fixtures/api/query_style.json b/test/fixtures/api/query_style.json index 4e1192177..97f1d0443 100644 --- a/test/fixtures/api/query_style.json +++ b/test/fixtures/api/query_style.json @@ -50,6 +50,15 @@ "key4": 0.5 } } + }, + "source5": { + "type": "vector", + "url": "mapbox://mapbox.mapbox-streets-v6" + }, + "source6": { + "type": "raster", + "url": "mapbox://mapbox.satellite", + "tileSize": 256 } }, "layers": [