diff options
Diffstat (limited to 'src/mbgl/layout/circle_layout.hpp')
-rw-r--r-- | src/mbgl/layout/circle_layout.hpp | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/mbgl/layout/circle_layout.hpp b/src/mbgl/layout/circle_layout.hpp new file mode 100644 index 0000000000..0f4f1d0328 --- /dev/null +++ b/src/mbgl/layout/circle_layout.hpp @@ -0,0 +1,165 @@ +#pragma once +#include <mbgl/geometry/feature_index.hpp> +#include <mbgl/layout/layout.hpp> +#include <mbgl/renderer/bucket_parameters.hpp> +#include <mbgl/renderer/buckets/circle_bucket.hpp> +#include <mbgl/renderer/render_layer.hpp> +#include <mbgl/style/layers/circle_layer_impl.hpp> + +namespace mbgl { + +class CircleFeature { +public: + friend bool operator<(const CircleFeature& lhs, const CircleFeature& rhs) { return lhs.sortKey < rhs.sortKey; } + + size_t i; + std::unique_ptr<GeometryTileFeature> feature; + float sortKey; +}; + +class CircleLayout : public Layout { +public: + CircleLayout(const BucketParameters& parameters, + const std::vector<Immutable<style::LayerProperties>>& group, + std::unique_ptr<GeometryTileLayer> sourceLayer_) + : sourceLayer(std::move(sourceLayer_)), + zoom(parameters.tileID.overscaledZ), + mode(parameters.mode), + hasPattern(false) { + assert(!group.empty()); + auto leaderLayerProperties = staticImmutableCast<style::CircleLayerProperties>(group.front()); + unevaluatedLayout = leaderLayerProperties->layerImpl().layout; + layout = unevaluatedLayout.evaluate(PropertyEvaluationParameters(zoom)); + sourceLayerID = leaderLayerProperties->layerImpl().sourceLayer; + bucketLeaderID = leaderLayerProperties->layerImpl().id; + + for (const auto& layerProperties : group) { + const std::string& layerId = layerProperties->baseImpl->id; + layerPropertiesMap.emplace(layerId, layerProperties); + } + + const size_t featureCount = sourceLayer->featureCount(); + for (size_t i = 0; i < featureCount; ++i) { + auto feature = sourceLayer->getFeature(i); + if (!leaderLayerProperties->layerImpl().filter( + style::expression::EvaluationContext{this->zoom, feature.get()})) + continue; + + auto sortKey = evaluateSortKey(*feature); + + CircleFeature circleFeature{i, std::move(feature), sortKey}; + const auto sortPosition = std::lower_bound(features.cbegin(), features.cend(), circleFeature); + features.insert(sortPosition, std::move(circleFeature)); + } + }; + + ~CircleLayout() final = default; + + bool hasDependencies() const override { return hasPattern; } + + void createBucket(const ImagePositions&, + std::unique_ptr<FeatureIndex>& featureIndex, + std::unordered_map<std::string, LayerRenderData>& renderData, + const bool, + const bool, + const CanonicalTileID& canonical) override { + auto bucket = std::make_shared<CircleBucket>(layerPropertiesMap, mode, zoom); + + for (auto& circleFeature : features) { + const auto i = circleFeature.i; + std::unique_ptr<GeometryTileFeature> feature = std::move(circleFeature.feature); + const GeometryCollection& geometries = feature->getGeometries(); + + addCircle(*bucket, *feature, geometries, i, circleFeature.sortKey, canonical); + featureIndex->insert(geometries, i, sourceLayerID, bucketLeaderID); + } + if (bucket->hasData()) { + for (const auto& pair : layerPropertiesMap) { + renderData.emplace(pair.first, LayerRenderData{bucket, pair.second}); + } + } + }; + +private: + void addCircle(CircleBucket& bucket, + const GeometryTileFeature& feature, + const GeometryCollection& geometry, + std::size_t featureIndex, + float sortKey, + const CanonicalTileID& canonical) { + constexpr const uint16_t vertexLength = 4; + + auto& segments = bucket.segments; + auto& vertices = bucket.vertices; + auto& triangles = bucket.triangles; + + for (auto& circle : geometry) { + for (auto& point : circle) { + auto x = point.x; + auto y = point.y; + + // Do not include points that are outside the tile boundaries. + // Include all points in Still mode. You need to include points from + // neighbouring tiles so that they are not clipped at tile boundaries. + if ((mode == MapMode::Continuous) && (x < 0 || x >= util::EXTENT || y < 0 || y >= util::EXTENT)) + continue; + + if (segments.empty() || + segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) { + // Move to a new segments because the old one can't hold the geometry. + segments.emplace_back(vertices.elements(), triangles.elements(), 0ul, 0ul, sortKey); + } + + // this geometry will be of the Point type, and we'll derive + // two triangles from it. + // + // ┌─────────┐ + // │ 4 3 │ + // │ │ + // │ 1 2 │ + // └─────────┘ + // + vertices.emplace_back(CircleProgram::vertex(point, -1, -1)); // 1 + vertices.emplace_back(CircleProgram::vertex(point, 1, -1)); // 2 + vertices.emplace_back(CircleProgram::vertex(point, 1, 1)); // 3 + vertices.emplace_back(CircleProgram::vertex(point, -1, 1)); // 4 + + auto& segment = segments.back(); + assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max()); + uint16_t index = segment.vertexLength; + + // 1, 2, 3 + // 1, 4, 3 + triangles.emplace_back(index, index + 1, index + 2); + triangles.emplace_back(index, index + 3, index + 2); + + segment.vertexLength += vertexLength; + segment.indexLength += 6; + } + } + + for (auto& pair : bucket.paintPropertyBinders) { + pair.second.populateVertexVectors(feature, vertices.elements(), featureIndex, {}, {}, canonical); + } + } + + float evaluateSortKey(const GeometryTileFeature& sourceFeature) { + const auto sortKeyProperty = layout.template get<style::CircleSortKey>(); + return sortKeyProperty.evaluate(sourceFeature, zoom, style::CircleSortKey::defaultValue()); + } + + std::map<std::string, Immutable<style::LayerProperties>> layerPropertiesMap; + std::string bucketLeaderID; + + const std::unique_ptr<GeometryTileLayer> sourceLayer; + std::list<CircleFeature> features; + typename style::CircleLayoutProperties::Unevaluated unevaluatedLayout; + typename style::CircleLayoutProperties::PossiblyEvaluated layout; + + const float zoom; + const MapMode mode; + std::string sourceLayerID; + bool hasPattern; +}; + +} // namespace mbgl |