From 9db5832d362fb7f1930d4b182a3fe37af492a9a0 Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Thu, 6 Jul 2017 09:37:46 -0400 Subject: Add base Expression model --- include/mbgl/style/conversion/expression.hpp | 56 +++++++++++++ include/mbgl/style/conversion/function.hpp | 1 + include/mbgl/style/function/expression.hpp | 101 +++++++++++++++++++++++ include/mbgl/style/function/type.hpp | 116 +++++++++++++++++++++++++++ src/mbgl/style/function/expression.cpp | 49 +++++++++++ src/mbgl/style/function/type.cpp | 26 ++++++ 6 files changed, 349 insertions(+) create mode 100644 include/mbgl/style/conversion/expression.hpp create mode 100644 include/mbgl/style/function/expression.hpp create mode 100644 include/mbgl/style/function/type.hpp create mode 100644 src/mbgl/style/function/expression.cpp create mode 100644 src/mbgl/style/function/type.cpp 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 +#include +#include +#include + +namespace mbgl { +namespace style { +namespace conversion { + +using namespace mbgl::style::expression; + +template<> struct Converter> { + template + std::string getJSType(const V& value) const { + if (isUndefined(value)) { + return "undefined"; + } + if (isArray(value) || isObject(value)) { + return "object"; + } + optional v = toValue(value); + assert(v); + return v->match( + [&] (std::string) { return "string"; }, + [&] (bool) { return "boolean"; }, + [&] (auto) { return "number"; } + ); + } + + template + optional> 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& 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("", 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 #include #include +#include #include #include #include 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 +#include +#include +#include +#include +#include +#include + + +namespace mbgl { + +class GeometryTileFeature; + + +namespace style { +namespace expression { + +using OutputValue = variant< + float, + std::string, + mbgl::Color, + std::array, + std::array>; + +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 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 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 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> args_) : + Expression(key, type), + name(name_), + args(std::move(args_)) + {} + +private: + std::string name; + std::vector> 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 +#include +#include + +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, + mapbox::util::recursive_wrapper, + mapbox::util::recursive_wrapper>; + +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 N; +}; + +class Variant { +public: + Variant(std::vector members_) : members(members_) {} + std::string getName() const { + return "variant"; + } + + std::vector getMembers() { + return members; + } + +private: + std::vector members; +}; + +class NArgs { +public: + NArgs(std::vector types_) : types(types_) {} + std::string getName() const { + return "nargs"; + } +private: + std::vector types; +}; + +class Lambda { +public: + Lambda(ValueType result_, std::vector params_) : + result(result_), + params(params_) + {} + std::string getName() const { + return "lambda"; + } +private: + ValueType result; + std::vector 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 +#include + +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 getID() const override { + return feature.id; + } + + GeometryCollection getGeometries() const override { + return {}; + } + + optional getValue(const std::string& key) const override { + auto it = feature.properties.find(key); + if (it != feature.properties.end()) { + return optional(it->second); + } + return optional(); + } +}; + +optional Expression::evaluate(float z, const Feature& feature, Error& error) const { + std::unique_ptr f = std::make_unique(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 + +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 -- cgit v1.2.1