diff options
-rw-r--r-- | include/llmr/map/filter_expression.hpp | 181 | ||||
-rw-r--r-- | include/llmr/map/tile_parser.hpp | 12 | ||||
-rw-r--r-- | include/llmr/map/vector_tile.hpp | 25 | ||||
-rw-r--r-- | include/llmr/style/bucket_description.hpp | 2 | ||||
-rw-r--r-- | include/llmr/style/style_bucket.hpp | 3 | ||||
-rw-r--r-- | include/llmr/style/style_parser.hpp | 9 | ||||
-rw-r--r-- | include/llmr/style/value.hpp | 12 | ||||
-rw-r--r-- | include/llmr/util/recursive_wrapper.hpp | 31 | ||||
-rw-r--r-- | include/llmr/util/variant.hpp | 453 | ||||
-rw-r--r-- | src/map/filter_expression.cpp | 282 | ||||
-rw-r--r-- | src/map/map.cpp | 2 | ||||
-rw-r--r-- | src/map/tile_parser.cpp | 18 | ||||
-rw-r--r-- | src/map/vector_tile.cpp | 199 | ||||
-rw-r--r-- | src/style/style_parser.cpp | 165 |
14 files changed, 974 insertions, 420 deletions
diff --git a/include/llmr/map/filter_expression.hpp b/include/llmr/map/filter_expression.hpp index 50e6ce1d78..3c4ac857e5 100644 --- a/include/llmr/map/filter_expression.hpp +++ b/include/llmr/map/filter_expression.hpp @@ -4,125 +4,114 @@ #include <llmr/style/value.hpp> #include <llmr/util/recursive_wrapper.hpp> -#include <vector> +#include <forward_list> #include <string> +#include <ostream> +#include <iostream> namespace llmr { -enum class FilterOperator { - Equal, - NotEqual, - Greater, - GreaterEqual, - Less, - LessEqual -}; +class VectorTileTagExtractor; -enum class ExpressionOperator { - Or, - And -}; +class FilterComparison { +public: + enum class Operator : uint8_t { + Equal, + NotEqual, + Greater, + GreaterEqual, + Less, + LessEqual, + In, + NotIn + }; + + class Instance { + public: + Instance(Operator op, std::forward_list<Value> &&values) + : op(op), values(values) {} + + bool compare(const Value &property_value) const; + bool compare(const std::forward_list<Value> &property_values) const; + + private: + template <typename Comparer> inline bool includes(const Value &property_value, const Comparer &comparer) const; + template <typename Comparer> inline bool compare(const Value &property_value, const Comparer &comparer) const; + template <typename Comparer> inline bool all(const std::forward_list<Value> &property_values, const Comparer &comparer) const; + + private: + Operator op = Operator::Equal; + std::forward_list<Value> values; + + friend std::ostream& operator <<(std::ostream &, const Instance &); + }; +public: + FilterComparison(const std::string &field) : field(field) {}; -inline FilterOperator filterOperatorType(const std::string &op) { - if (op == "!=" || op == "not") { - return FilterOperator::NotEqual; - } else if (op == "==" || op == "eq") { - return FilterOperator::Equal; - } else if (op == ">" || op == "gt") { - return FilterOperator::Greater; - } else if (op == ">=" || op == "gte") { - return FilterOperator::GreaterEqual; - } else if (op == "<" || op == "lt") { - return FilterOperator::Less; - } else if (op == "<=" || op == "lte") { - return FilterOperator::LessEqual; - } else { - fprintf(stderr, "[WARNING] filter operator '%s' unrecognized\n", op.c_str()); - return FilterOperator::Equal; - } -} + const std::string &getField() const; + inline bool compare(const VectorTileTagExtractor &extractor) const; -inline ExpressionOperator expressionOperatorType(const std::string &op) { - if (op == "&&" || op == "and") { - return ExpressionOperator::And; - } else if (op == "||" || op == "or") { - return ExpressionOperator::Or; - } else { - fprintf(stderr, "[WARNING] expression operator '%s' unrecognized\n", op.c_str()); - return ExpressionOperator::Or; + template <typename ...Args> + inline void add(Args&& ...args) { + instances.emplace_front(::std::forward<Args>(args)...); } -} +private: + std::string field; + std::forward_list<Instance> instances; -class PropertyFilter; -class PropertyExpression; + friend std::ostream& operator <<(std::ostream &, const FilterComparison &); +}; -typedef util::variant< - util::recursive_wrapper<PropertyFilter>, - util::recursive_wrapper<PropertyExpression>, - std::true_type -> PropertyFilterExpression; +std::ostream& operator <<(std::ostream &s, const FilterComparison &comparison); +std::ostream& operator <<(std::ostream &s, const FilterComparison::Instance &instance); -class PropertyFilter { -public: - inline PropertyFilter(const std::string &field, FilterOperator op, const Value &value) : field(field), op(op), value(value) {}; - inline PropertyFilter(PropertyFilter &&filter) - : field(std::move(filter.field)), - op(filter.op), - value(std::move(filter.value)) { - } +FilterComparison::Operator parseFilterComparisonOperator(const std::string &op); - // Returns true if the filter passes, even if the key is missing. - inline bool isMissingFieldOkay() const { - switch (op) { - case FilterOperator::NotEqual: - return true; - default: - return false; - } - } - - inline bool compare(const Value &other) const { - switch (op) { - case FilterOperator::Equal: - return util::relaxed_equal(other, value); - case FilterOperator::NotEqual: - return !util::relaxed_equal(other, value); - case FilterOperator::Greater: - return util::relaxed_greater(other, value); - case FilterOperator::GreaterEqual: - return util::relaxed_greater_equal(other, value); - case FilterOperator::Less: - return util::relaxed_less(other, value); - case FilterOperator::LessEqual: - return util::relaxed_less_equal(other, value); - default: - return false; - } - } +class FilterExpression { public: - std::string field; - FilterOperator op = FilterOperator::Equal; - Value value; -}; + typedef util::recursive_wrapper<FilterExpression> Wrapper; + + enum class Operator : uint8_t { + And, + Or, + Xor, + Nor + }; + + enum class GeometryType : uint8_t { + Any, + Point, + Line, + Polygon + }; -class PropertyExpression { public: - inline PropertyExpression() {} - inline PropertyExpression(PropertyExpression &&expression) - : op(expression.op), - operands(std::move(expression.operands)) { - } + FilterExpression() = default; + FilterExpression(Operator op) : op(op) {}; -public: - ExpressionOperator op = ExpressionOperator::Or; - std::vector<PropertyFilterExpression> operands; + bool empty() const; + + bool compare(const VectorTileTagExtractor &extractor) const; + void add(const FilterComparison &comparison); + void add(const FilterExpression &expression); + void setGeometryType(GeometryType g); + +private: + Operator op = Operator::And; + GeometryType type = GeometryType::Any; + std::forward_list<FilterComparison> comparisons; + std::forward_list<FilterExpression::Wrapper> expressions; + + friend std::ostream& operator <<(std::ostream &, const FilterExpression &); }; +std::ostream& operator <<(std::ostream &s, const FilterExpression &expression); +FilterExpression::GeometryType parseGeometryType(const std::string &geometry); } #endif diff --git a/include/llmr/map/tile_parser.hpp b/include/llmr/map/tile_parser.hpp index 9e763a13af..2809c6b4e7 100644 --- a/include/llmr/map/tile_parser.hpp +++ b/include/llmr/map/tile_parser.hpp @@ -42,13 +42,13 @@ private: void addGlyph(uint64_t tileid, const std::string stackname, const std::u32string &string, const FontStack &fontStack, GlyphAtlas &glyphAtlas, GlyphPositions &face); std::unique_ptr<Bucket> createBucket(std::shared_ptr<StyleBucket> bucket_desc); - std::unique_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketFill &fill); - std::unique_ptr<Bucket> createLineBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketLine &line); - std::unique_ptr<Bucket> createIconBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketIcon &icon); - std::unique_ptr<Bucket> createTextBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketText &text); + std::unique_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill); + std::unique_ptr<Bucket> createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line); + std::unique_ptr<Bucket> createIconBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketIcon &icon); + std::unique_ptr<Bucket> createTextBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketText &text); - template <class Bucket> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter); - template <class Bucket, typename ...Args> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter, Args&& ...args); + template <class Bucket> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter); + template <class Bucket, typename ...Args> void addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter, Args&& ...args); private: const VectorTile vector_data; diff --git a/include/llmr/map/vector_tile.hpp b/include/llmr/map/vector_tile.hpp index b2f3d416e3..f9e01c38b6 100644 --- a/include/llmr/map/vector_tile.hpp +++ b/include/llmr/map/vector_tile.hpp @@ -40,6 +40,22 @@ public: std::ostream& operator<<(std::ostream&, const VectorTileFeature& feature); + +class VectorTileTagExtractor { +public: + VectorTileTagExtractor(const VectorTileLayer &layer); + + void setTags(const pbf &pbf); + std::forward_list<Value> getValues(const std::string &key) const; + void setType(FilterExpression::GeometryType type); + FilterExpression::GeometryType getType() const; + +private: + const VectorTileLayer &layer_; + pbf tags_; + FilterExpression::GeometryType type_ = FilterExpression::GeometryType::Any; +}; + /* * Allows iterating over the features of a VectorTileLayer using a * BucketDescription as filter. Only features matching the descriptions will @@ -55,11 +71,6 @@ public: const pbf& operator*() const; private: - bool matchesFilterExpression(const PropertyFilterExpression &filterExpression, const pbf &tags_pbf); - bool matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf); - bool matchesFilter(const PropertyFilter &filter, const pbf &tags_pbf); - - private: const FilteredVectorTileLayer& parent; bool valid = false; pbf feature; @@ -67,14 +78,14 @@ public: }; public: - FilteredVectorTileLayer(const VectorTileLayer& layer, const PropertyFilterExpression &filterExpression); + FilteredVectorTileLayer(const VectorTileLayer& layer, const FilterExpression &filterExpression); iterator begin() const; iterator end() const; private: const VectorTileLayer& layer; - const PropertyFilterExpression& filterExpression; + const FilterExpression& filterExpression; }; std::ostream& operator<<(std::ostream&, const GlyphPlacement& placement); diff --git a/include/llmr/style/bucket_description.hpp b/include/llmr/style/bucket_description.hpp index 9b1bb5c774..6011b53990 100644 --- a/include/llmr/style/bucket_description.hpp +++ b/include/llmr/style/bucket_description.hpp @@ -22,7 +22,7 @@ public: std::string source_name; std::string source_layer; - PropertyFilterExpression filter = std::true_type(); + FilterExpression filter; // Specifies how the geometry for this bucket should be created StyleBucketRender render; diff --git a/include/llmr/style/style_bucket.hpp b/include/llmr/style/style_bucket.hpp index bd6dcf7147..eee9929a89 100644 --- a/include/llmr/style/style_bucket.hpp +++ b/include/llmr/style/style_bucket.hpp @@ -7,6 +7,7 @@ #include <llmr/util/variant.hpp> #include <memory> +#include <forward_list> namespace llmr { @@ -73,7 +74,7 @@ public: std::string name; std::shared_ptr<Source> source; std::string source_layer; - PropertyFilterExpression filter = std::true_type(); + FilterExpression filter; StyleBucketRender render = std::false_type(); }; diff --git a/include/llmr/style/style_parser.hpp b/include/llmr/style/style_parser.hpp index cdfd61094e..29a41fb141 100644 --- a/include/llmr/style/style_parser.hpp +++ b/include/llmr/style/style_parser.hpp @@ -39,7 +39,6 @@ private: void parseRasterize(JSVal value, std::shared_ptr<StyleLayer> &layer); void parseReference(JSVal value, std::shared_ptr<StyleLayer> &layer); void parseBucket(JSVal value, std::shared_ptr<StyleLayer> &layer); - void parseFilter(JSVal value, std::shared_ptr<StyleLayer> &layer); void parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer); // Parses optional properties into a render bucket. @@ -54,9 +53,11 @@ private: template <typename T> bool parseStyleProperty(const char *property_name, const std::vector<ClassPropertyKey> &keys, ClassProperties &klass, JSVal value); -// PropertyFilterExpression parseFilterOrExpression(JSVal value); -// Value parseValue(JSVal value); -// + + FilterExpression parseFilter(JSVal, FilterExpression::Operator op); + FilterExpression parseFilter(JSVal); + Value parseValue(JSVal value); + std::forward_list<Value> parseValues(JSVal values); private: std::unordered_map<std::string, const rapidjson::Value *> constants; diff --git a/include/llmr/style/value.hpp b/include/llmr/style/value.hpp index 8734386253..bdcba4cad3 100644 --- a/include/llmr/style/value.hpp +++ b/include/llmr/style/value.hpp @@ -62,6 +62,8 @@ template <> struct string_to_number<uint64_t> { template <typename Operator> struct relaxed_operator_visitor { + typedef bool result_type; + bool operator()(bool lhs, bool rhs) const { return Operator()(lhs, rhs); } template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type> @@ -114,23 +116,23 @@ struct relaxed_less_equal_operator { } // end namespace detail inline bool relaxed_equal(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_equal_operator>()); + return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_equal_operator>(), lhs, rhs); } inline bool relaxed_greater(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_greater_operator>()); + return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_greater_operator>(), lhs, rhs); } inline bool relaxed_greater_equal(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_greater_equal_operator>()); + return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_greater_equal_operator>(), lhs, rhs); } inline bool relaxed_less(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_less_operator>()); + return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_less_operator>(), lhs, rhs); } inline bool relaxed_less_equal(Value const &lhs, Value const &rhs) { - return apply_visitor(lhs, rhs, detail::relaxed_operator_visitor<detail::relaxed_less_equal_operator>()); + return apply_visitor(detail::relaxed_operator_visitor<detail::relaxed_less_equal_operator>(), lhs, rhs); } } diff --git a/include/llmr/util/recursive_wrapper.hpp b/include/llmr/util/recursive_wrapper.hpp index 557b576c03..b87dc5699a 100644 --- a/include/llmr/util/recursive_wrapper.hpp +++ b/include/llmr/util/recursive_wrapper.hpp @@ -1,19 +1,15 @@ -#ifndef LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP -#define LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP +#ifndef MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP +#define MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP #include <utility> -namespace llmr { - -namespace util { +namespace llmr { namespace util { template <typename T> class recursive_wrapper { public: - - typedef T type; - + using type = T; private: T* p_; @@ -34,19 +30,19 @@ private: public: - recursive_wrapper& operator=(const recursive_wrapper& rhs) + inline recursive_wrapper& operator=(recursive_wrapper const& rhs) { assign( rhs.get() ); return *this; } - recursive_wrapper& operator=(const T& rhs) + inline recursive_wrapper& operator=(T const& rhs) { assign( rhs ); return *this; } - void swap(recursive_wrapper& operand) noexcept + inline void swap(recursive_wrapper& operand) noexcept { T* temp = operand.p_; operand.p_ = p_; @@ -71,10 +67,10 @@ public: T& get() { return *get_pointer(); } const T& get() const { return *get_pointer(); } - T* get_pointer() { return p_; } const T* get_pointer() const { return p_; } - + operator T const&() const { return this->get(); } + operator T&() { return this->get(); } }; template <typename T> @@ -103,8 +99,9 @@ recursive_wrapper<T>::recursive_wrapper(T const& operand) template <typename T> recursive_wrapper<T>::recursive_wrapper(recursive_wrapper&& operand) - : p_(new T( std::move(operand.get()) )) + : p_(operand.p_) { + operand.p_ = nullptr; } template <typename T> @@ -125,8 +122,6 @@ inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept lhs.swap(rhs); } -} - -} +}} -#endif // LLMR_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP +#endif // MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP diff --git a/include/llmr/util/variant.hpp b/include/llmr/util/variant.hpp index b887ae494d..57f8593439 100644 --- a/include/llmr/util/variant.hpp +++ b/include/llmr/util/variant.hpp @@ -1,5 +1,5 @@ -#ifndef UTIL_VARIANT_HPP -#define UTIL_VARIANT_HPP +#ifndef MAPBOX_UTIL_VARIANT_HPP +#define MAPBOX_UTIL_VARIANT_HPP #include <utility> #include <typeinfo> @@ -9,50 +9,119 @@ #include <new> // operator new #include <cstddef> // size_t #include <iosfwd> +#include <string> -#ifdef NDEBUG -#define VARIANT_INLINE inline __attribute__((always_inline)) +#include "recursive_wrapper.hpp" + +#ifdef _MSC_VER + // http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx + #ifdef NDEBUG + #define VARIANT_INLINE __forceinline + #else + #define VARIANT_INLINE __declspec(noinline) + #endif #else -#define VARIANT_INLINE __attribute__((noinline)) + #ifdef NDEBUG + #define VARIANT_INLINE inline __attribute__((always_inline)) + #else + #define VARIANT_INLINE __attribute__((noinline)) + #endif #endif -namespace llmr { +#define VARIANT_MAJOR_VERSION 0 +#define VARIANT_MINOR_VERSION 1 +#define VARIANT_PATCH_VERSION 0 -namespace util { +// translates to 100 +#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION) -namespace detail { +namespace llmr { namespace util { namespace detail { static constexpr std::size_t invalid_value = std::size_t(-1); template <typename T, typename...Types> -struct type_traits; +struct direct_type; template <typename T, typename First, typename...Types> -struct type_traits<T, First, Types...> +struct direct_type<T, First, Types...> { - static constexpr std::size_t id = std::is_same<T, First>::value ? sizeof...(Types) : type_traits<T, Types...>::id; + static constexpr std::size_t index = std::is_same<T, First>::value + ? sizeof...(Types) : direct_type<T, Types...>::index; }; template <typename T> -struct type_traits<T> +struct direct_type<T> { - static constexpr std::size_t id = invalid_value; + static constexpr std::size_t index = invalid_value; +}; + +template <typename T, typename...Types> +struct convertible_type; + +template <typename T, typename First, typename...Types> +struct convertible_type<T, First, Types...> +{ + static constexpr std::size_t index = std::is_convertible<T, First>::value + ? sizeof...(Types) : convertible_type<T, Types...>::index; +}; + +template <typename T> +struct convertible_type<T> +{ + static constexpr std::size_t index = invalid_value; +}; + +template <typename T, typename...Types> +struct value_traits +{ + static constexpr std::size_t direct_index = direct_type<T, Types...>::index; + static constexpr std::size_t index = + (direct_index == invalid_value) ? convertible_type<T, Types...>::index : direct_index; }; template <typename T, typename...Types> struct is_valid_type; template <typename T, typename First, typename... Types> -struct is_valid_type<T,First,Types...> +struct is_valid_type<T, First, Types...> { - static constexpr bool value = std::is_same<T,First>::value - || is_valid_type<T,Types...>::value; + static constexpr bool value = std::is_convertible<T, First>::value + || is_valid_type<T, Types...>::value; }; template <typename T> struct is_valid_type<T> : std::false_type {}; -} +template <std::size_t N, typename ... Types> +struct select_type +{ + static_assert(N < sizeof...(Types), "index out of bounds"); +}; + +template <std::size_t N, typename T, typename ... Types> +struct select_type<N, T, Types...> +{ + using type = typename select_type<N - 1, Types...>::type; +}; + +template <typename T, typename ... Types> +struct select_type<0, T, Types...> +{ + using type = T; +}; + +} // namespace detail + +// static visitor +template <typename R = void> +struct static_visitor +{ + using result_type = R; +protected: + static_visitor() {} + ~static_visitor() {} +}; + template <std::size_t arg1, std::size_t ... others> struct static_max; @@ -125,37 +194,77 @@ template<> struct variant_helper<> namespace detail { +template <typename T> +struct unwrapper +{ + T const& operator() (T const& obj) const + { + return obj; + } + + T& operator() (T & obj) const + { + return obj; + } +}; + + +template <typename T> +struct unwrapper<recursive_wrapper<T>> +{ + auto operator() (recursive_wrapper<T> const& obj) const + -> typename recursive_wrapper<T>::type const& + { + return obj.get(); + } +}; + + template <typename F, typename V, typename...Types> struct dispatcher; template <typename F, typename V, typename T, typename...Types> -struct dispatcher<F,V,T,Types...> +struct dispatcher<F, V, T, Types...> { - typedef typename std::result_of<F(V const&)>::type result_type; + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& v, F f) + { + if (v.get_type_index() == sizeof...(Types)) + { + return f(unwrapper<T>()(v. template get<T>())); + } + else + { + return dispatcher<F, V, Types...>::apply_const(v, f); + } + } - VARIANT_INLINE static result_type apply(V const& v, F f) + VARIANT_INLINE static result_type apply(V & v, F f) { - if (v.get_type_id() == sizeof...(Types)) + if (v.get_type_index() == sizeof...(Types)) { - return f(v. template get<T>()); + return f(unwrapper<T>()(v. template get<T>())); } else { - return dispatcher<F,V,Types...>::apply(v, f); + return dispatcher<F, V, Types...>::apply(v, f); } } }; -template<typename F,typename V> -struct dispatcher<F,V> +template<typename F, typename V> +struct dispatcher<F, V> { - typedef typename std::result_of<F(V const&)>::type result_type; - - VARIANT_INLINE static result_type apply(V const&, F) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, F) { - throw std::runtime_error("unary dispatch: FAIL"); + throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); } + VARIANT_INLINE static result_type apply(V &, F) + { + throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name()); + } }; @@ -163,28 +272,46 @@ template <typename F, typename V, typename T, typename...Types> struct binary_dispatcher_rhs; template <typename F, typename V, typename T0, typename T1, typename...Types> -struct binary_dispatcher_rhs<F,V,T0,T1,Types...> +struct binary_dispatcher_rhs<F, V, T0, T1, Types...> { - typedef typename std::result_of<F(V const&, V const&)>::type result_type; - VARIANT_INLINE static result_type apply(V const& lhs, V const& rhs, F f) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) + { + if (rhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(unwrapper<T0>()(lhs. template get<T0>()), + unwrapper<T1>()(rhs. template get<T1>())); + } + else + { + return binary_dispatcher_rhs<F, V, T0, Types...>::apply_const(lhs, rhs, f); + } + } + + VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) { - if (rhs.get_type_id() == sizeof...(Types)) // call binary functor + if (rhs.get_type_index() == sizeof...(Types)) // call binary functor { - return f(lhs. template get<T0>(), rhs. template get<T1>()); + return f(unwrapper<T0>()(lhs. template get<T0>()), + unwrapper<T1>()(rhs. template get<T1>())); } else { - return binary_dispatcher_rhs<F,V,T0,Types...>::apply(lhs, rhs, f); + return binary_dispatcher_rhs<F, V, T0, Types...>::apply(lhs, rhs, f); } } + }; -template<typename F,typename V, typename T> -struct binary_dispatcher_rhs<F,V,T> +template<typename F, typename V, typename T> +struct binary_dispatcher_rhs<F, V, T> { - typedef typename std::result_of<F(V const&, V const&)>::type result_type; - - VARIANT_INLINE static result_type apply(V const&, V const&, F) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } + VARIANT_INLINE static result_type apply(V &, V &, F) { throw std::runtime_error("binary dispatch: FAIL"); } @@ -195,28 +322,45 @@ template <typename F, typename V, typename T, typename...Types> struct binary_dispatcher_lhs; template <typename F, typename V, typename T0, typename T1, typename...Types> -struct binary_dispatcher_lhs<F,V,T0,T1,Types...> +struct binary_dispatcher_lhs<F, V, T0, T1, Types...> { - typedef typename std::result_of<F(V const&, V const&)>::type binary_result_type; - VARIANT_INLINE static binary_result_type apply(V const& lhs, V const& rhs, F f) + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f) { - if (lhs.get_type_id() == sizeof...(Types)) // call binary functor + if (lhs.get_type_index() == sizeof...(Types)) // call binary functor { return f(lhs. template get<T1>(), rhs. template get<T0>()); } else { - return binary_dispatcher_lhs<F,V,T0,Types...>::apply(lhs, rhs, f); + return binary_dispatcher_lhs<F, V, T0, Types...>::apply_const(lhs, rhs, f); } } + + VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f) + { + if (lhs.get_type_index() == sizeof...(Types)) // call binary functor + { + return f(lhs. template get<T1>(), rhs. template get<T0>()); + } + else + { + return binary_dispatcher_lhs<F, V, T0, Types...>::apply(lhs, rhs, f); + } + } + }; -template<typename F,typename V, typename T> -struct binary_dispatcher_lhs<F,V,T> +template<typename F, typename V, typename T> +struct binary_dispatcher_lhs<F, V, T> { - typedef typename std::result_of<F(V const&, V const&)>::type result_type; + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } - VARIANT_INLINE static result_type apply(V const&, V const&, F) + VARIANT_INLINE static result_type apply(V &, V &, F) { throw std::runtime_error("binary dispatch: FAIL"); } @@ -226,37 +370,60 @@ template <typename F, typename V, typename...Types> struct binary_dispatcher; template <typename F, typename V, typename T, typename...Types> -struct binary_dispatcher<F,V,T,Types...> +struct binary_dispatcher<F, V, T, Types...> { - typedef typename std::result_of<F(V const&, V const&)>::type binary_result_type; + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f) + { + if (v0.get_type_index() == sizeof...(Types)) + { + if (v0.get_type_index() == v1.get_type_index()) + { + return f(v0. template get<T>(), v1. template get<T>()); // call binary functor + } + else + { + return binary_dispatcher_rhs<F, V, T, Types...>::apply_const(v0, v1, f); + } + } + else if (v1.get_type_index() == sizeof...(Types)) + { + return binary_dispatcher_lhs<F, V, T, Types...>::apply_const(v0, v1, f); + } + return binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f); + } - VARIANT_INLINE static binary_result_type apply(V const& v0, V const& v1, F f) + VARIANT_INLINE static result_type apply(V & v0, V & v1, F f) { - if (v0.get_type_id() == sizeof...(Types)) + if (v0.get_type_index() == sizeof...(Types)) { - if (v0.get_type_id() == v1.get_type_id()) + if (v0.get_type_index() == v1.get_type_index()) { return f(v0. template get<T>(), v1. template get<T>()); // call binary functor } else { - return binary_dispatcher_rhs<F,V,T,Types...>::apply(v0, v1, f); + return binary_dispatcher_rhs<F, V, T, Types...>::apply(v0, v1, f); } } - else if (v1.get_type_id() == sizeof...(Types)) + else if (v1.get_type_index() == sizeof...(Types)) { - return binary_dispatcher_lhs<F,V,T,Types...>::apply(v0, v1, f); + return binary_dispatcher_lhs<F, V, T, Types...>::apply(v0, v1, f); } - return binary_dispatcher<F,V,Types...>::apply(v0, v1, f); + return binary_dispatcher<F, V, Types...>::apply(v0, v1, f); } }; -template<typename F,typename V> -struct binary_dispatcher<F,V> +template<typename F, typename V> +struct binary_dispatcher<F, V> { - typedef typename std::result_of<F(V const&, V const&)>::type binary_result_type; + using result_type = typename F::result_type; + VARIANT_INLINE static result_type apply_const(V const&, V const&, F) + { + throw std::runtime_error("binary dispatch: FAIL"); + } - VARIANT_INLINE static binary_result_type apply(V const&, V const&, F) + VARIANT_INLINE static result_type apply(V &, V &, F) { throw std::runtime_error("binary dispatch: FAIL"); } @@ -275,19 +442,19 @@ struct equal_comp struct less_comp { template <typename T> - bool operator()(const T& lhs, const T& rhs) const + bool operator()(T const& lhs, T const& rhs) const { return lhs < rhs; } }; template <typename Variant, typename Comp> -class comparer +class comparer : public static_visitor<bool> { public: explicit comparer(Variant const& lhs) noexcept : lhs_(lhs) {} - comparer& operator=(const comparer&) = delete; + comparer& operator=(comparer const&) = delete; // visitor template<typename T> bool operator()(T const& rhs_content) const @@ -301,16 +468,16 @@ private: // operator<< helper template <typename Out> -class printer +class printer : public static_visitor<> { public: explicit printer(Out & out) : out_(out) {} - printer& operator=(printer const &) = delete; + printer& operator=(printer const&) = delete; // visitor template <typename T> - void operator()( T const & operand) const + void operator()(T const& operand) const { out_ << operand; } @@ -318,7 +485,7 @@ private: Out & out_; }; -} // detail +} // namespace detail template<typename... Types> class variant @@ -329,81 +496,106 @@ private: static const std::size_t data_align = static_max<alignof(Types)...>::value; using data_type = typename std::aligned_storage<data_size, data_align>::type; - using helper_type = variant_helper<Types...>; - std::size_t type_id; + std::size_t type_index; data_type data; public: VARIANT_INLINE variant() - : type_id(detail::invalid_value) {} + : type_index(sizeof...(Types) - 1) + { + new (&data) typename detail::select_type<0, Types...>::type(); + } - template <typename T> + template <typename T, class = typename std::enable_if< + detail::is_valid_type<T, Types...>::value>::type> VARIANT_INLINE explicit variant(T const& val) noexcept - : type_id(detail::type_traits<T, Types...>::id) + : type_index(detail::value_traits<T, Types...>::index) { - static_assert(detail::is_valid_type<T,Types...>::value, "Not a valid type for this variant"); - new (&data) T(val); + constexpr std::size_t index = sizeof...(Types) - detail::value_traits<T, Types...>::index - 1; + using target_type = typename detail::select_type<index, Types...>::type; + new (&data) target_type(val); } - template <typename T> + template <typename T, class = typename std::enable_if< + detail::is_valid_type<T, Types...>::value>::type> VARIANT_INLINE variant(T && val) noexcept - : type_id(detail::type_traits<T,Types...>::id) + : type_index(detail::value_traits<T, Types...>::index) { - static_assert(detail::is_valid_type<T,Types...>::value, "Not a valid type for this variant"); - new (&data) T(std::forward<T>(val)); // nothrow + constexpr std::size_t index = sizeof...(Types) - detail::value_traits<T, Types...>::index - 1; + using target_type = typename detail::select_type<index, Types...>::type; + new (&data) target_type(std::forward<T>(val)); // nothrow } VARIANT_INLINE variant(variant<Types...> const& old) - : type_id(old.type_id) + : type_index(old.type_index) { - helper_type::copy(old.type_id, &old.data, &data); + helper_type::copy(old.type_index, &old.data, &data); } VARIANT_INLINE variant(variant<Types...>&& old) noexcept - : type_id(old.type_id) + : type_index(old.type_index) { - helper_type::move(old.type_id, &old.data, &data); + helper_type::move(old.type_index, &old.data, &data); } friend void swap(variant<Types...> & first, variant<Types...> & second) { using std::swap; //enable ADL - swap(first.type_id, second.type_id); + swap(first.type_index, second.type_index); swap(first.data, second.data); } - VARIANT_INLINE variant<Types...>& operator= (variant<Types...> other) + VARIANT_INLINE variant<Types...>& operator=(variant<Types...> other) { swap(*this, other); return *this; } + // conversions + // move-assign + template <typename T> + VARIANT_INLINE variant<Types...>& operator=(T && rhs) noexcept + { + variant<Types...> temp(std::move(rhs)); + swap(*this, temp); + return *this; + } + + // copy-assign + template <typename T> + VARIANT_INLINE variant<Types...>& operator=(T const& rhs) + { + variant<Types...> temp(rhs); + swap(*this, temp); + return *this; + } + template<typename T> VARIANT_INLINE bool is() const { - return (type_id == detail::type_traits<T, Types...>::id); + return (type_index == detail::direct_type<T, Types...>::index); } VARIANT_INLINE bool valid() const { - return (type_id != detail::invalid_value); + return (type_index != detail::invalid_value); } template<typename T, typename... Args> VARIANT_INLINE void set(Args&&... args) { - helper_type::destroy(type_id, &data); + helper_type::destroy(type_index, &data); new (&data) T(std::forward<Args>(args)...); - type_id = detail::type_traits<T,Types...>::id; + type_index = detail::direct_type<T, Types...>::index; } template<typename T> VARIANT_INLINE T& get() { - if (type_id == detail::type_traits<T,Types...>::id) + if (type_index == detail::direct_type<T, Types...>::index) { return *reinterpret_cast<T*>(&data); } @@ -416,7 +608,7 @@ public: template<typename T> VARIANT_INLINE T const& get() const { - if (type_id == detail::type_traits<T,Types...>::id) + if (type_index == detail::direct_type<T, Types...>::index) { return *reinterpret_cast<T const*>(&data); } @@ -426,37 +618,57 @@ public: } } - VARIANT_INLINE std::size_t get_type_id() const + VARIANT_INLINE std::size_t get_type_index() const { - return type_id; + return type_index; } // visitor // unary template <typename F, typename V> - typename std::result_of<F(V const&)>::type - VARIANT_INLINE static visit(V const& v, F f) + auto VARIANT_INLINE + static visit(V const& v, F f) + -> decltype(detail::dispatcher<F, V, Types...>::apply_const(v, f)) + { + return detail::dispatcher<F, V, Types...>::apply_const(v, f); + } + // non-const + template <typename F, typename V> + auto VARIANT_INLINE + static visit(V & v, F f) + -> decltype(detail::dispatcher<F, V, Types...>::apply(v, f)) { return detail::dispatcher<F, V, Types...>::apply(v, f); } + // binary + // const + template <typename F, typename V> + auto VARIANT_INLINE + static binary_visit(V const& v0, V const& v1, F f) + -> decltype(detail::binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f)) + { + return detail::binary_dispatcher<F, V, Types...>::apply_const(v0, v1, f); + } + // non-const template <typename F, typename V> - typename std::result_of<F(V const&, V const& )>::type - VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F f) + auto VARIANT_INLINE + static binary_visit(V& v0, V& v1, F f) + -> decltype(detail::binary_dispatcher<F, V, Types...>::apply(v0, v1, f)) { return detail::binary_dispatcher<F, V, Types...>::apply(v0, v1, f); } ~variant() noexcept { - helper_type::destroy(type_id, &data); + helper_type::destroy(type_index, &data); } // comparison operators // equality VARIANT_INLINE bool operator==(variant const& rhs) const { - if (this->get_type_id() != rhs.get_type_id()) + if (this->get_type_index() != rhs.get_type_index()) return false; detail::comparer<variant, detail::equal_comp> visitor(*this); return visit(rhs, visitor); @@ -464,9 +676,9 @@ public: // less than VARIANT_INLINE bool operator<(variant const& rhs) const { - if (this->get_type_id() != rhs.get_type_id()) + if (this->get_type_index() != rhs.get_type_index()) { - return this->get_type_id() < rhs.get_type_id(); + return this->get_type_index() < rhs.get_type_index(); // ^^ borrowed from boost::variant } detail::comparer<variant, detail::less_comp> visitor(*this); @@ -475,17 +687,30 @@ public: }; // unary visitor interface + +// const +template <typename V, typename F> +auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f)) +{ + return V::visit(v, f); +} +// non-const template <typename V, typename F> -typename std::result_of<F(V const&)>::type -VARIANT_INLINE static apply_visitor(V const& v, F f) +auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f)) { - return V::visit(v,f); + return V::visit(v, f); } // binary visitor interface +// const +template <typename V, typename F> +auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f)) +{ + return V::binary_visit(v0, v1, f); +} +// non-const template <typename V, typename F> -typename std::result_of<F(V const&, V const&)>::type -VARIANT_INLINE static apply_visitor(V const& v0, V const& v1, F f) +auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f)) { return V::binary_visit(v0, v1, f); } @@ -493,14 +718,14 @@ VARIANT_INLINE static apply_visitor(V const& v0, V const& v1, F f) // operator<< template <typename charT, typename traits, typename Variant> -VARIANT_INLINE std::basic_ostream<charT,traits>& -operator<< (std::basic_ostream<charT,traits>& out, Variant const& rhs) +VARIANT_INLINE std::basic_ostream<charT, traits>& +operator<< (std::basic_ostream<charT, traits>& out, Variant const& rhs) { - detail::printer<std::basic_ostream<charT,traits> > visitor(out); - apply_visitor(rhs, visitor); + detail::printer<std::basic_ostream<charT, traits>> visitor(out); + apply_visitor(visitor, rhs); return out; } -} -} -#endif // UTIL_VARIANT_HPP +}} + +#endif // MAPBOX_UTIL_VARIANT_HPP diff --git a/src/map/filter_expression.cpp b/src/map/filter_expression.cpp new file mode 100644 index 0000000000..9e293b0026 --- /dev/null +++ b/src/map/filter_expression.cpp @@ -0,0 +1,282 @@ +#include <llmr/map/filter_expression.hpp> +#include <llmr/map/vector_tile.hpp> + +namespace llmr { + + +template <typename Comparer> +inline bool FilterComparison::Instance::includes(const Value &property_value, const Comparer &comparer) const { + for (const Value &filter_value : values) { + if (comparer(property_value, filter_value)) { + return true; + } + } + return false; +} + +template <typename Comparer> +inline bool FilterComparison::Instance::compare(const Value &property_value, const Comparer &comparer) const { + for (const Value &filter_value : values) { + if (!comparer(property_value, filter_value)) { + return false; + } + } + return true; +} + +template <typename Comparer> +inline bool FilterComparison::Instance::all(const std::forward_list<Value> &property_values, const Comparer &comparer) const { + for (const Value &property_value : property_values) { + if (!compare(property_value, comparer)) { + return false; + } + } + return true; +} + + + +bool FilterComparison::Instance::compare(const Value &property_value) const { + switch (op) { + case Operator::Equal: + case Operator::In: + return includes(property_value, util::relaxed_equal); + case Operator::NotEqual: + case Operator::NotIn: + return !includes(property_value, util::relaxed_equal); + case Operator::Greater: + return compare(property_value, util::relaxed_greater); + case Operator::GreaterEqual: + return compare(property_value, util::relaxed_greater_equal); + case Operator::Less: + return compare(property_value, util::relaxed_less); + case Operator::LessEqual: + return compare(property_value, util::relaxed_less_equal); + default: + return false; + } +} + +bool FilterComparison::Instance::compare(const std::forward_list<Value> &property_values) const { + switch (op) { + case Operator::Equal: + for (const Value &property_value : property_values) { + if (!includes(property_value, util::relaxed_equal)) { + return false; + } + } + return true; + case Operator::NotEqual: + for (const Value &property_value : property_values) { + if (includes(property_value, util::relaxed_equal)) { + return false; + } + } + return true; + case Operator::In: + for (const Value &property_value : property_values) { + if (includes(property_value, util::relaxed_equal)) { + return true; + } + } + return false; + case Operator::NotIn: + for (const Value &property_value : property_values) { + if (!includes(property_value, util::relaxed_equal)) { + return true; + } + } + return false; + case Operator::Greater: + return all(property_values, util::relaxed_greater); + case Operator::GreaterEqual: + return all(property_values, util::relaxed_greater_equal); + case Operator::Less: + return all(property_values, util::relaxed_less); + case Operator::LessEqual: + return all(property_values, util::relaxed_less_equal); + } +} + + +const std::string &FilterComparison::getField() const { + return field; +} + +inline bool FilterComparison::compare(const VectorTileTagExtractor &extractor) const { + const std::forward_list<Value> values = extractor.getValues(field); + + // All instances are ANDed together. + for (const Instance &instance : instances) { + if (!instance.compare(values)) { + return false; + } + } + return true; +} + + + +std::ostream& operator <<(std::ostream &s, const FilterComparison &comparison) { + s << "comparison" << std::endl; + for (const FilterComparison::Instance &instance : comparison.instances) { + s << " - " << comparison.field << " " << instance << std::endl; + } + return s; +} + + +std::ostream& operator <<(std::ostream &s, const FilterComparison::Instance &instance) { + switch (instance.op) { + case FilterComparison::Operator::Equal: s << "=="; break; + case FilterComparison::Operator::NotEqual: s << "!="; break; + case FilterComparison::Operator::Greater: s << ">"; break; + case FilterComparison::Operator::GreaterEqual: s << ">="; break; + case FilterComparison::Operator::Less: s << "<"; break; + case FilterComparison::Operator::LessEqual: s << "<="; break; + case FilterComparison::Operator::In: s << "in"; break; + case FilterComparison::Operator::NotIn: s << "!in"; break; + } + + s << " [ "; + for (const Value &value : instance.values) { + s << toString(value) << " "; + } + s << "]"; + return s; +} + + +FilterComparison::Operator parseFilterComparisonOperator(const std::string &op) { + if (op == "==") return FilterComparison::Operator::Equal; + if (op == "!=") return FilterComparison::Operator::NotEqual; + if (op == ">") return FilterComparison::Operator::Greater; + if (op == ">=") return FilterComparison::Operator::GreaterEqual; + if (op == "<") return FilterComparison::Operator::Less; + if (op == "<=") return FilterComparison::Operator::LessEqual; + if (op == "in") return FilterComparison::Operator::In; + if (op == "!in") return FilterComparison::Operator::NotIn; + return FilterComparison::Operator::Equal; +} + + +std::ostream& operator <<(std::ostream &s, FilterExpression::Operator op) { + switch (op) { + case FilterExpression::Operator::And: s << "AND"; break; + case FilterExpression::Operator::Or: s << "OR"; break; + case FilterExpression::Operator::Xor: s << "XOR"; break; + case FilterExpression::Operator::Nor: s << "NOR"; break; + } + return s; +} + + +std::ostream& operator <<(std::ostream &s, FilterExpression::GeometryType type) { + switch (type) { + case FilterExpression::GeometryType::Point: s << "point"; break; + case FilterExpression::GeometryType::Line: s << "line"; break; + case FilterExpression::GeometryType::Polygon: s << "polygon"; break; + case FilterExpression::GeometryType::Any: s << "any"; break; + } + return s; +} + + + +bool FilterExpression::compare(const VectorTileTagExtractor &extractor) const { + if (type != GeometryType::Any && extractor.getType() != type && extractor.getType() != GeometryType::Any) { + return false; + } + + switch (op) { + case Operator::And: + for (const FilterComparison &comparison : comparisons) { + if (!comparison.compare(extractor)) { + return false; + } + } + for (const FilterExpression &expression: expressions) { + if (!expression.compare(extractor)) { + return false; + } + } + return true; + case Operator::Or: + for (const FilterComparison &comparison : comparisons) { + if (comparison.compare(extractor)) { + return true; + } + } + for (const FilterExpression &expression: expressions) { + if (expression.compare(extractor)) { + return true; + } + } + return false; + case Operator::Xor: { + int count = 0; + for (const FilterComparison &comparison : comparisons) { + count += comparison.compare(extractor); + if (count > 1) { + return false; + } + } + for (const FilterExpression &expression: expressions) { + count += expression.compare(extractor); + if (count > 1) { + return false; + } + } + return count == 1; + } + case Operator::Nor: + for (const FilterComparison &comparison : comparisons) { + if (comparison.compare(extractor)) { + return false; + } + } + for (const FilterExpression &expression: expressions) { + if (expression.compare(extractor)) { + return false; + } + } + return true; + default: + return true; + } +} + +bool FilterExpression::empty() const { + return type == GeometryType::Any && comparisons.empty() && expressions.empty(); +} + +void FilterExpression::add(const FilterComparison &comparison) { + comparisons.emplace_front(comparison); +} + +void FilterExpression::add(const FilterExpression &expression) { + expressions.emplace_front(expression); +} + +void FilterExpression::setGeometryType(GeometryType g) { + type = g; +} + +FilterExpression::GeometryType parseGeometryType(const std::string &geometry) { + if (geometry == "point") return FilterExpression::GeometryType::Point; + if (geometry == "line") return FilterExpression::GeometryType::Line; + if (geometry == "polygon") return FilterExpression::GeometryType::Polygon; + return FilterExpression::GeometryType::Any; +} + +std::ostream& operator <<(std::ostream &s, const FilterExpression &expression) { + s << "expression " << expression.op << std::endl; + s << " - $type = " << expression.type << std::endl; + for (const FilterComparison &comparison : expression.comparisons) { + s << comparison; + } + s << "end expression" << std::endl; + return s; +} + +} diff --git a/src/map/map.cpp b/src/map/map.cpp index 01f7ac6072..db94ca97db 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -169,8 +169,6 @@ void Map::setup() { view.make_active(); painter.setup(); - - setStyleJSON(styleJSON); } void Map::setStyleJSON(std::string newStyleJSON) { diff --git a/src/map/tile_parser.cpp b/src/map/tile_parser.cpp index b4041ada4e..e834e6fa95 100644 --- a/src/map/tile_parser.cpp +++ b/src/map/tile_parser.cpp @@ -132,7 +132,7 @@ std::unique_ptr<Bucket> TileParser::createBucket(std::shared_ptr<StyleBucket> bu } template <class Bucket> -void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter) { +void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter) { FilteredVectorTileLayer filtered_layer(layer, filter); for (pbf feature : filtered_layer) { if (obsolete()) @@ -150,7 +150,7 @@ void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, } template <class Bucket, typename... Args> -void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const PropertyFilterExpression &filter, Args&& ...args) { +void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, const FilterExpression &filter, Args&& ...args) { FilteredVectorTileLayer filtered_layer(layer, filter); for (const pbf &feature_pbf : filtered_layer) { if (obsolete()) { @@ -161,25 +161,25 @@ void TileParser::addBucketFeatures(Bucket& bucket, const VectorTileLayer& layer, } -std::unique_ptr<Bucket> TileParser::createFillBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketFill &fill) { +std::unique_ptr<Bucket> TileParser::createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill) { std::unique_ptr<FillBucket> bucket = std::make_unique<FillBucket>(tile.fillVertexBuffer, tile.triangleElementsBuffer, tile.lineElementsBuffer, fill); addBucketFeatures(bucket, layer, filter); return obsolete() ? nullptr : std::move(bucket); } -std::unique_ptr<Bucket> TileParser::createLineBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketLine &line) { +std::unique_ptr<Bucket> TileParser::createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line) { std::unique_ptr<LineBucket> bucket = std::make_unique<LineBucket>(tile.lineVertexBuffer, tile.triangleElementsBuffer, tile.pointElementsBuffer, line); addBucketFeatures(bucket, layer, filter); return obsolete() ? nullptr : std::move(bucket); } -std::unique_ptr<Bucket> TileParser::createIconBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketIcon &icon) { +std::unique_ptr<Bucket> TileParser::createIconBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketIcon &icon) { std::unique_ptr<IconBucket> bucket = std::make_unique<IconBucket>(tile.iconVertexBuffer, icon); addBucketFeatures(bucket, layer, filter, *spriteAtlas); return obsolete() ? nullptr : std::move(bucket); } -std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer& layer, const PropertyFilterExpression &filter, const StyleBucketText &text) { +std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketText &text) { const StyleBucketText &properties = text; @@ -235,9 +235,3 @@ std::unique_ptr<Bucket> TileParser::createTextBucket(const VectorTileLayer& laye return std::move(bucket); } - - - - -//typedef std::pair<uint16_t, uint16_t> GlyphRange; -// diff --git a/src/map/vector_tile.cpp b/src/map/vector_tile.cpp index 24f03e1a97..54a971cd87 100644 --- a/src/map/vector_tile.cpp +++ b/src/map/vector_tile.cpp @@ -102,7 +102,7 @@ VectorTileLayer::VectorTileLayer(pbf layer) : data(layer) { } } -FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const PropertyFilterExpression &filterExpression) +FilteredVectorTileLayer::FilteredVectorTileLayer(const VectorTileLayer& layer, const FilterExpression &filterExpression) : layer(layer), filterExpression(filterExpression) { } @@ -122,120 +122,167 @@ FilteredVectorTileLayer::iterator::iterator(const FilteredVectorTileLayer& paren operator++(); } -bool FilteredVectorTileLayer::iterator::matchesFilterExpression(const PropertyFilterExpression &filterExpression, const pbf &tags_pbf) { - if (filterExpression.is<util::recursive_wrapper<PropertyFilter>>()) { - return matchesFilter(filterExpression.get<util::recursive_wrapper<PropertyFilter>>().get(), tags_pbf); - } else if (filterExpression.is<util::recursive_wrapper<PropertyExpression>>()) { - return matchesExpression(filterExpression.get<util::recursive_wrapper<PropertyExpression>>().get(), tags_pbf); - } else if (filterExpression.is<std::true_type>()) { - return true; - } else { - return false; - } +//bool FilteredVectorTileLayer::iterator::matchesFilterExpression(const FilterExpression &filterExpression, const pbf &tags_pbf) { +// if (filterExpression.empty()) { +// return true; +// } +// +// +// +// +// if (filterExpression.is<util::recursive_wrapper<PropertyFilter>>()) { +// return matchesFilter(filterExpression.get<util::recursive_wrapper<PropertyFilter>>().get(), tags_pbf); +// } else if (filterExpression.is<util::recursive_wrapper<PropertyExpression>>()) { +// return matchesExpression(filterExpression.get<util::recursive_wrapper<PropertyExpression>>().get(), tags_pbf); +// } else if (filterExpression.is<std::true_type>()) { +// return true; +// } else { +// return false; +// } +// return true; +//} + +// +//bool FilteredVectorTileLayer::iterator::matchesFilter(const PropertyFilter &filter, const pbf &const_tags_pbf) { +// auto field_it = parent.layer.key_index.find(filter.field); +// if (field_it != parent.layer.key_index.end()) { +// const uint32_t filter_key = field_it->second; +// +// // Now loop through all the key/value pair tags. +// // tags are packed varints. They should have an even length. +// pbf tags_pbf = const_tags_pbf; +// while (tags_pbf) { +// uint32_t tag_key = tags_pbf.varint(); +// if (!tags_pbf) { +// // This should not happen; otherwise the vector tile +// // is invalid. +// throw std::runtime_error("uneven number of feature tag ids"); +// } +// uint32_t tag_val = tags_pbf.varint(); +// +// if (tag_key == filter_key) { +// if (parent.layer.values.size() > tag_val) { +// const Value &value = parent.layer.values[tag_val]; +// return filter.compare(value); +// } else { +// throw std::runtime_error("feature references out of range value"); +// } +// } +// } +// } +// +// // The feature doesn't contain the field that we're looking to compare. +// // Depending on the filter, this may still be okay. +// return filter.isMissingFieldOkay(); +//} +// +//bool FilteredVectorTileLayer::iterator::matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf) { +// if (expression.op == ExpressionOperator::Or) { +// for (const PropertyFilterExpression &filterExpression : expression.operands) { +// if (matchesFilterExpression(filterExpression, tags_pbf)) { +// return true; +// } +// } +// return false; +// } else if (expression.op == ExpressionOperator::And) { +// for (const PropertyFilterExpression &filterExpression : expression.operands) { +// if (!matchesFilterExpression(filterExpression, tags_pbf)) { +// return false; +// } +// } +// return true; +// } else { +// return false; +// } +//} +// + +VectorTileTagExtractor::VectorTileTagExtractor(const VectorTileLayer &layer) : layer_(layer) {} + + +void VectorTileTagExtractor::setTags(const pbf &pbf) { + tags_ = pbf; } +std::forward_list<Value> VectorTileTagExtractor::getValues(const std::string &key) const { + std::forward_list<Value> values; -bool FilteredVectorTileLayer::iterator::matchesFilter(const PropertyFilter &filter, const pbf &const_tags_pbf) { - auto field_it = parent.layer.key_index.find(filter.field); - if (field_it != parent.layer.key_index.end()) { + auto field_it = layer_.key_index.find(key); + if (field_it != layer_.key_index.end()) { + auto it = values.before_begin(); const uint32_t filter_key = field_it->second; // Now loop through all the key/value pair tags. // tags are packed varints. They should have an even length. - pbf tags_pbf = const_tags_pbf; + pbf tags_pbf = tags_; + uint32_t tag_key, tag_val; while (tags_pbf) { - uint32_t tag_key = tags_pbf.varint(); + tag_key = tags_pbf.varint(); if (!tags_pbf) { - // This should not happen; otherwise the vector tile - // is invalid. - throw std::runtime_error("uneven number of feature tag ids"); + // This should not happen; otherwise the vector tile is invalid. + fprintf(stderr, "[WARNING] uneven number of feature tag ids\n"); + return values; } - uint32_t tag_val = tags_pbf.varint(); + // Note: We need to run this command in all cases, even if the keys don't match. + tag_val = tags_pbf.varint(); if (tag_key == filter_key) { - if (parent.layer.values.size() > tag_val) { - const Value &value = parent.layer.values[tag_val]; - return filter.compare(value); + if (layer_.values.size() > tag_val) { + it = values.emplace_after(it, layer_.values[tag_val]); } else { - throw std::runtime_error("feature references out of range value"); + fprintf(stderr, "[WARNING] feature references out of range value\n"); + break; } } } } - // The feature doesn't contain the field that we're looking to compare. - // Depending on the filter, this may still be okay. - return filter.isMissingFieldOkay(); + return values; } -bool FilteredVectorTileLayer::iterator::matchesExpression(const PropertyExpression &expression, const pbf &tags_pbf) { - if (expression.op == ExpressionOperator::Or) { - for (const PropertyFilterExpression &filterExpression : expression.operands) { - if (matchesFilterExpression(filterExpression, tags_pbf)) { - return true; - } - } - return false; - } else if (expression.op == ExpressionOperator::And) { - for (const PropertyFilterExpression &filterExpression : expression.operands) { - if (!matchesFilterExpression(filterExpression, tags_pbf)) { - return false; - } - } - return true; - } else { - return false; - } +void VectorTileTagExtractor::setType(FilterExpression::GeometryType type) { + type_ = type; } - +FilterExpression::GeometryType VectorTileTagExtractor::getType() const { + return type_; +} void FilteredVectorTileLayer::iterator::operator++() { valid = false; - const PropertyFilterExpression &expression = parent.filterExpression; + const FilterExpression &expression = parent.filterExpression; while (data.next(2)) { // feature feature = data.message(); pbf feature_pbf = feature; - BucketType type = BucketType::None; - bool matched = false; // Treat the absence of any expression filters as a match. - if (!expression.valid() || expression.is<std::true_type>()) { + if (expression.empty()) { matched = true; } - while (feature_pbf.next()) { - if (feature_pbf.tag == 2) { // tags - if (matched) { - // There is no filter, so we want to parse the entire layer anyway. - feature_pbf.skip(); - } else { - // We only want to parse some features. - const pbf tags_pbf = feature_pbf.message(); - matched = matchesFilterExpression(expression, tags_pbf); - if (!matched) { - break; // feature_pbf loop early + if (!matched) { + VectorTileTagExtractor extractor(parent.layer); + + // Retrieve the basic information + while (feature_pbf.next()) { + if (feature_pbf.tag == 2) { // tags + extractor.setTags(feature_pbf.message()); + } else if (feature_pbf.tag == 3) { // geometry type + switch (FeatureType(feature_pbf.varint())) { + case FeatureType::Point: extractor.setType(FilterExpression::GeometryType::Point); break; + case FeatureType::LineString: extractor.setType(FilterExpression::GeometryType::Line); break; + case FeatureType::Polygon: extractor.setType(FilterExpression::GeometryType::Polygon); break; + default: break; } + } else { + feature_pbf.skip(); } - } else if (feature_pbf.tag == 3) { // geometry type - switch (feature_pbf.varint()) { - case 1 /* Point */: type = BucketType::Icon; break; - case 2 /* LineString */: type = BucketType::Line; break; - case 3 /* Polygon */: type = BucketType::Fill; break; - default: type = BucketType::None; break; - } - - // TODO: Parse feature type -// if (type != parent.bucket_desc.feature_type) { -// matched = false; -// break; // feature_pbf loop early -// } - } else { - feature_pbf.skip(); } + + matched = expression.compare(extractor); } if (matched) { diff --git a/src/style/style_parser.cpp b/src/style/style_parser.cpp index 390096e9de..34aa7f2228 100644 --- a/src/style/style_parser.cpp +++ b/src/style/style_parser.cpp @@ -622,7 +622,7 @@ void StyleParser::parseBucket(JSVal value, std::shared_ptr<StyleLayer> &layer) { if (value.HasMember("filter")) { JSVal value_filter = replaceConstant(value["filter"]); - parseFilter(value_filter, layer); + layer->bucket->filter = parseFilter(value_filter); } if (value.HasMember("render")) { @@ -631,8 +631,92 @@ void StyleParser::parseBucket(JSVal value, std::shared_ptr<StyleLayer> &layer) { } } -void StyleParser::parseFilter(JSVal value, std::shared_ptr<StyleLayer> &layer) { - // TODO +FilterExpression StyleParser::parseFilter(JSVal value) { + return parseFilter(value, value.IsArray() ? FilterExpression::Operator::Or : FilterExpression::Operator::And); +} + +FilterExpression StyleParser::parseFilter(JSVal value, FilterExpression::Operator op) { + FilterExpression expression(op); + if (value.IsObject()) { + rapidjson::Value::ConstMemberIterator itr = value.MemberBegin(); + for (; itr != value.MemberEnd(); ++itr) { + const std::string name { itr->name.GetString(), itr->name.GetStringLength() }; + if (name == "&") { + expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::And)); + } else if (name == "|") { + expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::Or)); + } else if (name == "^") { + expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::Xor)); + } else if (name == "!") { + expression.add(parseFilter(replaceConstant(itr->value), FilterExpression::Operator::Nor)); + } else if (name == "$type") { + JSVal type = replaceConstant(itr->value); + if (type.IsString()) { + expression.setGeometryType(parseGeometryType({ type.GetString(), type.GetStringLength() })); + } + } else { + FilterComparison comparison(name); + JSVal filterValue = replaceConstant(itr->value); + if (filterValue.IsObject()) { + rapidjson::Value::ConstMemberIterator itr = filterValue.MemberBegin(); + for (; itr != filterValue.MemberEnd(); ++itr) { + comparison.add( + parseFilterComparisonOperator({ itr->name.GetString(), itr->name.GetStringLength() }), + parseValues(replaceConstant(itr->value)) + ); + } + } else if (filterValue.IsArray()) { + comparison.add(FilterComparison::Operator::In, parseValues(filterValue)); + } else { + comparison.add(FilterComparison::Operator::Equal, std::forward_list<Value>({ parseValue(filterValue) })); + } + expression.add(comparison); + } + } + } else if (value.IsArray()) { + for (rapidjson::SizeType i = 0; i < value.Size(); i++) { + expression.add(parseFilter(replaceConstant(value[i]))); + } + } else { + fprintf(stderr, "[WARNING] expression must be either an array or an object\n"); + } + + return expression; +} + +Value StyleParser::parseValue(JSVal value) { + switch (value.GetType()) { + case rapidjson::kNullType: + case rapidjson::kFalseType: + return false; + + case rapidjson::kTrueType: + return true; + + case rapidjson::kStringType: + return std::string { value.GetString(), value.GetStringLength() }; + + case rapidjson::kNumberType: + if (value.IsUint64()) return value.GetUint64(); + if (value.IsInt64()) return value.GetInt64(); + return value.GetDouble(); + + default: + return false; + } +} + +std::forward_list<Value> StyleParser::parseValues(JSVal value) { + std::forward_list<Value> values; + if (value.IsArray()) { + auto it = values.before_begin(); + for (rapidjson::SizeType i = 0; i < value.Size(); i++) { + it = values.emplace_after(it, parseValue(replaceConstant(value[i]))); + } + } else { + values.emplace_front(parseValue(value)); + } + return values; } void StyleParser::parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer) { @@ -724,79 +808,4 @@ void StyleParser::parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer) { } } -//PropertyFilterExpression StyleParser::parseFilterOrExpression(JSVal value) { -// if (value.IsArray()) { -// // This is an expression. -// util::recursive_wrapper<PropertyExpression> expression; -// for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { -// JSVal filter_item = value[i]; -// -// if (filter_item.IsString()) { -// expression.get().op = expressionOperatorType({ filter_item.GetString(), filter_item.GetStringLength() }); -// } else { -// expression.get().operands.emplace_back(parseFilterOrExpression(filter_item)); -// } -// } -// return std::move(expression); -// } else if (value.IsObject() && value.HasMember("field") && value.HasMember("value")) { -// // This is a filter. -// JSVal field = value["field"]; -// JSVal val = value["value"]; -// -// if (!field.IsString()) { -// throw Style::exception("field name must be a string"); -// } -// -// const std::string field_name { field.GetString(), field.GetStringLength() }; -// const FilterOperator op = [&]{ -// if (value.HasMember("operator")) { -// JSVal op_val = value["operator"]; -// return filterOperatorType({ op_val.GetString(), op_val.GetStringLength() }); -// } else { -// return FilterOperator::Equal; -// } -// }(); -// -// if (val.IsArray()) { -// // The filter has several values, so it's an OR sub-expression. -// util::recursive_wrapper<PropertyExpression> expression; -// for (rapidjson::SizeType i = 0; i < val.Size(); ++i) { -// expression.get().operands.emplace_back(util::recursive_wrapper<PropertyFilter>(PropertyFilter { field_name, op, parseValue(val[i]) })); -// } -// -// return std::move(expression); -// } else { -// // The filter only has a single value, so it is a real filter. -// return std::move(util::recursive_wrapper<PropertyFilter>(PropertyFilter { field_name, op, parseValue(val) })); -// } -// } -// -// return std::true_type(); - -//Value StyleParser::parseValue(JSVal value) { -// switch (value.GetType()) { -// case rapidjson::kNullType: -// case rapidjson::kFalseType: -// return false; -// -// case rapidjson::kTrueType: -// return true; -// -// case rapidjson::kStringType: -// return std::string { value.GetString(), value.GetStringLength() }; -// -// case rapidjson::kNumberType: -// if (value.IsUint64()) return value.GetUint64(); -// if (value.IsInt64()) return value.GetInt64(); -// return value.GetDouble(); -// -// case rapidjson::kObjectType: -// case rapidjson::kArrayType: -// throw Style::exception("value cannot be an object or array"); -// return false; -// } -// throw Style::exception("unhandled value type in style"); -// return false; -//} - } |