diff options
author | Anand Thakker <github@anandthakker.net> | 2017-07-06 09:37:46 -0400 |
---|---|---|
committer | Anand Thakker <github@anandthakker.net> | 2017-07-06 17:01:50 -0400 |
commit | 9db5832d362fb7f1930d4b182a3fe37af492a9a0 (patch) | |
tree | 9965b1b077e7487b3be406e25efa1d222c494169 | |
parent | e032c15fbe1647803599d3031b9da471aa77a616 (diff) | |
download | qtlocation-mapboxgl-9db5832d362fb7f1930d4b182a3fe37af492a9a0.tar.gz |
Add base Expression model
-rw-r--r-- | include/mbgl/style/conversion/expression.hpp | 56 | ||||
-rw-r--r-- | include/mbgl/style/conversion/function.hpp | 1 | ||||
-rw-r--r-- | include/mbgl/style/function/expression.hpp | 101 | ||||
-rw-r--r-- | include/mbgl/style/function/type.hpp | 116 | ||||
-rw-r--r-- | src/mbgl/style/function/expression.cpp | 49 | ||||
-rw-r--r-- | src/mbgl/style/function/type.cpp | 26 |
6 files changed, 349 insertions, 0 deletions
diff --git a/include/mbgl/style/conversion/expression.hpp b/include/mbgl/style/conversion/expression.hpp new file mode 100644 index 0000000000..d70e3e0b33 --- /dev/null +++ b/include/mbgl/style/conversion/expression.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include <memory> +#include <sstream> +#include <mbgl/style/function/expression.hpp> +#include <mbgl/style/conversion.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +using namespace mbgl::style::expression; + +template<> struct Converter<std::unique_ptr<Expression>> { + template <class V> + std::string getJSType(const V& value) const { + if (isUndefined(value)) { + return "undefined"; + } + if (isArray(value) || isObject(value)) { + return "object"; + } + optional<mbgl::Value> v = toValue(value); + assert(v); + return v->match( + [&] (std::string) { return "string"; }, + [&] (bool) { return "boolean"; }, + [&] (auto) { return "number"; } + ); + } + + template <class V> + optional<std::unique_ptr<Expression>> operator()(const V& value, Error& error) const { + if (isArray(value)) { + if (arrayLength(value) == 0) { + error = { "Expected an array with at least one element. If you wanted a literal array, use [\"literal\", []]." }; + return {}; + } + + const optional<std::string>& op = toString(arrayMember(value, 0)); + if (!op) { + std::ostringstream ss; + ss << "Expression name must be a string, but found " + << getJSType(arrayMember(value, 0)) + << " instead. If you wanted a literal array, use [\"literal\", [...]]."; + error = { ss.str() }; + return {}; + } + } + return {std::make_unique<LiteralExpression>("", 1.0f)}; + } +}; + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp index bf5b27a9a6..d1d0bb709f 100644 --- a/include/mbgl/style/conversion/function.hpp +++ b/include/mbgl/style/conversion/function.hpp @@ -3,6 +3,7 @@ #include <mbgl/style/function/camera_function.hpp> #include <mbgl/style/function/source_function.hpp> #include <mbgl/style/function/composite_function.hpp> +#include <mbgl/style/function/expression.hpp> #include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/constant.hpp> #include <mbgl/util/ignore.hpp> diff --git a/include/mbgl/style/function/expression.hpp b/include/mbgl/style/function/expression.hpp new file mode 100644 index 0000000000..6a25f006df --- /dev/null +++ b/include/mbgl/style/function/expression.hpp @@ -0,0 +1,101 @@ +#pragma once + +#include <array> +#include <vector> +#include <memory> +#include <mbgl/util/optional.hpp> +#include <mbgl/util/color.hpp> +#include <mbgl/style/function/type.hpp> +#include <mbgl/util/feature.hpp> + + +namespace mbgl { + +class GeometryTileFeature; + + +namespace style { +namespace expression { + +using OutputValue = variant< + float, + std::string, + mbgl::Color, + std::array<float, 2>, + std::array<float, 4>>; + +class Error { +public: + Error() {} + Error(std::string message_) : message(message_) {} + std::string message; +}; + +class Expression { +public: + Expression(std::string key_, type::Type type_) : key(key_), type(type_) {} + virtual ~Expression() {} + + virtual optional<OutputValue> evaluate(float, const GeometryTileFeature&, Error& e) const = 0; + + // Exposed for use with pure Feature objects (e.g. beyond the context of tiled map data). + optional<OutputValue> evaluate(float, const Feature&, Error&) const; + + type::Type getType() { + return type; + } + + bool isFeatureConstant() { + return true; + } + + bool isZoomConstant() { + return true; + } + +private: + std::string key; + type::Type type; +}; + +class LiteralExpression : public Expression { +public: + LiteralExpression(std::string key, OutputValue value_) : + Expression(key, value_.match( + [&] (const float&) -> type::Type { return type::Primitive::Number; }, + [&] (const std::string&) { return type::Primitive::String; }, + [&] (const mbgl::Color) { return type::Primitive::Color; }, + [&] (const auto&) { return type::Primitive::Null; } // TODO (remaining output types) + )), + value(value_) + {} + + optional<OutputValue> evaluate(float, const GeometryTileFeature&, Error&) const override { + return {value}; + } + +private: + OutputValue value; +}; + +class LambdaExpression : public Expression { +public: + LambdaExpression(std::string key, + type::Lambda type, + std::string name_, + std::vector<std::unique_ptr<Expression>> args_) : + Expression(key, type), + name(name_), + args(std::move(args_)) + {} + +private: + std::string name; + std::vector<std::unique_ptr<Expression>> args; +}; + + + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/function/type.hpp b/include/mbgl/style/function/type.hpp new file mode 100644 index 0000000000..461c95eb0d --- /dev/null +++ b/include/mbgl/style/function/type.hpp @@ -0,0 +1,116 @@ +#pragma once + +#include <vector> +#include <mbgl/util/optional.hpp> +#include <mbgl/util/variant.hpp> + +namespace mbgl { +namespace style { +namespace expression { +namespace type { + +class Primitive; +class Variant; +class Array; +class NArgs; +class Typename; +class Lambda; + +using ValueType = variant< + Primitive, + Typename, + mapbox::util::recursive_wrapper<Variant>, + mapbox::util::recursive_wrapper<Array>, + mapbox::util::recursive_wrapper<NArgs>>; + +using Type = variant< + Primitive, + Typename, + Variant, + Array, + NArgs, + Lambda>; + +class Primitive { +public: + std::string getName() const { return name; } + + static Primitive Null; + static Primitive Number; + static Primitive String; + static Primitive Color; + static Primitive Object; + + // It's weird for this to be on Primitive. Where should it go? + static Type Value; + +private: + std::string name; + Primitive(std::string name_) : name(name_) {} +}; + +class Typename { +public: + Typename(std::string name_) : name(name_) {} + std::string getName() const { return name; } +private: + std::string name; +}; + +class Array { +public: + Array(ValueType itemType_) : itemType(itemType_) {} + Array(ValueType itemType_, int N_) : itemType(itemType_), N(N_) {} + std::string getName() const { + return "array"; + } + +private: + ValueType itemType; + optional<int> N; +}; + +class Variant { +public: + Variant(std::vector<ValueType> members_) : members(members_) {} + std::string getName() const { + return "variant"; + } + + std::vector<ValueType> getMembers() { + return members; + } + +private: + std::vector<ValueType> members; +}; + +class NArgs { +public: + NArgs(std::vector<ValueType> types_) : types(types_) {} + std::string getName() const { + return "nargs"; + } +private: + std::vector<ValueType> types; +}; + +class Lambda { +public: + Lambda(ValueType result_, std::vector<ValueType> params_) : + result(result_), + params(params_) + {} + std::string getName() const { + return "lambda"; + } +private: + ValueType result; + std::vector<ValueType> params; +}; + + +} // namespace type +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/function/expression.cpp b/src/mbgl/style/function/expression.cpp new file mode 100644 index 0000000000..c620b0bb22 --- /dev/null +++ b/src/mbgl/style/function/expression.cpp @@ -0,0 +1,49 @@ +#include <mbgl/style/function/expression.hpp> +#include <mbgl/tile/geometry_tile_data.hpp> + +namespace mbgl { +namespace style { +namespace expression { + +class GeoJSONFeature : public GeometryTileFeature { +public: + const Feature& feature; + + GeoJSONFeature(const Feature& feature_) + : feature(feature_) { + } + + FeatureType getType() const override { + return apply_visitor(ToFeatureType(), feature.geometry); + } + + PropertyMap getProperties() const override { + return feature.properties; + } + + optional<FeatureIdentifier> getID() const override { + return feature.id; + } + + GeometryCollection getGeometries() const override { + return {}; + } + + optional<Value> getValue(const std::string& key) const override { + auto it = feature.properties.find(key); + if (it != feature.properties.end()) { + return optional<Value>(it->second); + } + return optional<Value>(); + } +}; + +optional<OutputValue> Expression::evaluate(float z, const Feature& feature, Error& error) const { + std::unique_ptr<const GeometryTileFeature> f = std::make_unique<const GeoJSONFeature>(feature); + return this->evaluate(z, *f, error); +} + + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/function/type.cpp b/src/mbgl/style/function/type.cpp new file mode 100644 index 0000000000..fbfe6efbc3 --- /dev/null +++ b/src/mbgl/style/function/type.cpp @@ -0,0 +1,26 @@ +#include <mbgl/style/function/type.hpp> + +namespace mbgl { +namespace style { +namespace expression { +namespace type { + +Primitive Primitive::Null = {"Null"}; +Primitive Primitive::String = {"String"}; +Primitive Primitive::Number = {"Number"}; +Primitive Primitive::Color = {"Color"}; +Primitive Primitive::Object = {"Object"}; + +// Need to add Array(Types::Value) to the member list somehow... +Type Primitive::Value = Variant({ + Primitive::Null, + Primitive::String, + Primitive::Number, + Primitive::Color, + Primitive::Object +}); + +} // namespace type +} // namespace expression +} // namespace style +} // namespace mbgl |