summaryrefslogtreecommitdiff
path: root/src/mbgl/style/conversion
diff options
context:
space:
mode:
authorLucas Wojciechowski <lucas@lucaswoj.com>2018-03-08 15:48:08 -0800
committerTobrun <tobrun@mapbox.com>2018-03-09 11:12:14 +0100
commit8a3deab73373c8f3182e4337a3619ebcc58ecc2c (patch)
tree46774560da0eac1e710dccbf41af2f2e7e8794c4 /src/mbgl/style/conversion
parent6179110b6bfe8ee0880a055a31c12a88f9bd9b20 (diff)
downloadqtlocation-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.cpp65
-rw-r--r--src/mbgl/style/conversion/stringify.hpp4
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>