From 33465df0002e2c61fe5c39d4aeb7a674ce0147da Mon Sep 17 00:00:00 2001 From: Gali Nelle Date: Wed, 15 Apr 2020 18:15:29 +0300 Subject: Introduce a mean to add render features in layers with no sources This change also uses the support in the LocationIndicator layer, to return a point feature when queried in correspondence of the location indicator. --- metrics/ignores/platform-linux.json | 5 +- .../location_indicator/query_test/expected.json | 16 ++++++ .../tests/location_indicator/query_test/style.json | 66 ++++++++++++++++++++++ .../query_test_miss/expected.json | 1 + .../location_indicator/query_test_miss/style.json | 66 ++++++++++++++++++++++ .../query_test_no_image/expected.json | 1 + .../query_test_no_image/style.json | 65 +++++++++++++++++++++ platform/glfw/glfw_view.cpp | 5 ++ src/mbgl/geometry/feature_index.cpp | 47 +++++++++++++++ src/mbgl/geometry/feature_index.hpp | 21 ++++++- .../layers/render_location_indicator_layer.cpp | 40 ++++++++++++- .../layers/render_location_indicator_layer.hpp | 1 + src/mbgl/renderer/render_layer.hpp | 3 + src/mbgl/renderer/render_orchestrator.cpp | 21 ++++--- 14 files changed, 346 insertions(+), 12 deletions(-) create mode 100644 metrics/tests/location_indicator/query_test/expected.json create mode 100644 metrics/tests/location_indicator/query_test/style.json create mode 100644 metrics/tests/location_indicator/query_test_miss/expected.json create mode 100644 metrics/tests/location_indicator/query_test_miss/style.json create mode 100644 metrics/tests/location_indicator/query_test_no_image/expected.json create mode 100644 metrics/tests/location_indicator/query_test_no_image/style.json diff --git a/metrics/ignores/platform-linux.json b/metrics/ignores/platform-linux.json index ec018eb805..9d3f0d491c 100644 --- a/metrics/ignores/platform-linux.json +++ b/metrics/ignores/platform-linux.json @@ -22,5 +22,8 @@ "location_indicator/tilted_texture_shift_top_right": "Would need a different baseline when ran on llvmpipe not supporting anisotropic filtering", "location_indicator/two_textures": "Would need a different baseline when ran on llvmpipe not supporting anisotropic filtering", "location_indicator/image_pixel_ratio": "Would need a different baseline when ran on llvmpipe not supporting anisotropic filtering", - "location_indicator/change_image": "Would need a different baseline when ran on llvmpipe not supporting anisotropic filtering" + "location_indicator/change_image": "Would need a different baseline when ran on llvmpipe not supporting anisotropic filtering", + "location_indicator/query_test": "Would need a different baseline when ran on llvmpipe not supporting anisotropic filtering", + "location_indicator/query_test_no_image": "Would need a different baseline when ran on llvmpipe not supporting anisotropic filtering", + "location_indicator/query_test_miss": "Would need a different baseline when ran on llvmpipe not supporting anisotropic filtering" } diff --git a/metrics/tests/location_indicator/query_test/expected.json b/metrics/tests/location_indicator/query_test/expected.json new file mode 100644 index 0000000000..3104dfe82d --- /dev/null +++ b/metrics/tests/location_indicator/query_test/expected.json @@ -0,0 +1,16 @@ +[ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + 35.693055, + 139.766707 + ] + }, + "properties": {}, + "source": "", + "sourceLayer": "puck123", + "state": {} + } +] \ No newline at end of file diff --git a/metrics/tests/location_indicator/query_test/style.json b/metrics/tests/location_indicator/query_test/style.json new file mode 100644 index 0000000000..efc09922aa --- /dev/null +++ b/metrics/tests/location_indicator/query_test/style.json @@ -0,0 +1,66 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ], + "queryGeometry": [ + 256, + 128 + ] + } + }, + "center": [ 139.766707, 35.693055 ], + "zoom": 16, + "pitch" : 60, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-indicator", + "layout" : { + "bearing-image" : "puck", + "top-image" : "puck_hat", + "shadow-image" : "puck_shadow" + }, + "paint" : { + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 0, + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image-size" : 0.26, + "top-image-size" : 0.18, + "shadow-image-size" : 0.2, + + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_indicator/query_test_miss/expected.json b/metrics/tests/location_indicator/query_test_miss/expected.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/metrics/tests/location_indicator/query_test_miss/expected.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/metrics/tests/location_indicator/query_test_miss/style.json b/metrics/tests/location_indicator/query_test_miss/style.json new file mode 100644 index 0000000000..8ff5b51c39 --- /dev/null +++ b/metrics/tests/location_indicator/query_test_miss/style.json @@ -0,0 +1,66 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ], + "queryGeometry": [ + 160, + 128 + ] + } + }, + "center": [ 139.766707, 35.693055 ], + "zoom": 16, + "pitch" : 60, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-indicator", + "layout" : { + "bearing-image" : "puck", + "top-image" : "puck_hat", + "shadow-image" : "puck_shadow" + }, + "paint" : { + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 0, + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image-size" : 0.26, + "top-image-size" : 0.18, + "shadow-image-size" : 0.2, + + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/metrics/tests/location_indicator/query_test_no_image/expected.json b/metrics/tests/location_indicator/query_test_no_image/expected.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/metrics/tests/location_indicator/query_test_no_image/expected.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/metrics/tests/location_indicator/query_test_no_image/style.json b/metrics/tests/location_indicator/query_test_no_image/style.json new file mode 100644 index 0000000000..684f5c597c --- /dev/null +++ b/metrics/tests/location_indicator/query_test_no_image/style.json @@ -0,0 +1,65 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 256, + "operations": [ + [ + "addImage", + "puck_hat", + "puck_hat.png" + ], + [ + "addImage", + "puck", + "puck.png" + ], + [ + "addImage", + "puck_shadow", + "puck_shadow.png" + ] + ], + "queryGeometry": [ + 256, + 128 + ] + } + }, + "center": [ 139.766707, 35.693055 ], + "zoom": 16, + "pitch" : 60, + "bearing" : 42, + "sources": {}, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "puck123", + "type": "location-indicator", + "layout" : { + "top-image" : "puck_hat", + "shadow-image" : "puck_shadow" + }, + "paint" : { + "bearing" : 45, + "perspective-compensation" : 1, + "image-tilt-displacement" : 0, + "location" : [ 35.693055, 139.766707, 0], + "accuracy-radius": 90.0, + "bearing-image-size" : 0.26, + "top-image-size" : 0.18, + "shadow-image-size" : 0.2, + + "accuracy-radius-color": "rgba(255,0,0,0.2)", + "accuracy-radius-border-color": "rgba(255,0,255,0.6)" + } + } + ] +} diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp index 06f435e4dd..0ff208586e 100644 --- a/platform/glfw/glfw_view.cpp +++ b/platform/glfw/glfw_view.cpp @@ -294,6 +294,11 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, case GLFW_KEY_Q: { auto result = view->rendererFrontend->getRenderer()->queryPointAnnotations({ {}, { double(view->getSize().width), double(view->getSize().height) } }); printf("visible point annotations: %lu\n", result.size()); + auto features = view->rendererFrontend->getRenderer()->queryRenderedFeatures( + mbgl::ScreenBox{{double(view->getSize().width * 0.5), double(view->getSize().height * 0.5)}, + {double(view->getSize().width * 0.5 + 1), double(view->getSize().height * 0.5 + 1)}}, + {}); + printf("Rendered features at the center of the screen: %lu\n", features.size()); } break; case GLFW_KEY_P: view->pauseResumeCallback(); diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp index 623b661695..85a116bc2f 100644 --- a/src/mbgl/geometry/feature_index.cpp +++ b/src/mbgl/geometry/feature_index.cpp @@ -8,13 +8,29 @@ #include #include #include +#include #include +#include #include #include #include +namespace { +mbgl::LatLng screenCoordinateToLatLng(mbgl::ScreenCoordinate point, + const mbgl::TransformState& state, + mbgl::LatLng::WrapMode wrapMode = mbgl::LatLng::Wrapped) { + point.y = state.getSize().height - point.y; + return state.screenCoordinateToLatLng(point, wrapMode); +} +mbgl::Point project(const mbgl::LatLng& coordinate, const mbgl::TransformState& state) { + mbgl::LatLng unwrappedLatLng = coordinate.wrapped(); + unwrappedLatLng.unwrapForShortestPath(state.getLatLng(mbgl::LatLng::Wrapped)); + return mbgl::Projection::project(unwrappedLatLng, state.getScale()); +} +} // namespace + namespace mbgl { FeatureIndex::FeatureIndex(std::unique_ptr tileData_) @@ -194,4 +210,35 @@ void FeatureIndex::setBucketLayerIDs(const std::string& bucketLeaderID, const st bucketLayerIDs[bucketLeaderID] = layerIDs; } +DynamicFeatureIndex::~DynamicFeatureIndex() = default; + +void DynamicFeatureIndex::query(std::unordered_map>& result, + const mbgl::ScreenLineString& queryGeometry, + const TransformState& state) const { + if (features.empty()) return; + mbgl::WithinBBox queryBox = DefaultBBox; + for (const auto& p : queryGeometry) { + const LatLng c = screenCoordinateToLatLng(p, state); + const Point pm = project(c, state); + const Point coord = {int64_t(pm.x), int64_t(pm.y)}; + mbgl::updateBBox(queryBox, coord); + } + for (const auto& f : features) { + // hit testing + mbgl::WithinBBox featureBox = DefaultBBox; + for (const auto& p : f.envelope->front()) mbgl::updateBBox(featureBox, p); + + const bool hit = mbgl::boxWithinBox(featureBox, queryBox) || mbgl::boxWithinBox(queryBox, featureBox); + if (hit) { + assert(f.feature); + result[f.feature->sourceLayer].push_back(*f.feature); + } + } +} + +void DynamicFeatureIndex::insert(std::shared_ptr feature, + std::shared_ptr> envelope) { + features.push_back({std::move(feature), std::move(envelope)}); +} + } // namespace mbgl diff --git a/src/mbgl/geometry/feature_index.hpp b/src/mbgl/geometry/feature_index.hpp index 24f36d98a0..dc6aa55f5e 100644 --- a/src/mbgl/geometry/feature_index.hpp +++ b/src/mbgl/geometry/feature_index.hpp @@ -3,8 +3,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -53,6 +54,24 @@ public: using FeatureSortOrder = std::shared_ptr>; +class DynamicFeatureIndex { +public: + ~DynamicFeatureIndex(); + void query(std::unordered_map>& result, + const mbgl::ScreenLineString& queryGeometry, + const TransformState& state) const; + + void insert(std::shared_ptr feature, std::shared_ptr> envelope); + +protected: + struct FeatureRecord { + std::shared_ptr feature; + std::shared_ptr> envelope; + }; + + std::vector features; +}; + class FeatureIndex { public: FeatureIndex(std::unique_ptr tileData_); diff --git a/src/mbgl/renderer/layers/render_location_indicator_layer.cpp b/src/mbgl/renderer/layers/render_location_indicator_layer.cpp index 933f674b89..c3872e92d0 100644 --- a/src/mbgl/renderer/layers/render_location_indicator_layer.cpp +++ b/src/mbgl/renderer/layers/render_location_indicator_layer.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -266,6 +267,7 @@ public: ~Texture() { release(); } void release() { MBGL_CHECK_ERROR(glDeleteTextures(1, &texId)); + texId = 0; image = nullptr; } /* @@ -338,7 +340,12 @@ public: float pixelRatio = 1.0f; }; - RenderLocationIndicatorImpl() : ruler(0, mapbox::cheap_ruler::CheapRuler::Meters) {} + RenderLocationIndicatorImpl(std::string sourceLayer) + : ruler(0, mapbox::cheap_ruler::CheapRuler::Meters), + feature(std::make_shared()), + featureEnvelope(std::make_shared>()) { + feature->sourceLayer = std::move(sourceLayer); + } static bool hasAnisotropicFiltering() { const auto* extensions = reinterpret_cast(glGetString(GL_EXTENSIONS)); @@ -404,7 +411,6 @@ public: projectionCircle = params.projectionMatrix; const Point positionMercator = project(params.puckPosition, *params.state); - mat4 translation; matrix::identity(translation); matrix::translate(translation, translation, positionMercator.x, positionMercator.y, 0.0); matrix::multiply(projectionCircle, projectionCircle, translation); @@ -422,6 +428,25 @@ public: } } oldParams = params; + dirtyFeature = true; + } + + void updateFeature() { + if (!dirtyFeature) return; + dirtyFeature = false; + featureEnvelope->clear(); + if (!texPuck || !texPuck->isValid()) return; + + feature->geometry = + mapbox::geometry::point{oldParams.puckPosition.latitude(), oldParams.puckPosition.longitude()}; + mapbox::geometry::linear_ring border; + for (const auto& v : puckGeometry) { + vec4 p{v.x, v.y, 0, 1}; + matrix::transformMat4(p, p, translation); + border.push_back(Point{int64_t(p[0]), int64_t(p[1])}); + } + border.push_back(border.front()); + featureEnvelope->push_back(border); } protected: @@ -682,6 +707,7 @@ protected: std::array puckGeometry; std::array hatGeometry; std::array texCoords; + mbgl::mat4 translation; mbgl::mat4 projectionCircle; mbgl::mat4 projectionPuck; @@ -690,9 +716,12 @@ protected: bool bearingChanged = false; mbgl::LocationIndicatorRenderParameters oldParams; bool initialized = false; + bool dirtyFeature = true; public: mbgl::LocationIndicatorRenderParameters parameters; + std::shared_ptr feature; + std::shared_ptr> featureEnvelope; static bool anisotropicFilteringAvailable; }; @@ -709,7 +738,7 @@ inline const LocationIndicatorLayer::Impl& impl(const Immutable _impl) : RenderLayer(makeMutable(std::move(_impl))), - renderImpl(std::make_unique()), + renderImpl(std::make_unique(impl(baseImpl).id)), unevaluated(impl(baseImpl).paint.untransitioned()) { assert(gfx::BackendScope::exists()); } @@ -804,4 +833,9 @@ void RenderLocationIndicatorLayer::render(PaintParameters& paintParameters) { glContext.setDirtyState(); } +void RenderLocationIndicatorLayer::populateDynamicRenderFeatureIndex(DynamicFeatureIndex& index) const { + renderImpl->updateFeature(); + if (!renderImpl->featureEnvelope->empty()) index.insert(renderImpl->feature, renderImpl->featureEnvelope); +} + } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_location_indicator_layer.hpp b/src/mbgl/renderer/layers/render_location_indicator_layer.hpp index 0adb328df9..78d1203731 100644 --- a/src/mbgl/renderer/layers/render_location_indicator_layer.hpp +++ b/src/mbgl/renderer/layers/render_location_indicator_layer.hpp @@ -21,6 +21,7 @@ private: void prepare(const LayerPrepareParameters &) override; void render(PaintParameters &) override; + void populateDynamicRenderFeatureIndex(DynamicFeatureIndex &) const override; bool contextDestroyed = false; std::unique_ptr renderImpl; diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index f7232a5aa0..553730de24 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -21,6 +21,7 @@ class TransformState; class PatternAtlas; class LineAtlas; class SymbolBucket; +class DynamicFeatureIndex; class LayerRenderData { public: @@ -106,6 +107,8 @@ public: return false; }; + virtual void populateDynamicRenderFeatureIndex(DynamicFeatureIndex&) const {} + virtual void prepare(const LayerPrepareParameters&); const LayerPlacementData& getPlacementData() const { return placementData; } diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 77e23d3ab6..d7f13695de 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -52,7 +52,7 @@ private: bool hasRenderPass(RenderPass pass) const override { return layer.get().hasRenderPass(pass); } void upload(gfx::UploadPass& pass) const override { layer.get().upload(pass); } void render(PaintParameters& parameters) const override { layer.get().render(parameters); } - const std::string& getName() const override { return layer.get().getID(); } + const std::string& getName() const override { return layer.get().getID(); } }; class RenderTreeImpl final : public RenderTree { @@ -327,7 +327,7 @@ std::unique_ptr RenderOrchestrator::createRenderTree( } } continue; - } + } // Handle layers without source. if (layerIsVisible && zoomFitsLayer && sourceImpl.get() == sourceImpls->at(0).get()) { @@ -335,7 +335,8 @@ std::unique_ptr RenderOrchestrator::createRenderTree( const auto& solidBackground = layer.getSolidBackground(); if (solidBackground) { renderTreeParameters->backgroundColor = *solidBackground; - continue; // This layer is shown with background color, and it shall not be added to render items. + continue; // This layer is shown with background color, and it shall not be added to render + // items. } } renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, layer, nullptr, index); @@ -474,7 +475,7 @@ std::vector RenderOrchestrator::queryRenderedFeatures(const ScreenLineS return queryRenderedFeatures(geometry, options, layers); } - + void RenderOrchestrator::queryRenderedSymbols(std::unordered_map>& resultsByLayer, const ScreenLineString& geometry, const std::unordered_map& layers, @@ -506,7 +507,7 @@ void RenderOrchestrator::queryRenderedSymbols(std::unordered_maplookupSymbolFeatures(renderedSymbols[queryData.bucketInstanceId], @@ -514,7 +515,7 @@ void RenderOrchestrator::queryRenderedSymbols(std::unordered_map RenderOrchestrator::queryRenderedFeatures(const ScreenLineS std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin())); } } - + queryRenderedSymbols(resultsByLayer, geometry, filteredLayers, options); + mbgl::DynamicFeatureIndex dynamicIndex; + for (const auto& pair : filteredLayers) { + const RenderLayer* layer = pair.second; + layer->populateDynamicRenderFeatureIndex(dynamicIndex); + } + dynamicIndex.query(resultsByLayer, geometry, transformState); std::vector result; if (resultsByLayer.empty()) { -- cgit v1.2.1