From 5b3ebc4a2429c202f08c7468c300950de4844615 Mon Sep 17 00:00:00 2001 From: Lucas Wojciechowski Date: Thu, 8 Mar 2018 15:48:08 -0800 Subject: [core] Add expression filter support (#11251) * WIP * WIP * WIP * Remove Filter::operator()(const Feature&) * WIP * WIP * WIP * WIP * Hook up expression filter evaluator * Replace `shared_ptr` with &reference * Fill in implementation of `void operator()(const ExpressionFilter&)` * Fix failing tests * Switch back to a shared_ptr per chat with @anandthakker * Fix benchmark compilation * Shot in the dark to fix CI * Shot in the dark to fix CI (part 2) * Shot in the dark to fix CI (part 3) * In src/mbgl/style/conversion/filter.cpp, add a port of isExpressionFilter and use it to decide in Converter::operator() whether to parse the incoming JSON as an ExpressionFilter or one of the legacy filter types * Remove bool Filter::operator()(const GeometryTileFeature&) const * Ensure the map zoom is passed into filtering operations wherever applicable * Add expression filter tests * Addressed PR feedback * Implement `NSPredicate *operator()(mbgl::style::ExpressionFilter filter)` * Fix formatting& nit --- src/mbgl/geometry/feature_index.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/mbgl/geometry/feature_index.cpp') diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp index 3b5e12b54a..6fb0d5e446 100644 --- a/src/mbgl/geometry/feature_index.cpp +++ b/src/mbgl/geometry/feature_index.cpp @@ -125,7 +125,7 @@ void FeatureIndex::addFeature( continue; } - if (options.filter && !(*options.filter)(*geometryTileFeature)) { + if (options.filter && !(*options.filter)(style::expression::EvaluationContext { static_cast(tileID.z), geometryTileFeature.get() })) { continue; } -- cgit v1.2.1 From a62745edf9ee2da1f6ebda07acfd8260f3696e50 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Wed, 18 Apr 2018 16:33:37 -0700 Subject: Port global symbol query from GL JS: - Symbol querying is now global instead of per-tile - Symbols that bleed over tile boundaries no longer missed in queries - Symbol results now sorted based on rendering order (ie overlapping symbols change their sort order when a bearing change causes their render order to change) - Placement::retainedQueryData now responsible for maintaining symbol querying data for buckets that may no longer be in the TilePyramid. --- src/mbgl/geometry/feature_index.cpp | 58 ++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 17 deletions(-) (limited to 'src/mbgl/geometry/feature_index.cpp') diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp index c67786274a..8ea6259129 100644 --- a/src/mbgl/geometry/feature_index.cpp +++ b/src/mbgl/geometry/feature_index.cpp @@ -33,14 +33,6 @@ void FeatureIndex::insert(const GeometryCollection& geometries, } } -static bool topDown(const IndexedSubfeature& a, const IndexedSubfeature& b) { - return a.sortIndex > b.sortIndex; -} - -static bool topDownSymbols(const IndexedSubfeature& a, const IndexedSubfeature& b) { - return a.sortIndex < b.sortIndex; -} - void FeatureIndex::query( std::unordered_map>& result, const GeometryCoordinates& queryGeometry, @@ -49,9 +41,7 @@ void FeatureIndex::query( const double scale, const RenderedQueryOptions& queryOptions, const UnwrappedTileID& tileID, - const std::string& sourceID, const std::vector& layers, - const CollisionIndex& collisionIndex, const float additionalQueryRadius) const { if (!tileData) { @@ -68,7 +58,9 @@ void FeatureIndex::query( convertPoint(box.max + additionalRadius) }); - std::sort(features.begin(), features.end(), topDown); + std::sort(features.begin(), features.end(), [](const IndexedSubfeature& a, const IndexedSubfeature& b) { + return a.sortIndex > b.sortIndex; + }); size_t previousSortIndex = std::numeric_limits::max(); for (const auto& indexedFeature : features) { @@ -76,23 +68,55 @@ void FeatureIndex::query( if (indexedFeature.sortIndex == previousSortIndex) continue; previousSortIndex = indexedFeature.sortIndex; - addFeature(result, indexedFeature, queryGeometry, queryOptions, tileID.canonical, layers, bearing, pixelsToTileUnits); + addFeature(result, indexedFeature, queryOptions, tileID.canonical, layers, queryGeometry, bearing, pixelsToTileUnits); } +} + +std::unordered_map> FeatureIndex::lookupSymbolFeatures(const std::vector& symbolFeatures, + const RenderedQueryOptions& queryOptions, + const std::vector& layers, + const OverscaledTileID& tileID, + const std::shared_ptr>& featureSortOrder) const { + std::unordered_map> result; + if (!tileData) { + return result; + } + std::vector sortedFeatures(symbolFeatures.begin(), symbolFeatures.end()); + + std::sort(sortedFeatures.begin(), sortedFeatures.end(), [featureSortOrder](const IndexedSubfeature& a, const IndexedSubfeature& b) { + // Same idea as the non-symbol sort order, but symbol features may have changed their sort order + // since their corresponding IndexedSubfeature was added to the CollisionIndex + // The 'featureSortOrder' is relatively inefficient for querying but cheap to build on every bucket sort + if (featureSortOrder) { + // queryRenderedSymbols documentation says we'll return features in + // "top-to-bottom" rendering order (aka last-to-first). + // Actually there can be multiple symbol instances per feature, so + // we sort each feature based on the first matching symbol instance. + auto sortedA = std::find(featureSortOrder->begin(), featureSortOrder->end(), a.index); + auto sortedB = std::find(featureSortOrder->begin(), featureSortOrder->end(), b.index); + assert(sortedA != featureSortOrder->end()); + assert(sortedB != featureSortOrder->end()); + return sortedA > sortedB; + } else { + // Bucket hasn't been re-sorted based on angle, so use same "reverse of appearance in source data" + // logic as non-symboles + return a.sortIndex > b.sortIndex; + } + }); - std::vector symbolFeatures = collisionIndex.queryRenderedSymbols(queryGeometry, tileID, sourceID); - std::sort(symbolFeatures.begin(), symbolFeatures.end(), topDownSymbols); - for (const auto& symbolFeature : symbolFeatures) { - addFeature(result, symbolFeature, queryGeometry, queryOptions, tileID.canonical, layers, bearing, pixelsToTileUnits); + for (const auto& symbolFeature : sortedFeatures) { + addFeature(result, symbolFeature, queryOptions, tileID.canonical, layers, GeometryCoordinates(), 0, 0); } + return result; } void FeatureIndex::addFeature( std::unordered_map>& result, const IndexedSubfeature& indexedFeature, - const GeometryCoordinates& queryGeometry, const RenderedQueryOptions& options, const CanonicalTileID& tileID, const std::vector& layers, + const GeometryCoordinates& queryGeometry, const float bearing, const float pixelsToTileUnits) const { -- cgit v1.2.1 From f7d20a587199ccee42469ecea2299ae73bfaae49 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Mon, 2 Apr 2018 17:41:09 -0700 Subject: [core] fix querying circles across tile boundaries --- src/mbgl/geometry/feature_index.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/mbgl/geometry/feature_index.cpp') diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp index 8ea6259129..728996a2eb 100644 --- a/src/mbgl/geometry/feature_index.cpp +++ b/src/mbgl/geometry/feature_index.cpp @@ -42,7 +42,7 @@ void FeatureIndex::query( const RenderedQueryOptions& queryOptions, const UnwrappedTileID& tileID, const std::vector& layers, - const float additionalQueryRadius) const { + const float additionalQueryPadding) const { if (!tileData) { return; @@ -50,12 +50,12 @@ void FeatureIndex::query( // Determine query radius const float pixelsToTileUnits = util::EXTENT / tileSize / scale; - const int16_t additionalRadius = std::min(util::EXTENT, additionalQueryRadius * pixelsToTileUnits); + const int16_t additionalPadding = std::min(util::EXTENT, additionalQueryPadding * pixelsToTileUnits); // Query the grid index mapbox::geometry::box box = mapbox::geometry::envelope(queryGeometry); - std::vector features = grid.query({ convertPoint(box.min - additionalRadius), - convertPoint(box.max + additionalRadius) }); + std::vector features = grid.query({ convertPoint(box.min - additionalPadding), + convertPoint(box.max + additionalPadding) }); std::sort(features.begin(), features.end(), [](const IndexedSubfeature& a, const IndexedSubfeature& b) { -- cgit v1.2.1 From f86fe44dbd4de44c9fc8cb364521f966039289d7 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Mon, 2 Apr 2018 17:41:55 -0700 Subject: [core] fix circle querying for scale and alignment This fixes circle querying for cases where either circle-pitch-alignment=map or circle-pitch-scaling=viewport --- src/mbgl/geometry/feature_index.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src/mbgl/geometry/feature_index.cpp') diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp index 728996a2eb..e7759b0868 100644 --- a/src/mbgl/geometry/feature_index.cpp +++ b/src/mbgl/geometry/feature_index.cpp @@ -36,7 +36,8 @@ void FeatureIndex::insert(const GeometryCollection& geometries, void FeatureIndex::query( std::unordered_map>& result, const GeometryCoordinates& queryGeometry, - const float bearing, + const TransformState& transformState, + const mat4& posMatrix, const double tileSize, const double scale, const RenderedQueryOptions& queryOptions, @@ -68,7 +69,7 @@ void FeatureIndex::query( if (indexedFeature.sortIndex == previousSortIndex) continue; previousSortIndex = indexedFeature.sortIndex; - addFeature(result, indexedFeature, queryOptions, tileID.canonical, layers, queryGeometry, bearing, pixelsToTileUnits); + addFeature(result, indexedFeature, queryOptions, tileID.canonical, layers, queryGeometry, transformState, pixelsToTileUnits, posMatrix); } } @@ -105,7 +106,7 @@ std::unordered_map> FeatureIndex::lookupSymbol }); for (const auto& symbolFeature : sortedFeatures) { - addFeature(result, symbolFeature, queryOptions, tileID.canonical, layers, GeometryCoordinates(), 0, 0); + addFeature(result, symbolFeature, queryOptions, tileID.canonical, layers, GeometryCoordinates(), {}, 0, {}); } return result; } @@ -117,8 +118,9 @@ void FeatureIndex::addFeature( const CanonicalTileID& tileID, const std::vector& layers, const GeometryCoordinates& queryGeometry, - const float bearing, - const float pixelsToTileUnits) const { + const TransformState& transformState, + const float pixelsToTileUnits, + const mat4& posMatrix) const { auto getRenderLayer = [&] (const std::string& layerID) -> const RenderLayer* { for (const auto& layer : layers) { @@ -148,7 +150,7 @@ void FeatureIndex::addFeature( } if (!renderLayer->is() && - !renderLayer->queryIntersectsFeature(queryGeometry, *geometryTileFeature, tileID.z, bearing, pixelsToTileUnits)) { + !renderLayer->queryIntersectsFeature(queryGeometry, *geometryTileFeature, tileID.z, transformState, pixelsToTileUnits, posMatrix)) { continue; } -- cgit v1.2.1 From 0ca53ea5a83efcc44abbf1c2a4b3001001e6d14e Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 30 Mar 2018 16:28:05 -0400 Subject: [core] only index features within tile boundaries Previously we relied on tile buffers for querying features who's rendered representations cross tile boundaries. Now we query multiple tiles making it unnecessary to index features that are completely outside a tile's boundaries. --- src/mbgl/geometry/feature_index.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/mbgl/geometry/feature_index.cpp') diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp index e7759b0868..520fd313a2 100644 --- a/src/mbgl/geometry/feature_index.cpp +++ b/src/mbgl/geometry/feature_index.cpp @@ -28,8 +28,13 @@ void FeatureIndex::insert(const GeometryCollection& geometries, const std::string& bucketName) { for (const auto& ring : geometries) { auto envelope = mapbox::geometry::envelope(ring); - grid.insert(IndexedSubfeature(index, sourceLayerName, bucketName, sortIndex++), - {convertPoint(envelope.min), convertPoint(envelope.max)}); + if (envelope.min.x < util::EXTENT && + envelope.min.y < util::EXTENT && + envelope.max.x >= 0 && + envelope.max.y >= 0) { + grid.insert(IndexedSubfeature(index, sourceLayerName, bucketName, sortIndex++), + {convertPoint(envelope.min), convertPoint(envelope.max)}); + } } } @@ -106,7 +111,8 @@ std::unordered_map> FeatureIndex::lookupSymbol }); for (const auto& symbolFeature : sortedFeatures) { - addFeature(result, symbolFeature, queryOptions, tileID.canonical, layers, GeometryCoordinates(), {}, 0, {}); + mat4 unusedMatrix; + addFeature(result, symbolFeature, queryOptions, tileID.canonical, layers, GeometryCoordinates(), {}, 0, unusedMatrix); } return result; } -- cgit v1.2.1 From 27b21363e62c105db0b040b4c5a5ef31170ebd30 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Fri, 27 Apr 2018 17:18:29 -0700 Subject: [core] Only run placement for first layer per SymbolBucket Native version of mapbox/mapbox-gl-js#6548. Port of mapbox/mapbox-gl-js#6550. Prevents symbols that share the same layout properties from colliding against each other. Bump GL JS pin to get regression test. Rename "bucketName" -> "bucketLeaderID" to make it clearer what it represents. --- src/mbgl/geometry/feature_index.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/mbgl/geometry/feature_index.cpp') diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp index 520fd313a2..fdd9558d0b 100644 --- a/src/mbgl/geometry/feature_index.cpp +++ b/src/mbgl/geometry/feature_index.cpp @@ -25,14 +25,14 @@ FeatureIndex::FeatureIndex(std::unique_ptr tileData_) void FeatureIndex::insert(const GeometryCollection& geometries, std::size_t index, const std::string& sourceLayerName, - const std::string& bucketName) { + const std::string& bucketLeaderID) { for (const auto& ring : geometries) { auto envelope = mapbox::geometry::envelope(ring); if (envelope.min.x < util::EXTENT && envelope.min.y < util::EXTENT && envelope.max.x >= 0 && envelope.max.y >= 0) { - grid.insert(IndexedSubfeature(index, sourceLayerName, bucketName, sortIndex++), + grid.insert(IndexedSubfeature(index, sourceLayerName, bucketLeaderID, sortIndex++), {convertPoint(envelope.min), convertPoint(envelope.max)}); } } @@ -141,7 +141,7 @@ void FeatureIndex::addFeature( std::unique_ptr sourceLayer; std::unique_ptr geometryTileFeature; - for (const std::string& layerID : bucketLayerIDs.at(indexedFeature.bucketName)) { + for (const std::string& layerID : bucketLayerIDs.at(indexedFeature.bucketLeaderID)) { const RenderLayer* renderLayer = getRenderLayer(layerID); if (!renderLayer) { continue; @@ -190,8 +190,8 @@ optional FeatureIndex::translateQueryGeometry( return translated; } -void FeatureIndex::setBucketLayerIDs(const std::string& bucketName, const std::vector& layerIDs) { - bucketLayerIDs[bucketName] = layerIDs; +void FeatureIndex::setBucketLayerIDs(const std::string& bucketLeaderID, const std::vector& layerIDs) { + bucketLayerIDs[bucketLeaderID] = layerIDs; } } // namespace mbgl -- cgit v1.2.1 From a4e2c1af1fd83b22ef4ee57ab19a15616224f8b8 Mon Sep 17 00:00:00 2001 From: Lucas Wojciechowski Date: Thu, 10 May 2018 12:37:14 -0700 Subject: [core] Convert "legacy" filters directly into expressions (#11610) Ports the specialized filter-* expressions from GL JS, adding them to src/mbgl/style/expression/compound_expression.cpp --- src/mbgl/geometry/feature_index.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/mbgl/geometry/feature_index.cpp') diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp index c67786274a..57719de038 100644 --- a/src/mbgl/geometry/feature_index.cpp +++ b/src/mbgl/geometry/feature_index.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include -- cgit v1.2.1