diff options
author | Lucas Wojciechowski <lucas@lucaswoj.com> | 2018-03-08 15:48:08 -0800 |
---|---|---|
committer | Tobrun <tobrun@mapbox.com> | 2018-03-09 11:12:14 +0100 |
commit | 8a3deab73373c8f3182e4337a3619ebcc58ecc2c (patch) | |
tree | 46774560da0eac1e710dccbf41af2f2e7e8794c4 /src/mbgl/style/conversion | |
parent | 6179110b6bfe8ee0880a055a31c12a88f9bd9b20 (diff) | |
download | qtlocation-mapboxgl-8a3deab73373c8f3182e4337a3619ebcc58ecc2c.tar.gz |
[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<Filter>::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
Diffstat (limited to 'src/mbgl/style/conversion')
-rw-r--r-- | src/mbgl/style/conversion/filter.cpp | 65 | ||||
-rw-r--r-- | src/mbgl/style/conversion/stringify.hpp | 4 |
2 files changed, 63 insertions, 6 deletions
diff --git a/src/mbgl/style/conversion/filter.cpp b/src/mbgl/style/conversion/filter.cpp index bb7bb6ea98..fba149da12 100644 --- a/src/mbgl/style/conversion/filter.cpp +++ b/src/mbgl/style/conversion/filter.cpp @@ -1,11 +1,52 @@ #include <mbgl/style/conversion/filter.hpp> #include <mbgl/util/geometry.hpp> +#include <mbgl/style/expression/expression.hpp> +#include <mbgl/style/expression/type.hpp> +#include <mbgl/style/conversion/expression.hpp> namespace mbgl { namespace style { namespace conversion { + +using GeometryValue = mapbox::geometry::value; -static optional<Value> normalizeValue(const optional<Value>& value, Error& error) { +// This is a port from https://github.com/mapbox/mapbox-gl-js/blob/master/src/style-spec/feature_filter/index.js +static bool isExpressionFilter(const Convertible& filter) { + if (!isArray(filter) || arrayLength(filter) == 0) { + return false; + } + + optional<std::string> op = toString(arrayMember(filter, 0)); + + if (!op) { + return false; + + } else if (*op == "has") { + if (arrayLength(filter) < 2) return false; + optional<std::string> operand = toString(arrayMember(filter, 1)); + return operand && *operand != "$id" && *operand != "$type"; + + } else if (*op == "in" || *op == "!in" || *op == "!has" || *op == "none") { + return false; + + } else if (*op == "==" || *op == "!=" || *op == ">" || *op == ">=" || *op == "<" || *op == "<=") { + return arrayLength(filter) == 3 && (isArray(arrayMember(filter, 1)) || isArray(arrayMember(filter, 2))); + + } else if (*op == "any" || *op == "all") { + for (std::size_t i = 1; i < arrayLength(filter); i++) { + Convertible f = arrayMember(filter, i); + if (!isExpressionFilter(f) && !toBool(f)) { + return false; + } + } + return true; + + } else { + return true; + } +} + +static optional<GeometryValue> normalizeValue(const optional<GeometryValue>& value, Error& error) { if (!value) { error = { "filter expression value must be a boolean, number, or string" }; return {}; @@ -32,7 +73,7 @@ static optional<FeatureType> toFeatureType(const Convertible& value, Error& erro } static optional<FeatureIdentifier> toFeatureIdentifier(const Convertible& value, Error& error) { - optional<Value> identifier = toValue(value); + optional<GeometryValue> identifier = toValue(value); if (!identifier) { error = { "filter expression value must be a boolean, number, or string" }; return {}; @@ -99,7 +140,7 @@ optional<Filter> convertEqualityFilter(const Convertible& value, Error& error) { return { IdentifierFilterType { *filterValue } }; } else { - optional<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); + optional<GeometryValue> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); if (!filterValue) { return {}; } @@ -121,7 +162,7 @@ optional<Filter> convertBinaryFilter(const Convertible& value, Error& error) { return {}; } - optional<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); + optional<GeometryValue> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); if (!filterValue) { return {}; } @@ -167,9 +208,9 @@ optional<Filter> convertSetFilter(const Convertible& value, Error& error) { return { IdentifierFilterType { std::move(values) } }; } else { - std::vector<Value> values; + std::vector<GeometryValue> values; for (std::size_t i = 2; i < arrayLength(value); ++i) { - optional<Value> filterValue = normalizeValue(toValue(arrayMember(value, i)), error); + optional<GeometryValue> filterValue = normalizeValue(toValue(arrayMember(value, i)), error); if (!filterValue) { return {}; } @@ -193,8 +234,20 @@ optional<Filter> convertCompoundFilter(const Convertible& value, Error& error) { return { FilterType { std::move(filters) } }; } + +optional<Filter> convertExpressionFilter(const Convertible& value, Error& error) { + optional<std::unique_ptr<Expression>> expression = convert<std::unique_ptr<Expression>>(value, error, expression::type::Boolean); + if (!expression) { + return {}; + } + return { ExpressionFilter { std::move(*expression) } }; +} optional<Filter> Converter<Filter>::operator()(const Convertible& value, Error& error) const { + if (isExpressionFilter(value)) { + return convertExpressionFilter(value, error); + } + if (!isArray(value)) { error = { "filter expression must be an array" }; return {}; diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp index 6ae6fede42..7924a442c4 100644 --- a/src/mbgl/style/conversion/stringify.hpp +++ b/src/mbgl/style/conversion/stringify.hpp @@ -225,6 +225,10 @@ public: void operator()(const NotHasIdentifierFilter&) { stringifyUnaryFilter("!has", "$id"); } + + void operator()(const ExpressionFilter& filter) { + stringify(writer, filter.expression->serialize()); + } private: template <class F> |