From c6f3cc8b60e0cff032020a780d4fd3de1cb2a112 Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Wed, 30 Oct 2019 10:21:17 +0200 Subject: [core] Implement image expression (#15877) * [core] Bump gl-js version * [core] Implement image expression * [core] Use new image expression * [core] Coerce image expression to / from string * [core] Serialize evaluated image * [core] Pass available images to layout * [core] Pass images to evaluation context * [core] Set available flag value based on image availability * [core] Allow image coercion to boolean to indicate image availability * [core] Coalesce image expression * [core] Add image expression to next build system * [core] Align serialization format and evaluated type with gl-js * [core] Add images to expression evaluation method * [core] Add support for Image expression to expression test runner * [core] Unskip image expression tests * [core] Update unit tests * [core] Use image expression in annotation manager * [core] Add string to ImageExpression conversion * [core] Add image expression to expression dsl * [core] Convert tokens for implicitly created Image literal * [core] Fix clang format * [core] Split generated style code lines that are over 120 characters * [core] Add unit test for image expression equality * [core] Add image property expression evaluation unit test * [core] Unskip image expression render test * [core] Skip 'in' expression tests * [core] Ignore fill-pattern/update-feature-state render test * [core] Rename Image::serialize to Image::toValue --- include/mbgl/style/conversion/function.hpp | 1 + include/mbgl/style/conversion/property_value.hpp | 6 +++ include/mbgl/style/conversion_impl.hpp | 1 + include/mbgl/style/expression/dsl.hpp | 4 ++ include/mbgl/style/expression/expression.hpp | 20 ++++++--- include/mbgl/style/expression/formatted.hpp | 2 +- include/mbgl/style/expression/image.hpp | 49 +++++++++++++++++++++ include/mbgl/style/expression/image_expression.hpp | 33 ++++++++++++++ include/mbgl/style/expression/is_constant.hpp | 2 + include/mbgl/style/expression/type.hpp | 50 ++++++++++++---------- include/mbgl/style/expression/value.hpp | 21 ++++----- include/mbgl/style/layers/background_layer.hpp | 6 +-- include/mbgl/style/layers/fill_extrusion_layer.hpp | 6 +-- include/mbgl/style/layers/fill_layer.hpp | 6 +-- include/mbgl/style/layers/line_layer.hpp | 6 +-- include/mbgl/style/layers/symbol_layer.hpp | 6 +-- include/mbgl/style/property_expression.hpp | 24 ++++++++++- 17 files changed, 188 insertions(+), 55 deletions(-) create mode 100644 include/mbgl/style/expression/image.hpp create mode 100644 include/mbgl/style/expression/image_expression.hpp (limited to 'include') diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp index 47ce6843b5..9ceeb979ce 100644 --- a/include/mbgl/style/conversion/function.hpp +++ b/include/mbgl/style/conversion/function.hpp @@ -12,6 +12,7 @@ namespace conversion { bool hasTokens(const std::string&); std::unique_ptr convertTokenStringToFormatExpression(const std::string&); +std::unique_ptr convertTokenStringToImageExpression(const std::string&); std::unique_ptr convertTokenStringToExpression(const std::string&); optional> convertFunctionToExpression(expression::type::Type, const Convertible&, Error&, bool convertTokens); diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp index 9d619f7a02..61360b7440 100644 --- a/include/mbgl/style/conversion/property_value.hpp +++ b/include/mbgl/style/conversion/property_value.hpp @@ -39,6 +39,12 @@ struct Converter> { ? PropertyValue(PropertyExpression(convertTokenStringToFormatExpression(firstUnformattedSection))) : PropertyValue(t); } + + PropertyValue maybeConvertTokens(const expression::Image& image) const { + return hasTokens(image.id()) + ? PropertyValue(PropertyExpression(convertTokenStringToImageExpression(image.id()))) + : PropertyValue(image); + } }; } // namespace conversion diff --git a/include/mbgl/style/conversion_impl.hpp b/include/mbgl/style/conversion_impl.hpp index 3e1b8455e5..73d83302a0 100644 --- a/include/mbgl/style/conversion_impl.hpp +++ b/include/mbgl/style/conversion_impl.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include diff --git a/include/mbgl/style/expression/dsl.hpp b/include/mbgl/style/expression/dsl.hpp index 4abeac7989..347861abc9 100644 --- a/include/mbgl/style/expression/dsl.hpp +++ b/include/mbgl/style/expression/dsl.hpp @@ -49,6 +49,7 @@ std::unique_ptr toString(std::unique_ptr, std::unique_ptr def = nullptr); std::unique_ptr toFormatted(std::unique_ptr, std::unique_ptr def = nullptr); +std::unique_ptr toImage(std::unique_ptr, std::unique_ptr def = nullptr); std::unique_ptr get(const char* value); std::unique_ptr get(std::unique_ptr); @@ -89,6 +90,9 @@ std::unique_ptr concat(std::vector> inpu std::unique_ptr format(const char* value); std::unique_ptr format(std::unique_ptr); +std::unique_ptr image(const char* value); +std::unique_ptr image(std::unique_ptr); + } // namespace dsl } // namespace expression } // namespace style diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index 1341a8d041..9893daa8c4 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -28,9 +28,7 @@ public: EvaluationContext() = default; explicit EvaluationContext(float zoom_) : zoom(zoom_) {} explicit EvaluationContext(GeometryTileFeature const * feature_) : feature(feature_) {} - EvaluationContext(float zoom_, GeometryTileFeature const * feature_) : - zoom(zoom_), feature(feature_) - {} + EvaluationContext(float zoom_, GeometryTileFeature const* feature_) : zoom(zoom_), feature(feature_) {} EvaluationContext(optional accumulated_, GeometryTileFeature const * feature_) : accumulated(std::move(accumulated_)), feature(feature_) {} @@ -50,6 +48,11 @@ public: return *this; }; + EvaluationContext& withAvailableImages(const std::set* availableImages_) noexcept { + availableImages = availableImages_; + return *this; + }; + optional zoom; optional accumulated; GeometryTileFeature const * feature = nullptr; @@ -57,6 +60,7 @@ public: // Contains formatted section object, std::unordered_map. const Value* formattedSection = nullptr; const FeatureState* featureState = nullptr; + const std::set* availableImages = nullptr; }; template @@ -155,7 +159,8 @@ enum class Kind : int32_t { Comparison, FormatExpression, FormatSectionOverride, - NumberFormat + NumberFormat, + ImageExpression }; class Expression { @@ -172,9 +177,14 @@ public: Kind getKind() const { return kind; }; type::Type getType() const { return type; }; - + EvaluationResult evaluate(optional zoom, const Feature& feature, optional colorRampParameter) const; + EvaluationResult evaluate(optional zoom, + const Feature& feature, + optional colorRampParameter, + const std::set& availableImages) const; EvaluationResult evaluate(optional accumulated, const Feature& feature) const; + /** * Statically analyze the expression, attempting to enumerate possible outputs. Returns * an array of values plus the sentinel null optional value, used to indicate that the diff --git a/include/mbgl/style/expression/formatted.hpp b/include/mbgl/style/expression/formatted.hpp index bb3d609c91..09edad240f 100644 --- a/include/mbgl/style/expression/formatted.hpp +++ b/include/mbgl/style/expression/formatted.hpp @@ -36,7 +36,7 @@ struct FormattedSection { class Formatted { public: Formatted() = default; - + Formatted(const char* plainU8String) { sections.emplace_back(std::string(plainU8String), nullopt, nullopt, nullopt); } diff --git a/include/mbgl/style/expression/image.hpp b/include/mbgl/style/expression/image.hpp new file mode 100644 index 0000000000..0bc4794a24 --- /dev/null +++ b/include/mbgl/style/expression/image.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include +#include +#include + +#include +#include + +namespace mbgl { +namespace style { +namespace expression { + +class Image { +public: + Image() = default; + Image(const char* imageID); + Image(std::string imageID); + explicit Image(std::string imageID, bool available); + bool operator==(const Image&) const; + mbgl::Value toValue() const; + const std::string& id() const; + bool isAvailable() const; + bool empty() const; + +private: + std::string imageID; + bool available; +}; + +} // namespace expression + +namespace conversion { + +template <> +struct Converter { +public: + optional operator()(const Convertible& value, Error& error) const; +}; + +template <> +struct ValueFactory { + static Value make(const expression::Image& image) { return image.toValue(); } +}; + +} // namespace conversion + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/expression/image_expression.hpp b/include/mbgl/style/expression/image_expression.hpp new file mode 100644 index 0000000000..cd3d375284 --- /dev/null +++ b/include/mbgl/style/expression/image_expression.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include + +namespace mbgl { +namespace style { +namespace expression { + +class ParsingContext; + +class ImageExpression final : public Expression { +public: + explicit ImageExpression(std::unique_ptr imageID); + + EvaluationResult evaluate(const EvaluationContext&) const override; + static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&); + + void eachChild(const std::function&) const override; + + bool operator==(const Expression& e) const override; + + std::vector> possibleOutputs() const override { return {nullopt}; } + + mbgl::Value serialize() const override; + std::string getOperator() const override { return "image"; } + +private: + std::shared_ptr imageID; +}; + +} // namespace expression +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/expression/is_constant.hpp b/include/mbgl/style/expression/is_constant.hpp index 2861407af0..a9c41e48b1 100644 --- a/include/mbgl/style/expression/is_constant.hpp +++ b/include/mbgl/style/expression/is_constant.hpp @@ -30,6 +30,8 @@ bool isGlobalPropertyConstant(const Expression& expression, const T& properties) bool isFeatureConstant(const Expression& expression); bool isZoomConstant(const Expression& e); +// Returns true if expression does not depend on information provided by the runtime. +bool isRuntimeConstant(const Expression& e); } // namespace expression } // namespace style diff --git a/include/mbgl/style/expression/type.hpp b/include/mbgl/style/expression/type.hpp index a5a1e76164..ab398741f0 100644 --- a/include/mbgl/style/expression/type.hpp +++ b/include/mbgl/style/expression/type.hpp @@ -14,65 +14,70 @@ template std::string toString(const T& t); struct NullType { - constexpr NullType() {}; + constexpr NullType() = default; std::string getName() const { return "null"; } bool operator==(const NullType&) const { return true; } }; struct NumberType { - constexpr NumberType() {}; + constexpr NumberType() = default; std::string getName() const { return "number"; } bool operator==(const NumberType&) const { return true; } }; struct BooleanType { - constexpr BooleanType() {}; + constexpr BooleanType() = default; std::string getName() const { return "boolean"; } bool operator==(const BooleanType&) const { return true; } }; struct StringType { - constexpr StringType() {}; + constexpr StringType() = default; std::string getName() const { return "string"; } bool operator==(const StringType&) const { return true; } }; struct ColorType { - constexpr ColorType() {}; + constexpr ColorType() = default; std::string getName() const { return "color"; } bool operator==(const ColorType&) const { return true; } }; struct ObjectType { - constexpr ObjectType() {}; + constexpr ObjectType() = default; std::string getName() const { return "object"; } bool operator==(const ObjectType&) const { return true; } }; struct ErrorType { - constexpr ErrorType() {}; + constexpr ErrorType() = default; std::string getName() const { return "error"; } bool operator==(const ErrorType&) const { return true; } }; struct ValueType { - constexpr ValueType() {}; + constexpr ValueType() = default; std::string getName() const { return "value"; } bool operator==(const ValueType&) const { return true; } }; struct CollatorType { - constexpr CollatorType() {}; // NOLINT + constexpr CollatorType() = default; std::string getName() const { return "collator"; } bool operator==(const CollatorType&) const { return true; } }; struct FormattedType { - constexpr FormattedType() {}; // NOLINT + constexpr FormattedType() = default; std::string getName() const { return "formatted"; } bool operator==(const FormattedType&) const { return true; } }; +struct ImageType { + constexpr ImageType() = default; + std::string getName() const { return "resolvedImage"; } + bool operator==(const ImageType&) const { return true; } +}; constexpr NullType Null; constexpr NumberType Number; @@ -84,21 +89,22 @@ constexpr ObjectType Object; constexpr CollatorType Collator; constexpr FormattedType Formatted; constexpr ErrorType Error; +constexpr ImageType Image; struct Array; -using Type = variant< - NullType, - NumberType, - BooleanType, - StringType, - ColorType, - ObjectType, - ValueType, - mapbox::util::recursive_wrapper, - CollatorType, - FormattedType, - ErrorType>; +using Type = variant, + CollatorType, + FormattedType, + ErrorType, + ImageType>; struct Array { explicit Array(Type itemType_) : itemType(std::move(itemType_)) {} diff --git a/include/mbgl/style/expression/value.hpp b/include/mbgl/style/expression/value.hpp index 91239d083f..902f5ae209 100644 --- a/include/mbgl/style/expression/value.hpp +++ b/include/mbgl/style/expression/value.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -19,16 +20,16 @@ namespace expression { struct Value; -using ValueBase = variant< - NullValue, - bool, - double, - std::string, - Color, - Collator, - Formatted, - mapbox::util::recursive_wrapper>, - mapbox::util::recursive_wrapper>>; +using ValueBase = variant>, + mapbox::util::recursive_wrapper>>; struct Value : ValueBase { using ValueBase::ValueBase; diff --git a/include/mbgl/style/layers/background_layer.hpp b/include/mbgl/style/layers/background_layer.hpp index ebdce35d0f..bc9d5222fd 100644 --- a/include/mbgl/style/layers/background_layer.hpp +++ b/include/mbgl/style/layers/background_layer.hpp @@ -40,9 +40,9 @@ public: void setBackgroundOpacityTransition(const TransitionOptions&); TransitionOptions getBackgroundOpacityTransition() const; - static PropertyValue getDefaultBackgroundPattern(); - const PropertyValue& getBackgroundPattern() const; - void setBackgroundPattern(const PropertyValue&); + static PropertyValue getDefaultBackgroundPattern(); + const PropertyValue& getBackgroundPattern() const; + void setBackgroundPattern(const PropertyValue&); void setBackgroundPatternTransition(const TransitionOptions&); TransitionOptions getBackgroundPatternTransition() const; diff --git a/include/mbgl/style/layers/fill_extrusion_layer.hpp b/include/mbgl/style/layers/fill_extrusion_layer.hpp index 76c2359617..2996cd0066 100644 --- a/include/mbgl/style/layers/fill_extrusion_layer.hpp +++ b/include/mbgl/style/layers/fill_extrusion_layer.hpp @@ -52,9 +52,9 @@ public: void setFillExtrusionOpacityTransition(const TransitionOptions&); TransitionOptions getFillExtrusionOpacityTransition() const; - static PropertyValue getDefaultFillExtrusionPattern(); - const PropertyValue& getFillExtrusionPattern() const; - void setFillExtrusionPattern(const PropertyValue&); + static PropertyValue getDefaultFillExtrusionPattern(); + const PropertyValue& getFillExtrusionPattern() const; + void setFillExtrusionPattern(const PropertyValue&); void setFillExtrusionPatternTransition(const TransitionOptions&); TransitionOptions getFillExtrusionPatternTransition() const; diff --git a/include/mbgl/style/layers/fill_layer.hpp b/include/mbgl/style/layers/fill_layer.hpp index 9ec33d7e96..90e51c85a3 100644 --- a/include/mbgl/style/layers/fill_layer.hpp +++ b/include/mbgl/style/layers/fill_layer.hpp @@ -52,9 +52,9 @@ public: void setFillOutlineColorTransition(const TransitionOptions&); TransitionOptions getFillOutlineColorTransition() const; - static PropertyValue getDefaultFillPattern(); - const PropertyValue& getFillPattern() const; - void setFillPattern(const PropertyValue&); + static PropertyValue getDefaultFillPattern(); + const PropertyValue& getFillPattern() const; + void setFillPattern(const PropertyValue&); void setFillPatternTransition(const TransitionOptions&); TransitionOptions getFillPatternTransition() const; diff --git a/include/mbgl/style/layers/line_layer.hpp b/include/mbgl/style/layers/line_layer.hpp index 4f2cf53708..33312795d0 100644 --- a/include/mbgl/style/layers/line_layer.hpp +++ b/include/mbgl/style/layers/line_layer.hpp @@ -91,9 +91,9 @@ public: void setLineOpacityTransition(const TransitionOptions&); TransitionOptions getLineOpacityTransition() const; - static PropertyValue getDefaultLinePattern(); - const PropertyValue& getLinePattern() const; - void setLinePattern(const PropertyValue&); + static PropertyValue getDefaultLinePattern(); + const PropertyValue& getLinePattern() const; + void setLinePattern(const PropertyValue&); void setLinePatternTransition(const TransitionOptions&); TransitionOptions getLinePatternTransition() const; diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp index 92e214919a..0ef212a3b9 100644 --- a/include/mbgl/style/layers/symbol_layer.hpp +++ b/include/mbgl/style/layers/symbol_layer.hpp @@ -42,9 +42,9 @@ public: const PropertyValue& getIconIgnorePlacement() const; void setIconIgnorePlacement(const PropertyValue&); - static PropertyValue getDefaultIconImage(); - const PropertyValue& getIconImage() const; - void setIconImage(const PropertyValue&); + static PropertyValue getDefaultIconImage(); + const PropertyValue& getIconImage() const; + void setIconImage(const PropertyValue&); static PropertyValue getDefaultIconKeepUpright(); const PropertyValue& getIconKeepUpright() const; diff --git a/include/mbgl/style/property_expression.hpp b/include/mbgl/style/property_expression.hpp index f68285fb1b..7dcd818dde 100644 --- a/include/mbgl/style/property_expression.hpp +++ b/include/mbgl/style/property_expression.hpp @@ -16,7 +16,7 @@ public: bool isZoomConstant() const noexcept; bool isFeatureConstant() const noexcept; - bool canEvaluateWith(const expression::EvaluationContext&) const noexcept; + bool isRuntimeConstant() const noexcept; float interpolationFactor(const Range&, const float) const noexcept; Range getCoveringStops(const float, const float) const noexcept; const expression::Expression& getExpression() const noexcept; @@ -28,6 +28,7 @@ protected: variant zoomCurve; bool isZoomConstant_; bool isFeatureConstant_; + bool isRuntimeConstant_; }; template @@ -40,7 +41,6 @@ public: } T evaluate(const expression::EvaluationContext& context, T finalDefaultValue = T()) const { - assert(canEvaluateWith(context)); const expression::EvaluationResult result = expression->evaluate(context); if (result) { const optional typed = expression::fromExpressionValue(*result); @@ -50,18 +50,38 @@ public: } T evaluate(float zoom) const { + assert(!isZoomConstant()); + assert(isFeatureConstant()); return evaluate(expression::EvaluationContext(zoom)); } T evaluate(const GeometryTileFeature& feature, T finalDefaultValue) const { + assert(isZoomConstant()); + assert(!isFeatureConstant()); return evaluate(expression::EvaluationContext(&feature), finalDefaultValue); } + T evaluate(const GeometryTileFeature& feature, + const std::set& availableImages, + T finalDefaultValue) const { + return evaluate(expression::EvaluationContext(&feature).withAvailableImages(&availableImages), + finalDefaultValue); + } + T evaluate(float zoom, const GeometryTileFeature& feature, T finalDefaultValue) const { return evaluate(expression::EvaluationContext(zoom, &feature), finalDefaultValue); } + T evaluate(float zoom, + const GeometryTileFeature& feature, + const std::set& availableImages, + T finalDefaultValue) const { + return evaluate(expression::EvaluationContext(zoom, &feature).withAvailableImages(&availableImages), + finalDefaultValue); + } + T evaluate(float zoom, const GeometryTileFeature& feature, const FeatureState& state, T finalDefaultValue) const { + assert(!isFeatureConstant()); return evaluate(expression::EvaluationContext(zoom, &feature, &state), finalDefaultValue); } -- cgit v1.2.1