diff options
author | zmiao <miao.zhao@mapbox.com> | 2020-01-29 12:46:16 +0200 |
---|---|---|
committer | zmiao <miao.zhao@mapbox.com> | 2020-02-12 12:24:05 +0200 |
commit | 3e99c08ea610d791b21f1631308451687c464d98 (patch) | |
tree | c7f3e20ad9ddc161ab3378d37bde9aa31675da83 /src/mbgl | |
parent | 4f18d5fa92df175ac30f856a9273a00349b56cc3 (diff) | |
download | qtlocation-mapboxgl-3e99c08ea610d791b21f1631308451687c464d98.tar.gz |
Enable parse within expression
Add geometry type checker
Diffstat (limited to 'src/mbgl')
24 files changed, 367 insertions, 80 deletions
diff --git a/src/mbgl/layout/layout.hpp b/src/mbgl/layout/layout.hpp index 4e7c0c7aca..ae0eb5d5f3 100644 --- a/src/mbgl/layout/layout.hpp +++ b/src/mbgl/layout/layout.hpp @@ -21,7 +21,8 @@ public: std::unique_ptr<FeatureIndex>&, std::unordered_map<std::string, LayerRenderData>&, const bool, - const bool) = 0; + const bool, + const CanonicalTileID&) = 0; virtual void prepareSymbols(const GlyphMap&, const GlyphPositions&, const ImageMap&, const ImagePositions&){}; diff --git a/src/mbgl/layout/pattern_layout.hpp b/src/mbgl/layout/pattern_layout.hpp index 44729dea83..c6815e4cad 100644 --- a/src/mbgl/layout/pattern_layout.hpp +++ b/src/mbgl/layout/pattern_layout.hpp @@ -152,7 +152,12 @@ public: return hasPattern; } - void createBucket(const ImagePositions& patternPositions, std::unique_ptr<FeatureIndex>& featureIndex, std::unordered_map<std::string, LayerRenderData>& renderData, const bool, const bool) override { + void createBucket(const ImagePositions& patternPositions, + 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<BucketType>(layout, layerPropertiesMap, zoom, overscaling); for (auto & patternFeature : features) { const auto i = patternFeature.i; @@ -160,7 +165,7 @@ public: const PatternLayerMap& patterns = patternFeature.patterns; const GeometryCollection& geometries = feature->getGeometries(); - bucket->addFeature(*feature, geometries, patternPositions, patterns, i); + bucket->addFeature(*feature, geometries, patternPositions, patterns, i, canonical); featureIndex->insert(geometries, i, sourceLayerID, bucketLeaderID); } if (bucket->hasData()) { diff --git a/src/mbgl/layout/symbol_feature.hpp b/src/mbgl/layout/symbol_feature.hpp index d0aced1b19..f536642709 100644 --- a/src/mbgl/layout/symbol_feature.hpp +++ b/src/mbgl/layout/symbol_feature.hpp @@ -12,16 +12,16 @@ namespace mbgl { class SymbolFeature : public GeometryTileFeature { public: - SymbolFeature(std::unique_ptr<GeometryTileFeature> feature_) : - feature(std::move(feature_)), - geometry(feature->getGeometries().clone()) // we need a mutable copy of the geometry for mergeLines() + SymbolFeature(std::unique_ptr<GeometryTileFeature> feature_) + : feature(std::move(feature_)), + geometry(feature->getGeometries().clone()) // we need a mutable copy of the geometry for mergeLines() {} - + FeatureType getType() const override { return feature->getType(); } - optional<Value> getValue(const std::string& key) const override { return feature->getValue(key); }; - const PropertyMap& getProperties() const override { return feature->getProperties(); }; + optional<Value> getValue(const std::string& key) const override { return feature->getValue(key); } + const PropertyMap& getProperties() const override { return feature->getProperties(); } FeatureIdentifier getID() const override { return feature->getID(); }; - const GeometryCollection& getGeometries() const override { return geometry; }; + const GeometryCollection& getGeometries() const override { return feature->getGeometries(); } friend bool operator < (const SymbolFeature& lhs, const SymbolFeature& rhs) { return lhs.sortKey < rhs.sortKey; diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 61c3b4ad66..a4890c85d1 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -742,7 +742,12 @@ std::vector<float> SymbolLayout::calculateTileDistances(const GeometryCoordinate return tileDistances; } -void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIndex>&, std::unordered_map<std::string, LayerRenderData>& renderData, const bool firstLoad, const bool showCollisionBoxes) { +void SymbolLayout::createBucket(const ImagePositions&, + std::unique_ptr<FeatureIndex>&, + std::unordered_map<std::string, LayerRenderData>& renderData, + const bool firstLoad, + const bool showCollisionBoxes, + const CanonicalTileID& canonical) { auto bucket = std::make_shared<SymbolBucket>(layout, layerPaintProperties, textSize, @@ -796,8 +801,8 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn } for (auto& pair : bucket->paintProperties) { - pair.second.iconBinders.populateVertexVectors(feature, iconBuffer.vertices.elements(), - symbolInstance.dataFeatureIndex, {}, {}); + pair.second.iconBinders.populateVertexVectors( + feature, iconBuffer.vertices.elements(), symbolInstance.dataFeatureIndex, {}, {}, canonical); } } @@ -805,26 +810,61 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn optional<std::size_t> lastAddedSection; if (singleLine) { optional<std::size_t> placedTextIndex; - lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, placedTextIndex, symbolInstance.rightJustifiedGlyphQuads(), lastAddedSection); + lastAddedSection = addSymbolGlyphQuads(*bucket, + symbolInstance, + feature, + symbolInstance.writingModes, + placedTextIndex, + symbolInstance.rightJustifiedGlyphQuads(), + canonical, + lastAddedSection); symbolInstance.placedRightTextIndex = placedTextIndex; symbolInstance.placedCenterTextIndex = placedTextIndex; symbolInstance.placedLeftTextIndex = placedTextIndex; } else { if (symbolInstance.rightJustifiedGlyphQuadsSize) { - lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, symbolInstance.placedRightTextIndex, symbolInstance.rightJustifiedGlyphQuads(), lastAddedSection); + lastAddedSection = addSymbolGlyphQuads(*bucket, + symbolInstance, + feature, + symbolInstance.writingModes, + symbolInstance.placedRightTextIndex, + symbolInstance.rightJustifiedGlyphQuads(), + canonical, + lastAddedSection); } if (symbolInstance.centerJustifiedGlyphQuadsSize) { - lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, symbolInstance.placedCenterTextIndex, symbolInstance.centerJustifiedGlyphQuads(), lastAddedSection); + lastAddedSection = addSymbolGlyphQuads(*bucket, + symbolInstance, + feature, + symbolInstance.writingModes, + symbolInstance.placedCenterTextIndex, + symbolInstance.centerJustifiedGlyphQuads(), + canonical, + lastAddedSection); } if (symbolInstance.leftJustifiedGlyphQuadsSize) { - lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, symbolInstance.placedLeftTextIndex, symbolInstance.leftJustifiedGlyphQuads(), lastAddedSection); + lastAddedSection = addSymbolGlyphQuads(*bucket, + symbolInstance, + feature, + symbolInstance.writingModes, + symbolInstance.placedLeftTextIndex, + symbolInstance.leftJustifiedGlyphQuads(), + canonical, + lastAddedSection); } } if (symbolInstance.writingModes & WritingModeType::Vertical && symbolInstance.verticalGlyphQuadsSize) { - lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, WritingModeType::Vertical, symbolInstance.placedVerticalTextIndex, symbolInstance.verticalGlyphQuads(), lastAddedSection); + lastAddedSection = addSymbolGlyphQuads(*bucket, + symbolInstance, + feature, + WritingModeType::Vertical, + symbolInstance.placedVerticalTextIndex, + symbolInstance.verticalGlyphQuads(), + canonical, + lastAddedSection); } assert(lastAddedSection); // True, as hasText == true; - updatePaintPropertiesForSection(*bucket, feature, *lastAddedSection); + updatePaintPropertiesForSection(*bucket, feature, *lastAddedSection, canonical); } symbolInstance.releaseSharedData(); @@ -841,16 +881,16 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn renderData.emplace(pair.first, LayerRenderData{bucket, pair.second}); } } - } void SymbolLayout::updatePaintPropertiesForSection(SymbolBucket& bucket, const SymbolFeature& feature, - std::size_t sectionIndex) { + std::size_t sectionIndex, + const CanonicalTileID& canonical) { const auto& formattedSection = sectionOptionsToValue((*feature.formattedText).sectionAt(sectionIndex)); for (auto& pair : bucket.paintProperties) { - pair.second.textBinders.populateVertexVectors(feature, bucket.text.vertices.elements(), feature.index, {}, {}, - formattedSection); + pair.second.textBinders.populateVertexVectors( + feature, bucket.text.vertices.elements(), feature.index, {}, {}, canonical, formattedSection); } } @@ -860,6 +900,7 @@ std::size_t SymbolLayout::addSymbolGlyphQuads(SymbolBucket& bucket, WritingModeType writingMode, optional<size_t>& placedIndex, const SymbolQuads& glyphQuads, + const CanonicalTileID& canonical, optional<std::size_t> lastAddedSection) { const Range<float> sizeData = bucket.textSizeBinder->getVertexSizeData(feature); const bool hasFormatSectionOverrides = bucket.hasFormatSectionOverrides(); @@ -881,7 +922,7 @@ std::size_t SymbolLayout::addSymbolGlyphQuads(SymbolBucket& bucket, for (const auto& symbolQuad : glyphQuads) { if (hasFormatSectionOverrides) { if (lastAddedSection && *lastAddedSection != symbolQuad.sectionIndex) { - updatePaintPropertiesForSection(bucket, feature, *lastAddedSection); + updatePaintPropertiesForSection(bucket, feature, *lastAddedSection, canonical); } lastAddedSection = symbolQuad.sectionIndex; } diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 52c912c8ae..740a69df9e 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -36,7 +36,12 @@ public: const ImageMap&, const ImagePositions&) override; - void createBucket(const ImagePositions&, std::unique_ptr<FeatureIndex>&, std::unordered_map<std::string, LayerRenderData>&, const bool firstLoad, const bool showCollisionBoxes) override; + void createBucket(const ImagePositions&, + std::unique_ptr<FeatureIndex>&, + std::unordered_map<std::string, LayerRenderData>&, + const bool firstLoad, + const bool showCollisionBoxes, + const CanonicalTileID& canonical) override; bool hasSymbolInstances() const override; bool hasDependencies() const override; @@ -97,11 +102,13 @@ private: WritingModeType, optional<size_t>& placedIndex, const SymbolQuads&, + const CanonicalTileID& canonical, optional<std::size_t> lastAddedSection = nullopt); void updatePaintPropertiesForSection(SymbolBucket&, const SymbolFeature&, - std::size_t sectionIndex); + std::size_t sectionIndex, + const CanonicalTileID& canonical); // Stores the layer so that we can hold on to GeometryTileFeature instances in SymbolFeature, // which may reference data from this object. diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp index fc34f55e75..4e28107f07 100644 --- a/src/mbgl/renderer/bucket.hpp +++ b/src/mbgl/renderer/bucket.hpp @@ -32,8 +32,12 @@ public: // Feature geometries are also used to populate the feature index. // Obtaining these is a costly operation, so we do it only once, and // pass-by-const-ref the geometries as a second parameter. - virtual void addFeature(const GeometryTileFeature&, const GeometryCollection&, const ImagePositions&, - const PatternLayerMap&, std::size_t){}; + virtual void addFeature(const GeometryTileFeature&, + const GeometryCollection&, + const ImagePositions&, + const PatternLayerMap&, + std::size_t, + const CanonicalTileID&){}; virtual void update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) {} diff --git a/src/mbgl/renderer/buckets/circle_bucket.cpp b/src/mbgl/renderer/buckets/circle_bucket.cpp index 560a74781a..744b559c42 100644 --- a/src/mbgl/renderer/buckets/circle_bucket.cpp +++ b/src/mbgl/renderer/buckets/circle_bucket.cpp @@ -41,8 +41,12 @@ bool CircleBucket::hasData() const { return !segments.empty(); } -void CircleBucket::addFeature(const GeometryTileFeature& feature, const GeometryCollection& geometry, - const ImagePositions&, const PatternLayerMap&, std::size_t featureIndex) { +void CircleBucket::addFeature(const GeometryTileFeature& feature, + const GeometryCollection& geometry, + const ImagePositions&, + const PatternLayerMap&, + std::size_t featureIndex, + const CanonicalTileID& canonical) { constexpr const uint16_t vertexLength = 4; for (auto& circle : geometry) { @@ -90,7 +94,7 @@ void CircleBucket::addFeature(const GeometryTileFeature& feature, const Geometry } for (auto& pair : paintPropertyBinders) { - pair.second.populateVertexVectors(feature, vertices.elements(), featureIndex, {}, {}); + pair.second.populateVertexVectors(feature, vertices.elements(), featureIndex, {}, {}, canonical); } } diff --git a/src/mbgl/renderer/buckets/circle_bucket.hpp b/src/mbgl/renderer/buckets/circle_bucket.hpp index e514f8a5f2..17ddd9dc10 100644 --- a/src/mbgl/renderer/buckets/circle_bucket.hpp +++ b/src/mbgl/renderer/buckets/circle_bucket.hpp @@ -18,8 +18,12 @@ public: CircleBucket(const BucketParameters&, const std::vector<Immutable<style::LayerProperties>>&); ~CircleBucket() override; - void addFeature(const GeometryTileFeature&, const GeometryCollection&, const ImagePositions&, - const PatternLayerMap&, std::size_t) override; + void addFeature(const GeometryTileFeature&, + const GeometryCollection&, + const ImagePositions&, + const PatternLayerMap&, + std::size_t, + const CanonicalTileID&) override; bool hasData() const override; diff --git a/src/mbgl/renderer/buckets/fill_bucket.cpp b/src/mbgl/renderer/buckets/fill_bucket.cpp index 6660934f8d..73c2530241 100644 --- a/src/mbgl/renderer/buckets/fill_bucket.cpp +++ b/src/mbgl/renderer/buckets/fill_bucket.cpp @@ -44,9 +44,12 @@ FillBucket::FillBucket(const FillBucket::PossiblyEvaluatedLayoutProperties, FillBucket::~FillBucket() = default; -void FillBucket::addFeature(const GeometryTileFeature& feature, const GeometryCollection& geometry, - const ImagePositions& patternPositions, const PatternLayerMap& patternDependencies, - std::size_t index) { +void FillBucket::addFeature(const GeometryTileFeature& feature, + const GeometryCollection& geometry, + const ImagePositions& patternPositions, + const PatternLayerMap& patternDependencies, + std::size_t index, + const CanonicalTileID& canonical) { for (auto& polygon : classifyRings(geometry)) { // Optimize polygons with many interior rings for earcut tesselation. limitHoles(polygon, 500); @@ -113,9 +116,10 @@ void FillBucket::addFeature(const GeometryTileFeature& feature, const GeometryCo for (auto& pair : paintPropertyBinders) { const auto it = patternDependencies.find(pair.first); if (it != patternDependencies.end()){ - pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, it->second); + pair.second.populateVertexVectors( + feature, vertices.elements(), index, patternPositions, it->second, canonical); } else { - pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, {}); + pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, {}, canonical); } } } diff --git a/src/mbgl/renderer/buckets/fill_bucket.hpp b/src/mbgl/renderer/buckets/fill_bucket.hpp index 7a3f681121..4de97141a7 100644 --- a/src/mbgl/renderer/buckets/fill_bucket.hpp +++ b/src/mbgl/renderer/buckets/fill_bucket.hpp @@ -25,8 +25,12 @@ public: const float zoom, const uint32_t overscaling); - void addFeature(const GeometryTileFeature&, const GeometryCollection&, const mbgl::ImagePositions&, - const PatternLayerMap&, std::size_t) override; + void addFeature(const GeometryTileFeature&, + const GeometryCollection&, + const mbgl::ImagePositions&, + const PatternLayerMap&, + std::size_t, + const CanonicalTileID&) override; bool hasData() const override; diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp index 698895fdcf..39c9f9af1e 100644 --- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp +++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp @@ -50,9 +50,12 @@ FillExtrusionBucket::FillExtrusionBucket(const FillExtrusionBucket::PossiblyEval FillExtrusionBucket::~FillExtrusionBucket() = default; -void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature, const GeometryCollection& geometry, - const ImagePositions& patternPositions, const PatternLayerMap& patternDependencies, - std::size_t index) { +void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature, + const GeometryCollection& geometry, + const ImagePositions& patternPositions, + const PatternLayerMap& patternDependencies, + std::size_t index, + const CanonicalTileID& canonical) { for (auto& polygon : classifyRings(geometry)) { // Optimize polygons with many interior rings for earcut tesselation. limitHoles(polygon, 500); @@ -157,9 +160,10 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature, const G for (auto& pair : paintPropertyBinders) { const auto it = patternDependencies.find(pair.first); if (it != patternDependencies.end()){ - pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, it->second); + pair.second.populateVertexVectors( + feature, vertices.elements(), index, patternPositions, it->second, canonical); } else { - pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, {}); + pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, {}, canonical); } } } diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp index 8535f99b70..833eee7a73 100644 --- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp +++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp @@ -24,8 +24,12 @@ public: const float, const uint32_t); - void addFeature(const GeometryTileFeature&, const GeometryCollection&, const mbgl::ImagePositions&, - const PatternLayerMap&, std::size_t) override; + void addFeature(const GeometryTileFeature&, + const GeometryCollection&, + const mbgl::ImagePositions&, + const PatternLayerMap&, + std::size_t, + const CanonicalTileID&) override; bool hasData() const override; diff --git a/src/mbgl/renderer/buckets/heatmap_bucket.cpp b/src/mbgl/renderer/buckets/heatmap_bucket.cpp index 78c4fb7507..31c4bc0e9c 100644 --- a/src/mbgl/renderer/buckets/heatmap_bucket.cpp +++ b/src/mbgl/renderer/buckets/heatmap_bucket.cpp @@ -39,8 +39,12 @@ bool HeatmapBucket::hasData() const { return !segments.empty(); } -void HeatmapBucket::addFeature(const GeometryTileFeature& feature, const GeometryCollection& geometry, - const ImagePositions&, const PatternLayerMap&, std::size_t featureIndex) { +void HeatmapBucket::addFeature(const GeometryTileFeature& feature, + const GeometryCollection& geometry, + const ImagePositions&, + const PatternLayerMap&, + std::size_t featureIndex, + const CanonicalTileID& canonical) { constexpr const uint16_t vertexLength = 4; for (auto& points : geometry) { @@ -87,7 +91,7 @@ void HeatmapBucket::addFeature(const GeometryTileFeature& feature, const Geometr } for (auto& pair : paintPropertyBinders) { - pair.second.populateVertexVectors(feature, vertices.elements(), featureIndex, {}, {}); + pair.second.populateVertexVectors(feature, vertices.elements(), featureIndex, {}, {}, canonical); } } diff --git a/src/mbgl/renderer/buckets/heatmap_bucket.hpp b/src/mbgl/renderer/buckets/heatmap_bucket.hpp index 04d4170b50..0aaff7f298 100644 --- a/src/mbgl/renderer/buckets/heatmap_bucket.hpp +++ b/src/mbgl/renderer/buckets/heatmap_bucket.hpp @@ -18,8 +18,12 @@ public: HeatmapBucket(const BucketParameters&, const std::vector<Immutable<style::LayerProperties>>&); ~HeatmapBucket() override; - void addFeature(const GeometryTileFeature&, const GeometryCollection&, const ImagePositions&, - const PatternLayerMap&, std::size_t) override; + void addFeature(const GeometryTileFeature&, + const GeometryCollection&, + const ImagePositions&, + const PatternLayerMap&, + std::size_t, + const CanonicalTileID&) override; bool hasData() const override; void upload(gfx::UploadPass&) override; diff --git a/src/mbgl/renderer/buckets/line_bucket.cpp b/src/mbgl/renderer/buckets/line_bucket.cpp index c32515e016..fdb110bc9d 100644 --- a/src/mbgl/renderer/buckets/line_bucket.cpp +++ b/src/mbgl/renderer/buckets/line_bucket.cpp @@ -27,9 +27,12 @@ LineBucket::LineBucket(const LineBucket::PossiblyEvaluatedLayoutProperties layou LineBucket::~LineBucket() = default; -void LineBucket::addFeature(const GeometryTileFeature& feature, const GeometryCollection& geometryCollection, - const ImagePositions& patternPositions, const PatternLayerMap& patternDependencies, - std::size_t index) { +void LineBucket::addFeature(const GeometryTileFeature& feature, + const GeometryCollection& geometryCollection, + const ImagePositions& patternPositions, + const PatternLayerMap& patternDependencies, + std::size_t index, + const CanonicalTileID& canonical) { for (auto& line : geometryCollection) { addGeometry(line, feature); } @@ -37,9 +40,10 @@ void LineBucket::addFeature(const GeometryTileFeature& feature, const GeometryCo for (auto& pair : paintPropertyBinders) { const auto it = patternDependencies.find(pair.first); if (it != patternDependencies.end()){ - pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, it->second); + pair.second.populateVertexVectors( + feature, vertices.elements(), index, patternPositions, it->second, canonical); } else { - pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, {}); + pair.second.populateVertexVectors(feature, vertices.elements(), index, patternPositions, {}, canonical); } } } diff --git a/src/mbgl/renderer/buckets/line_bucket.hpp b/src/mbgl/renderer/buckets/line_bucket.hpp index a3237c9df9..a3821d108b 100644 --- a/src/mbgl/renderer/buckets/line_bucket.hpp +++ b/src/mbgl/renderer/buckets/line_bucket.hpp @@ -25,8 +25,12 @@ public: const uint32_t overscaling); ~LineBucket() override; - void addFeature(const GeometryTileFeature&, const GeometryCollection&, const mbgl::ImagePositions& patternPositions, - const PatternLayerMap&, std::size_t) override; + void addFeature(const GeometryTileFeature&, + const GeometryCollection&, + const mbgl::ImagePositions& patternPositions, + const PatternLayerMap&, + std::size_t, + const CanonicalTileID&) override; bool hasData() const override; diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index db9f61411a..3a9dceacc0 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -105,8 +105,12 @@ public: virtual ~PaintPropertyBinder() = default; - virtual void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, std::size_t index, - const ImagePositions&, const optional<PatternDependency>&, + virtual void populateVertexVector(const GeometryTileFeature& feature, + std::size_t length, + std::size_t index, + const ImagePositions&, + const optional<PatternDependency>&, + const CanonicalTileID& canonical, const style::expression::Value&) = 0; virtual void updateVertexVectors(const FeatureStates&, const GeometryTileLayer&, const ImagePositions&) {} @@ -131,8 +135,13 @@ public: : constant(std::move(constant_)) { } - void populateVertexVector(const GeometryTileFeature&, std::size_t, std::size_t, const ImagePositions&, - const optional<PatternDependency>&, const style::expression::Value&) override {} + void populateVertexVector(const GeometryTileFeature&, + std::size_t, + std::size_t, + const ImagePositions&, + const optional<PatternDependency>&, + const CanonicalTileID&, + const style::expression::Value&) override {} void updateVertexVector(std::size_t, std::size_t, const GeometryTileFeature&, const FeatureState&) override {} void upload(gfx::UploadPass&) override {} void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, const CrossfadeParameters&) override {}; @@ -160,8 +169,13 @@ public: : constant(std::move(constant_)), constantPatternPositions({}) { } - void populateVertexVector(const GeometryTileFeature&, std::size_t, std::size_t, const ImagePositions&, - const optional<PatternDependency>&, const style::expression::Value&) override {} + void populateVertexVector(const GeometryTileFeature&, + std::size_t, + std::size_t, + const ImagePositions&, + const optional<PatternDependency>&, + const CanonicalTileID&, + const style::expression::Value&) override {} void updateVertexVector(std::size_t, std::size_t, const GeometryTileFeature&, const FeatureState&) override {} void upload(gfx::UploadPass&) override {} @@ -204,11 +218,17 @@ public: defaultValue(std::move(defaultValue_)) { } void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, const CrossfadeParameters&) override {}; - void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, std::size_t index, - const ImagePositions&, const optional<PatternDependency>&, + void populateVertexVector(const GeometryTileFeature& feature, + std::size_t length, + std::size_t index, + const ImagePositions&, + const optional<PatternDependency>&, + const CanonicalTileID& canonical, const style::expression::Value& formattedSection) override { using style::expression::EvaluationContext; - auto evaluated = expression.evaluate(EvaluationContext(&feature).withFormattedSection(&formattedSection), defaultValue); + auto evaluated = expression.evaluate( + EvaluationContext(&feature).withFormattedSection(&formattedSection).withCanonicalTileID(canonical), + defaultValue); this->statistics.add(evaluated); auto value = attributeValue(evaluated); auto elements = vertexVector.elements(); @@ -299,13 +319,23 @@ public: zoomRange({zoom, zoom + 1}) { } void setPatternParameters(const optional<ImagePosition>&, const optional<ImagePosition>&, const CrossfadeParameters&) override {}; - void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, std::size_t index, - const ImagePositions&, const optional<PatternDependency>&, + void populateVertexVector(const GeometryTileFeature& feature, + std::size_t length, + std::size_t index, + const ImagePositions&, + const optional<PatternDependency>&, + const CanonicalTileID& canonical, const style::expression::Value& formattedSection) override { using style::expression::EvaluationContext; Range<T> range = { - expression.evaluate(EvaluationContext(zoomRange.min, &feature).withFormattedSection(&formattedSection), defaultValue), - expression.evaluate(EvaluationContext(zoomRange.max, &feature).withFormattedSection(&formattedSection), defaultValue), + expression.evaluate(EvaluationContext(zoomRange.min, &feature) + .withFormattedSection(&formattedSection) + .withCanonicalTileID(canonical), + defaultValue), + expression.evaluate(EvaluationContext(zoomRange.max, &feature) + .withFormattedSection(&formattedSection) + .withCanonicalTileID(canonical), + defaultValue), }; this->statistics.add(range.min); this->statistics.add(range.max); @@ -416,9 +446,12 @@ public: crossfade = crossfade_; }; - void populateVertexVector(const GeometryTileFeature&, std::size_t length, std::size_t /* index */, + void populateVertexVector(const GeometryTileFeature&, + std::size_t length, + std::size_t /* index */, const ImagePositions& patternPositions, const optional<PatternDependency>& patternDependencies, + const CanonicalTileID&, const style::expression::Value&) override { if (!patternDependencies || patternDependencies->mid.empty()) { // Unlike other propperties with expressions that evaluate to null, the default value for `*-pattern` properties is an empty @@ -589,12 +622,15 @@ public: PaintPropertyBinders(PaintPropertyBinders&&) = default; PaintPropertyBinders(const PaintPropertyBinders&) = delete; - void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length, std::size_t index, + void populateVertexVectors(const GeometryTileFeature& feature, + std::size_t length, + std::size_t index, const ImagePositions& patternPositions, const optional<PatternDependency>& patternDependencies, + const CanonicalTileID& canonical, const style::expression::Value& formattedSection = {}) { - util::ignore({(binders.template get<Ps>()->populateVertexVector(feature, length, index, patternPositions, - patternDependencies, formattedSection), + util::ignore({(binders.template get<Ps>()->populateVertexVector( + feature, length, index, patternPositions, patternDependencies, canonical, formattedSection), 0)...}); } diff --git a/src/mbgl/style/expression/is_constant.cpp b/src/mbgl/style/expression/is_constant.cpp index eb823bc77c..e6bd05418f 100644 --- a/src/mbgl/style/expression/is_constant.cpp +++ b/src/mbgl/style/expression/is_constant.cpp @@ -29,6 +29,10 @@ bool isFeatureConstant(const Expression& expression) { return false; } + if (expression.getKind() == Kind::Within) { + return false; + } + if (expression.getKind() == Kind::CollatorExpression) { // Although the results of a Collator expression with fixed arguments // generally shouldn't change between executions, we can't serialize them diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index ae991b2e88..d42c46bb09 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -22,6 +22,7 @@ #include <mbgl/style/expression/match.hpp> #include <mbgl/style/expression/number_format.hpp> #include <mbgl/style/expression/step.hpp> +#include <mbgl/style/expression/within.hpp> #include <mbgl/style/expression/find_zoom_curve.hpp> #include <mbgl/style/expression/dsl.hpp> @@ -134,6 +135,7 @@ MAPBOX_ETERNAL_CONSTEXPR const auto expressionRegistry = {"to-number", Coercion::parse}, {"to-string", Coercion::parse}, {"var", Var::parse}, + {"within", Within::parse}, }); bool isExpression(const std::string& name) { diff --git a/src/mbgl/style/expression/within.cpp b/src/mbgl/style/expression/within.cpp new file mode 100644 index 0000000000..1b1b8b11b9 --- /dev/null +++ b/src/mbgl/style/expression/within.cpp @@ -0,0 +1,139 @@ +#include <mapbox/geojson.hpp> +#include <mapbox/geometry.hpp> +#include <mbgl/style/conversion_impl.hpp> +#include <mbgl/style/expression/within.hpp> +#include <mbgl/tile/geometry_tile_data.hpp> +#include <mbgl/util/string.hpp> + +namespace { + +double isLeft(mbgl::Point<double> P0, mbgl::Point<double> P1, mbgl::Point<double> P2) { + return ((P1.x - P0.x) * (P2.y - P0.y) - (P2.x - P0.x) * (P1.y - P0.y)); +} + +// winding number algorithm for checking if point inside a ploygon or not. +// http://geomalgorithms.com/a03-_inclusion.html#wn_PnPoly() +bool pointWithinPoly(mbgl::Point<double> point, const mapbox::geometry::polygon<double>& polys) { + // wn = the winding number (=0 only when point is outside) + int wn = 0; + for (auto poly : polys) { + auto size = poly.size(); + auto i = size; + // loop through every edge of the polygon + for (i = 0; i < size - 1; ++i) { + if (poly[i].y <= point.y) { + if (poly[i + 1].y > point.y) { // upward horizontal crossing from point to edge E(poly[i], poly[i+1]) + if (isLeft(poly[i], poly[i + 1], point) > 0) { + ++wn; + } + } + } else { + if (poly[i + 1].y <= point.y) { // downward crossing + if (isLeft(poly[i], poly[i + 1], point) < 0) { + --wn; + } + } + } + } + if (wn != 0) { + return true; + } + } + return wn != 0; +} + +bool pointsWithinPoly(const mbgl::GeometryTileFeature& feature, + const mbgl::CanonicalTileID& canonical, + const mbgl::GeoJSON& geoJson) { + bool result = false; + geoJson.match( + [&](const mapbox::geometry::geometry<double>& geometrySet) { + geometrySet.match( + [&](const mapbox::geometry::polygon<double>& polygons) { + convertGeometry(feature, canonical) + .match( + [&](const mapbox::geometry::point<double>& point) { + result = pointWithinPoly(point, polygons); + }, + [&](const mapbox::geometry::multi_point<double>& points) { + for (const auto& p : points) { + result = pointWithinPoly(p, polygons); + if (!result) { + return; + } + } + }, + [&](const auto&) { return; }); + }, + [&](const auto&) { return; }); + }, + [&](const auto&) { return; }); + + return result; +} + +mbgl::optional<mbgl::GeoJSON> parseValue(const mbgl::style::conversion::Convertible& value_, + mbgl::style::expression::ParsingContext& ctx) { + if (isObject(value_)) { + const auto geometryType = objectMember(value_, "type"); + if (geometryType) { + const auto type = toString(*geometryType); + if (type && *type == "Polygon") { + mbgl::style::conversion::Error error; + auto geojson = toGeoJSON(value_, error); + if (geojson && error.message.empty()) { + return geojson; + } + ctx.error(error.message); + } + } + } + ctx.error("'Within' expression requires valid geojson source that contains polygon geometry type."); + return mbgl::optional<mbgl::GeoJSON>(); +} + +} // namespace + +namespace mbgl { +namespace style { +namespace expression { + +using namespace mbgl::style::conversion; + +EvaluationResult Within::evaluate(const EvaluationContext& params) const { + if (!params.feature || !params.canonical) { + return false; + } + auto geometryType = params.feature->getType(); + // Currently only support Point/Points in polygon + if (geometryType == FeatureType::Point) { + return pointsWithinPoly(*params.feature, *params.canonical, geoJSONSource); + } + return false; +} + +ParseResult Within::parse(const Convertible& value, ParsingContext& ctx) { + if (isArray(value)) { + // object value, quoted with ["Within", value] + if (arrayLength(value) != 2) { + ctx.error("'Within' expression requires exactly one argument, but found " + + util::toString(arrayLength(value) - 1) + " instead."); + return ParseResult(); + } + + auto parsedValue = parseValue(arrayMember(value, 1), ctx); + if (!parsedValue) { + return ParseResult(); + } + return ParseResult(std::make_unique<Within>(*parsedValue)); + } + return ParseResult(); +} + +mbgl::Value Within::serialize() const { + return std::vector<mbgl::Value>{{getOperator()}, {mapbox::geojson::stringify(geoJSONSource)}}; +} + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/properties.hpp b/src/mbgl/style/properties.hpp index 9c8996fcbe..2fab53ad12 100644 --- a/src/mbgl/style/properties.hpp +++ b/src/mbgl/style/properties.hpp @@ -206,6 +206,11 @@ public: } template <class P> + auto evaluate(float z, const GeometryTileFeature& feature, const CanonicalTileID& canonical) const { + return evaluate(z, feature, canonical, this->template get<P>(), P::defaultValue()); + } + + template <class P> auto evaluate(float z, const GeometryTileFeature& feature, const FeatureState& state) const { return evaluate(z, feature, state, this->template get<P>(), P::defaultValue()); } diff --git a/src/mbgl/tile/geometry_tile_data.cpp b/src/mbgl/tile/geometry_tile_data.cpp index f723a94800..838f37f0da 100644 --- a/src/mbgl/tile/geometry_tile_data.cpp +++ b/src/mbgl/tile/geometry_tile_data.cpp @@ -99,7 +99,7 @@ void limitHoles(GeometryCollection& polygon, uint32_t maxHoles) { } } -static Feature::geometry_type convertGeometry(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) { +Feature::geometry_type convertGeometry(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) { const double size = util::EXTENT * std::pow(2, tileID.z); const double x0 = util::EXTENT * static_cast<double>(tileID.x); const double y0 = util::EXTENT * static_cast<double>(tileID.y); diff --git a/src/mbgl/tile/geometry_tile_data.hpp b/src/mbgl/tile/geometry_tile_data.hpp index 49620982c1..a0a069f3d1 100644 --- a/src/mbgl/tile/geometry_tile_data.hpp +++ b/src/mbgl/tile/geometry_tile_data.hpp @@ -80,6 +80,8 @@ std::vector<GeometryCollection> classifyRings(const GeometryCollection&); // Truncate polygon to the largest `maxHoles` inner rings by area. void limitHoles(GeometryCollection&, uint32_t maxHoles); +Feature::geometry_type convertGeometry(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID); + // convert from GeometryTileFeature to Feature (eventually we should eliminate GeometryTileFeature) Feature convertFeature(const GeometryTileFeature&, const CanonicalTileID&); diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index c38464bb04..0729ed2aa5 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -391,7 +391,7 @@ void GeometryTileWorker::parse() { if (layout->hasDependencies()) { layouts.push_back(std::move(layout)); } else { - layout->createBucket({}, featureIndex, renderData, firstLoad, showCollisionBoxes); + layout->createBucket({}, featureIndex, renderData, firstLoad, showCollisionBoxes, id.canonical); } } else { const Filter& filter = leaderImpl.filter; @@ -405,7 +405,7 @@ void GeometryTileWorker::parse() { continue; const GeometryCollection& geometries = feature->getGeometries(); - bucket->addFeature(*feature, geometries, {}, PatternLayerMap(), i); + bucket->addFeature(*feature, geometries, {}, PatternLayerMap(), i, id.canonical); featureIndex->insert(geometries, i, sourceLayerID, leaderImpl.id); } @@ -467,7 +467,8 @@ void GeometryTileWorker::finalizeLayout() { } // layout adds the bucket to buckets - layout->createBucket(iconAtlas.patternPositions, featureIndex, renderData, firstLoad, showCollisionBoxes); + layout->createBucket( + iconAtlas.patternPositions, featureIndex, renderData, firstLoad, showCollisionBoxes, id.canonical); } } |