From 7ddca3b6116903bae9ecde1d49d29a8f1fedcec3 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Wed, 12 Apr 2017 12:31:51 +0300 Subject: [PATCH] [core] account for property functions in query rendered features --- mapbox-gl-js | 2 +- src/mbgl/geometry/feature_index.cpp | 45 ++++++++++++++++--- src/mbgl/geometry/feature_index.hpp | 4 +- src/mbgl/renderer/bucket.hpp | 6 +++ src/mbgl/renderer/circle_bucket.cpp | 23 ++++++++++ src/mbgl/renderer/circle_bucket.hpp | 2 + src/mbgl/renderer/fill_bucket.cpp | 11 +++++ src/mbgl/renderer/fill_bucket.hpp | 2 + src/mbgl/renderer/line_bucket.cpp | 35 +++++++++++++++ src/mbgl/renderer/line_bucket.hpp | 5 +++ src/mbgl/style/layer_impl.hpp | 6 +-- src/mbgl/style/layers/circle_layer_impl.cpp | 21 +++++---- src/mbgl/style/layers/circle_layer_impl.hpp | 12 ++--- src/mbgl/style/layers/fill_layer_impl.cpp | 12 ++--- src/mbgl/style/layers/fill_layer_impl.hpp | 12 ++--- src/mbgl/style/layers/line_layer_impl.cpp | 31 ++++++------- src/mbgl/style/layers/line_layer_impl.hpp | 14 +++--- .../possibly_evaluated_property_value.hpp | 15 ++++++- src/mbgl/style/style.cpp | 12 ----- src/mbgl/style/style.hpp | 2 - src/mbgl/tile/geometry_tile.cpp | 3 +- 21 files changed, 195 insertions(+), 80 deletions(-) diff --git a/mapbox-gl-js b/mapbox-gl-js index 1bc8caa7c64..cfb4525fc9c 160000 --- a/mapbox-gl-js +++ b/mapbox-gl-js @@ -1 +1 @@ -Subproject commit 1bc8caa7c647d89200b974374b4476cef937aa0c +Subproject commit cfb4525fc9cdb5e4f9ec49f8d503cea88017d5a9 diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp index 0a159f2ce23..6fae5fe9a12 100644 --- a/src/mbgl/geometry/feature_index.cpp +++ b/src/mbgl/geometry/feature_index.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -53,6 +54,36 @@ static bool topDownSymbols(const IndexedSubfeature& a, const IndexedSubfeature& return a.sortIndex < b.sortIndex; } +static int16_t getAdditionalQueryRadius(const RenderedQueryOptions& queryOptions, + const style::Style& style, + const GeometryTile& tile, + const float pixelsToTileUnits) { + + // Determine the additional radius needed factoring in property functions + float additionalRadius = 0; + auto getQueryRadius = [&](const style::Layer& layer) { + auto bucket = tile.getBucket(layer); + if (bucket) { + additionalRadius = std::max(additionalRadius, bucket->getQueryRadius(layer) * pixelsToTileUnits); + } + }; + + if (queryOptions.layerIDs) { + for (const auto& layerID : *queryOptions.layerIDs) { + style::Layer* layer = style.getLayer(layerID); + if (layer) { + getQueryRadius(*layer); + } + } + } else { + for (const style::Layer* layer : style.getLayers()) { + getQueryRadius(*layer); + } + } + + return std::min(util::EXTENT, additionalRadius); +} + void FeatureIndex::query( std::unordered_map>& result, const GeometryCoordinates& queryGeometry, @@ -63,14 +94,18 @@ void FeatureIndex::query( const GeometryTileData& geometryTileData, const CanonicalTileID& tileID, const style::Style& style, - const CollisionTile* collisionTile) const { - - mapbox::geometry::box box = mapbox::geometry::envelope(queryGeometry); + const CollisionTile* collisionTile, + const GeometryTile& tile) const { + // Determine query radius const float pixelsToTileUnits = util::EXTENT / tileSize / scale; - const int16_t additionalRadius = std::min(util::EXTENT, std::ceil(style.getQueryRadius() * pixelsToTileUnits)); + const int16_t additionalRadius = getAdditionalQueryRadius(queryOptions, style, tile, pixelsToTileUnits); + + // Query the grid index + mapbox::geometry::box box = mapbox::geometry::envelope(queryGeometry); std::vector features = grid.query({ box.min - additionalRadius, box.max + additionalRadius }); + std::sort(features.begin(), features.end(), topDown); size_t previousSortIndex = std::numeric_limits::max(); for (const auto& indexedFeature : features) { @@ -124,7 +159,7 @@ void FeatureIndex::addFeature( auto styleLayer = style.getLayer(layerID); if (!styleLayer || (!styleLayer->is() && - !styleLayer->baseImpl->queryIntersectsGeometry(queryGeometry, geometryTileFeature->getGeometries(), bearing, pixelsToTileUnits))) { + !styleLayer->baseImpl->queryIntersectsFeature(queryGeometry, *geometryTileFeature, tileID.z, bearing, pixelsToTileUnits))) { continue; } diff --git a/src/mbgl/geometry/feature_index.hpp b/src/mbgl/geometry/feature_index.hpp index 61f0bad4d5e..f7aa0182e43 100644 --- a/src/mbgl/geometry/feature_index.hpp +++ b/src/mbgl/geometry/feature_index.hpp @@ -11,6 +11,7 @@ namespace mbgl { +class GeometryTile; class RenderedQueryOptions; namespace style { @@ -45,7 +46,8 @@ class FeatureIndex { const GeometryTileData&, const CanonicalTileID&, const style::Style&, - const CollisionTile*) const; + const CollisionTile*, + const GeometryTile& tile) const; static optional translateQueryGeometry( const GeometryCoordinates& queryGeometry, diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp index 294e50dd8c8..84ecabe6326 100644 --- a/src/mbgl/renderer/bucket.hpp +++ b/src/mbgl/renderer/bucket.hpp @@ -5,6 +5,8 @@ #include #include +#include +#include namespace mbgl { @@ -38,6 +40,10 @@ class Bucket : private util::noncopyable { virtual bool hasData() const = 0; + virtual float getQueryRadius(const style::Layer&) const { + return 0; + }; + bool needsUpload() const { return !uploaded; } diff --git a/src/mbgl/renderer/circle_bucket.cpp b/src/mbgl/renderer/circle_bucket.cpp index e437eff1358..94529a66d8c 100644 --- a/src/mbgl/renderer/circle_bucket.cpp +++ b/src/mbgl/renderer/circle_bucket.cpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace mbgl { @@ -97,4 +98,26 @@ void CircleBucket::addFeature(const GeometryTileFeature& feature, } } +template +static float get(const CircleLayer& layer, const std::map& paintPropertyBinders) { + auto it = paintPropertyBinders.find(layer.getID()); + if (it == paintPropertyBinders.end() || !it->second.statistics().max()) { + return layer.impl->paint.evaluated.get().constantOr(Property::defaultValue()); + } else { + return *it->second.statistics().max(); + } +} + +float CircleBucket::getQueryRadius(const style::Layer& layer) const { + if (!layer.is()) { + return 0; + } + + auto circleLayer = layer.as(); + + float radius = get(*circleLayer, paintPropertyBinders); + auto translate = circleLayer->impl->paint.evaluated.get(); + return radius + util::length(translate[0], translate[1]); +} + } // namespace mbgl diff --git a/src/mbgl/renderer/circle_bucket.hpp b/src/mbgl/renderer/circle_bucket.hpp index da12dcdecd6..02f60ad2ba3 100644 --- a/src/mbgl/renderer/circle_bucket.hpp +++ b/src/mbgl/renderer/circle_bucket.hpp @@ -26,6 +26,8 @@ class CircleBucket : public Bucket { void upload(gl::Context&) override; void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override; + float getQueryRadius(const style::Layer&) const override; + gl::VertexVector vertices; gl::IndexVector triangles; gl::SegmentVector segments; diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/fill_bucket.cpp index d5664616736..53bf825d488 100644 --- a/src/mbgl/renderer/fill_bucket.cpp +++ b/src/mbgl/renderer/fill_bucket.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -131,4 +132,14 @@ bool FillBucket::hasData() const { return !triangleSegments.empty() || !lineSegments.empty(); } +float FillBucket::getQueryRadius(const style::Layer& layer) const { + if (!layer.is()) { + return 0; + } + + const std::array& translate = layer.as()->impl->paint.evaluated.get(); + return util::length(translate[0], translate[1]); + +} + } // namespace mbgl diff --git a/src/mbgl/renderer/fill_bucket.hpp b/src/mbgl/renderer/fill_bucket.hpp index f505f313d17..e96cd2ac5e9 100644 --- a/src/mbgl/renderer/fill_bucket.hpp +++ b/src/mbgl/renderer/fill_bucket.hpp @@ -27,6 +27,8 @@ class FillBucket : public Bucket { void upload(gl::Context&) override; void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override; + float getQueryRadius(const style::Layer&) const override; + gl::VertexVector vertices; gl::IndexVector lines; gl::IndexVector triangles; diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp index 13caea4539b..b12bfebf884 100644 --- a/src/mbgl/renderer/line_bucket.cpp +++ b/src/mbgl/renderer/line_bucket.cpp @@ -460,4 +460,39 @@ bool LineBucket::hasData() const { return !segments.empty(); } +template +static float get(const LineLayer& layer, const std::map& paintPropertyBinders) { + auto it = paintPropertyBinders.find(layer.getID()); + if (it == paintPropertyBinders.end() || !it->second.statistics().max()) { + return layer.impl->paint.evaluated.get().constantOr(Property::defaultValue()); + } else { + return *it->second.statistics().max(); + } +} + +float LineBucket::getLineWidth(const style::LineLayer& layer) const { + float lineWidth = layer.impl->paint.evaluated.get(); + float gapWidth = get(layer, paintPropertyBinders); + + if (gapWidth) { + return gapWidth + 2 * lineWidth; + } else { + return lineWidth; + } +} + +float LineBucket::getQueryRadius(const style::Layer& layer) const { + if (!layer.is()) { + return 0; + } + + auto lineLayer = layer.as(); + auto paint = lineLayer->impl->paint; + + const std::array& translate = paint.evaluated.get(); + float offset = get(*lineLayer, paintPropertyBinders); + return getLineWidth(*lineLayer) / 2.0 + std::abs(offset) + util::length(translate[0], translate[1]); +} + + } // namespace mbgl diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/line_bucket.hpp index 5a126ba18ee..30198305ad9 100644 --- a/src/mbgl/renderer/line_bucket.hpp +++ b/src/mbgl/renderer/line_bucket.hpp @@ -14,6 +14,7 @@ namespace mbgl { namespace style { class BucketParameters; +class LineLayer; } // namespace style class LineBucket : public Bucket { @@ -29,6 +30,8 @@ class LineBucket : public Bucket { void upload(gl::Context&) override; void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override; + float getQueryRadius(const style::Layer&) const override; + style::LineLayoutProperties::PossiblyEvaluated layout; gl::VertexVector vertices; @@ -59,6 +62,8 @@ class LineBucket : public Bucket { std::ptrdiff_t e3; const uint32_t overscaling; + + float getLineWidth(const style::LineLayer& layer) const; }; } // namespace mbgl diff --git a/src/mbgl/style/layer_impl.hpp b/src/mbgl/style/layer_impl.hpp index 9b2bfe4d2ca..5179192c94f 100644 --- a/src/mbgl/style/layer_impl.hpp +++ b/src/mbgl/style/layer_impl.hpp @@ -69,10 +69,10 @@ class Layer::Impl { // Checks whether this layer can be rendered. bool needsRendering(float zoom) const; - virtual float getQueryRadius() const { return 0; } - virtual bool queryIntersectsGeometry( + virtual bool queryIntersectsFeature( const GeometryCoordinates&, - const GeometryCollection&, + const GeometryTileFeature&, + const float, const float, const float) const { return false; }; diff --git a/src/mbgl/style/layers/circle_layer_impl.cpp b/src/mbgl/style/layers/circle_layer_impl.cpp index ea1d4eeb650..2dde632f6e7 100644 --- a/src/mbgl/style/layers/circle_layer_impl.cpp +++ b/src/mbgl/style/layers/circle_layer_impl.cpp @@ -29,25 +29,24 @@ std::unique_ptr CircleLayer::Impl::createBucket(const BucketParameters& return std::make_unique(parameters, layers); } -float CircleLayer::Impl::getQueryRadius() const { - const std::array& translate = paint.evaluated.get(); - return paint.evaluated.get().constantOr(CircleRadius::defaultValue()) - + util::length(translate[0], translate[1]); -} - -bool CircleLayer::Impl::queryIntersectsGeometry( +bool CircleLayer::Impl::queryIntersectsFeature( const GeometryCoordinates& queryGeometry, - const GeometryCollection& geometry, + const GeometryTileFeature& feature, + const float zoom, const float bearing, const float pixelsToTileUnits) const { + // Translate query geometry auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry( queryGeometry, paint.evaluated.get(), paint.evaluated.get(), bearing, pixelsToTileUnits); - auto circleRadius = paint.evaluated.get().constantOr(CircleRadius::defaultValue()) * pixelsToTileUnits; + // Evaluate function + auto circleRadius = paint.evaluated.get() + .evaluate(feature, zoom, CircleRadius::defaultValue()) + * pixelsToTileUnits; - return util::polygonIntersectsBufferedMultiPoint( - translatedQueryGeometry.value_or(queryGeometry), geometry, circleRadius); + // Test intersection + return util::polygonIntersectsBufferedMultiPoint(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries(), circleRadius); } } // namespace style diff --git a/src/mbgl/style/layers/circle_layer_impl.hpp b/src/mbgl/style/layers/circle_layer_impl.hpp index 0f9611d589b..2e3f37e1f93 100644 --- a/src/mbgl/style/layers/circle_layer_impl.hpp +++ b/src/mbgl/style/layers/circle_layer_impl.hpp @@ -18,12 +18,12 @@ class CircleLayer::Impl : public Layer::Impl { std::unique_ptr createBucket(const BucketParameters&, const std::vector&) const override; - float getQueryRadius() const override; - bool queryIntersectsGeometry( - const GeometryCoordinates& queryGeometry, - const GeometryCollection& geometry, - const float bearing, - const float pixelsToTileUnits) const override; + bool queryIntersectsFeature( + const GeometryCoordinates&, + const GeometryTileFeature&, + const float, + const float, + const float) const override; CirclePaintProperties paint; }; diff --git a/src/mbgl/style/layers/fill_layer_impl.cpp b/src/mbgl/style/layers/fill_layer_impl.cpp index c7c89f8c20d..19675ca9fb9 100644 --- a/src/mbgl/style/layers/fill_layer_impl.cpp +++ b/src/mbgl/style/layers/fill_layer_impl.cpp @@ -39,21 +39,17 @@ std::unique_ptr FillLayer::Impl::createBucket(const BucketParameters& pa return std::make_unique(parameters, layers); } -float FillLayer::Impl::getQueryRadius() const { - const std::array& translate = paint.evaluated.get(); - return util::length(translate[0], translate[1]); -} - -bool FillLayer::Impl::queryIntersectsGeometry( +bool FillLayer::Impl::queryIntersectsFeature( const GeometryCoordinates& queryGeometry, - const GeometryCollection& geometry, + const GeometryTileFeature& feature, + const float, const float bearing, const float pixelsToTileUnits) const { auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry( queryGeometry, paint.evaluated.get(), paint.evaluated.get(), bearing, pixelsToTileUnits); - return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), geometry); + return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries()); } } // namespace style diff --git a/src/mbgl/style/layers/fill_layer_impl.hpp b/src/mbgl/style/layers/fill_layer_impl.hpp index bd25a8bebf1..712cb0a6e02 100644 --- a/src/mbgl/style/layers/fill_layer_impl.hpp +++ b/src/mbgl/style/layers/fill_layer_impl.hpp @@ -18,12 +18,12 @@ class FillLayer::Impl : public Layer::Impl { std::unique_ptr createBucket(const BucketParameters&, const std::vector&) const override; - float getQueryRadius() const override; - bool queryIntersectsGeometry( - const GeometryCoordinates& queryGeometry, - const GeometryCollection& geometry, - const float bearing, - const float pixelsToTileUnits) const override; + bool queryIntersectsFeature( + const GeometryCoordinates&, + const GeometryTileFeature&, + const float, + const float, + const float) const override; FillPaintProperties paint; }; diff --git a/src/mbgl/style/layers/line_layer_impl.cpp b/src/mbgl/style/layers/line_layer_impl.cpp index ef0131e3d57..d2832929144 100644 --- a/src/mbgl/style/layers/line_layer_impl.cpp +++ b/src/mbgl/style/layers/line_layer_impl.cpp @@ -32,9 +32,10 @@ std::unique_ptr LineLayer::Impl::createBucket(const BucketParameters& pa return std::make_unique(parameters, layers, layout); } -float LineLayer::Impl::getLineWidth() const { +float LineLayer::Impl::getLineWidth(const GeometryTileFeature& feature, const float zoom) const { float lineWidth = paint.evaluated.get(); - float gapWidth = paint.evaluated.get().constantOr(0); + float gapWidth = paint.evaluated.get() + .evaluate(feature, zoom, LineGapWidth::defaultValue()); if (gapWidth) { return gapWidth + 2 * lineWidth; } else { @@ -72,29 +73,29 @@ optional offsetLine(const GeometryCollection& rings, const d return newRings; } -float LineLayer::Impl::getQueryRadius() const { - const std::array& translate = paint.evaluated.get(); - auto offset = paint.evaluated.get().constantOr(LineOffset::defaultValue()); - return getLineWidth() / 2.0 + std::abs(offset) + util::length(translate[0], translate[1]); -} - -bool LineLayer::Impl::queryIntersectsGeometry( +bool LineLayer::Impl::queryIntersectsFeature( const GeometryCoordinates& queryGeometry, - const GeometryCollection& geometry, + const GeometryTileFeature& feature, + const float zoom, const float bearing, const float pixelsToTileUnits) const { - const float halfWidth = getLineWidth() / 2.0 * pixelsToTileUnits; - + // Translate query geometry auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry( queryGeometry, paint.evaluated.get(), paint.evaluated.get(), bearing, pixelsToTileUnits); - auto offset = paint.evaluated.get().constantOr(LineOffset::defaultValue()); - auto offsetGeometry = offsetLine(geometry, offset * pixelsToTileUnits); + // Evaluate function + auto offset = paint.evaluated.get().evaluate(feature, zoom, LineOffset::defaultValue()) * pixelsToTileUnits; + + // Apply offset to geometry + auto offsetGeometry = offsetLine(feature.getGeometries(), offset); + + // Test intersection + const float halfWidth = getLineWidth(feature, zoom) / 2.0 * pixelsToTileUnits; return util::polygonIntersectsBufferedMultiLine( translatedQueryGeometry.value_or(queryGeometry), - offsetGeometry.value_or(geometry), + offsetGeometry.value_or(feature.getGeometries()), halfWidth); } diff --git a/src/mbgl/style/layers/line_layer_impl.hpp b/src/mbgl/style/layers/line_layer_impl.hpp index 67e793f2ea7..b25ece31004 100644 --- a/src/mbgl/style/layers/line_layer_impl.hpp +++ b/src/mbgl/style/layers/line_layer_impl.hpp @@ -18,12 +18,12 @@ class LineLayer::Impl : public Layer::Impl { std::unique_ptr createBucket(const BucketParameters&, const std::vector&) const override; - float getQueryRadius() const override; - bool queryIntersectsGeometry( - const GeometryCoordinates& queryGeometry, - const GeometryCollection& geometry, - const float bearing, - const float pixelsToTileUnits) const override; + bool queryIntersectsFeature( + const GeometryCoordinates&, + const GeometryTileFeature&, + const float, + const float, + const float) const override; LineLayoutProperties layout; LinePaintProperties paint; @@ -32,7 +32,7 @@ class LineLayer::Impl : public Layer::Impl { float dashLineWidth = 1; private: - float getLineWidth() const; + float getLineWidth(const GeometryTileFeature&, const float) const; }; } // namespace style diff --git a/src/mbgl/style/possibly_evaluated_property_value.hpp b/src/mbgl/style/possibly_evaluated_property_value.hpp index 8c3f1780a62..9cb5f6e81be 100644 --- a/src/mbgl/style/possibly_evaluated_property_value.hpp +++ b/src/mbgl/style/possibly_evaluated_property_value.hpp @@ -7,8 +7,6 @@ namespace mbgl { -class GeometryTileFeature; - namespace style { template @@ -43,6 +41,19 @@ class PossiblyEvaluatedPropertyValue { auto match(Ts&&... ts) const { return value.match(std::forward(ts)...); } + + template + T evaluate(const Feature& feature, float zoom, T defaultValue) const { + return this->match( + [&] (const T& constant) { return constant; }, + [&] (const SourceFunction& function) { + return function.evaluate(feature, defaultValue); + }, + [&] (const CompositeFunction& function) { + return function.evaluate(zoom, feature, defaultValue); + } + ); + } }; } // namespace style diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index 4c3ea207f53..1e187093914 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -541,18 +541,6 @@ std::vector Style::queryRenderedFeatures(const ScreenLineString& geomet return result; } -float Style::getQueryRadius() const { - float additionalRadius = 0; - for (auto& layer : layers) { - if (!layer->baseImpl->needsRendering(zoomHistory.lastZoom)) { - continue; - } - additionalRadius = util::max(additionalRadius, layer->baseImpl->getQueryRadius()); - } - return additionalRadius; -} - - void Style::setSourceTileCacheSize(size_t size) { for (const auto& source : sources) { source->baseImpl->setCacheSize(size); diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index 817cab5fd58..50c91b80508 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -101,8 +101,6 @@ class Style : public GlyphAtlasObserver, const TransformState& transformState, const RenderedQueryOptions& options) const; - float getQueryRadius() const; - void setSourceTileCacheSize(size_t); void onLowMemory(); diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 83554ce76ac..c9ed46a529f 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -186,7 +186,8 @@ void GeometryTile::queryRenderedFeatures( *data, id.canonical, style, - collisionTile.get()); + collisionTile.get(), + *this); } void GeometryTile::querySourceFeatures(