[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
This commit is contained in:
@@ -12,6 +12,7 @@ namespace conversion {
|
||||
|
||||
bool hasTokens(const std::string&);
|
||||
std::unique_ptr<expression::Expression> convertTokenStringToFormatExpression(const std::string&);
|
||||
std::unique_ptr<expression::Expression> convertTokenStringToImageExpression(const std::string&);
|
||||
std::unique_ptr<expression::Expression> convertTokenStringToExpression(const std::string&);
|
||||
|
||||
optional<std::unique_ptr<expression::Expression>> convertFunctionToExpression(expression::type::Type, const Convertible&, Error&, bool convertTokens);
|
||||
|
||||
@@ -39,6 +39,12 @@ struct Converter<PropertyValue<T>> {
|
||||
? PropertyValue<T>(PropertyExpression<T>(convertTokenStringToFormatExpression(firstUnformattedSection)))
|
||||
: PropertyValue<T>(t);
|
||||
}
|
||||
|
||||
PropertyValue<T> maybeConvertTokens(const expression::Image& image) const {
|
||||
return hasTokens(image.id())
|
||||
? PropertyValue<T>(PropertyExpression<T>(convertTokenStringToImageExpression(image.id())))
|
||||
: PropertyValue<T>(image);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace conversion
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <mbgl/style/color_ramp_property_value.hpp>
|
||||
#include <mbgl/style/conversion.hpp>
|
||||
#include <mbgl/style/expression/image.hpp>
|
||||
#include <mbgl/style/layer.hpp>
|
||||
#include <mbgl/style/property_value.hpp>
|
||||
#include <mbgl/style/transition_options.hpp>
|
||||
|
||||
@@ -49,6 +49,7 @@ std::unique_ptr<Expression> toString(std::unique_ptr<Expression>,
|
||||
std::unique_ptr<Expression> def = nullptr);
|
||||
std::unique_ptr<Expression> toFormatted(std::unique_ptr<Expression>,
|
||||
std::unique_ptr<Expression> def = nullptr);
|
||||
std::unique_ptr<Expression> toImage(std::unique_ptr<Expression>, std::unique_ptr<Expression> def = nullptr);
|
||||
|
||||
std::unique_ptr<Expression> get(const char* value);
|
||||
std::unique_ptr<Expression> get(std::unique_ptr<Expression>);
|
||||
@@ -89,6 +90,9 @@ std::unique_ptr<Expression> concat(std::vector<std::unique_ptr<Expression>> inpu
|
||||
std::unique_ptr<Expression> format(const char* value);
|
||||
std::unique_ptr<Expression> format(std::unique_ptr<Expression>);
|
||||
|
||||
std::unique_ptr<Expression> image(const char* value);
|
||||
std::unique_ptr<Expression> image(std::unique_ptr<Expression>);
|
||||
|
||||
} // namespace dsl
|
||||
} // namespace expression
|
||||
} // namespace style
|
||||
|
||||
@@ -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<mbgl::Value> accumulated_, GeometryTileFeature const * feature_) :
|
||||
accumulated(std::move(accumulated_)), feature(feature_)
|
||||
{}
|
||||
@@ -50,6 +48,11 @@ public:
|
||||
return *this;
|
||||
};
|
||||
|
||||
EvaluationContext& withAvailableImages(const std::set<std::string>* availableImages_) noexcept {
|
||||
availableImages = availableImages_;
|
||||
return *this;
|
||||
};
|
||||
|
||||
optional<float> zoom;
|
||||
optional<mbgl::Value> accumulated;
|
||||
GeometryTileFeature const * feature = nullptr;
|
||||
@@ -57,6 +60,7 @@ public:
|
||||
// Contains formatted section object, std::unordered_map<std::string, Value>.
|
||||
const Value* formattedSection = nullptr;
|
||||
const FeatureState* featureState = nullptr;
|
||||
const std::set<std::string>* availableImages = nullptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -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<float> zoom, const Feature& feature, optional<double> colorRampParameter) const;
|
||||
EvaluationResult evaluate(optional<float> zoom,
|
||||
const Feature& feature,
|
||||
optional<double> colorRampParameter,
|
||||
const std::set<std::string>& availableImages) const;
|
||||
EvaluationResult evaluate(optional<mbgl::Value> 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
|
||||
|
||||
@@ -36,7 +36,7 @@ struct FormattedSection {
|
||||
class Formatted {
|
||||
public:
|
||||
Formatted() = default;
|
||||
|
||||
|
||||
Formatted(const char* plainU8String) {
|
||||
sections.emplace_back(std::string(plainU8String), nullopt, nullopt, nullopt);
|
||||
}
|
||||
|
||||
49
include/mbgl/style/expression/image.hpp
Normal file
49
include/mbgl/style/expression/image.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/conversion.hpp>
|
||||
#include <mbgl/util/color.hpp>
|
||||
#include <mbgl/util/optional.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
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<expression::Image> {
|
||||
public:
|
||||
optional<expression::Image> operator()(const Convertible& value, Error& error) const;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ValueFactory<expression::Image> {
|
||||
static Value make(const expression::Image& image) { return image.toValue(); }
|
||||
};
|
||||
|
||||
} // namespace conversion
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
33
include/mbgl/style/expression/image_expression.hpp
Normal file
33
include/mbgl/style/expression/image_expression.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/expression/expression.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
namespace expression {
|
||||
|
||||
class ParsingContext;
|
||||
|
||||
class ImageExpression final : public Expression {
|
||||
public:
|
||||
explicit ImageExpression(std::unique_ptr<Expression> imageID);
|
||||
|
||||
EvaluationResult evaluate(const EvaluationContext&) const override;
|
||||
static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&);
|
||||
|
||||
void eachChild(const std::function<void(const Expression&)>&) const override;
|
||||
|
||||
bool operator==(const Expression& e) const override;
|
||||
|
||||
std::vector<optional<Value>> possibleOutputs() const override { return {nullopt}; }
|
||||
|
||||
mbgl::Value serialize() const override;
|
||||
std::string getOperator() const override { return "image"; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Expression> imageID;
|
||||
};
|
||||
|
||||
} // namespace expression
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
@@ -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
|
||||
|
||||
@@ -14,65 +14,70 @@ template <class T>
|
||||
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<Array>,
|
||||
CollatorType,
|
||||
FormattedType,
|
||||
ErrorType>;
|
||||
using Type = variant<NullType,
|
||||
NumberType,
|
||||
BooleanType,
|
||||
StringType,
|
||||
ColorType,
|
||||
ObjectType,
|
||||
ValueType,
|
||||
mapbox::util::recursive_wrapper<Array>,
|
||||
CollatorType,
|
||||
FormattedType,
|
||||
ErrorType,
|
||||
ImageType>;
|
||||
|
||||
struct Array {
|
||||
explicit Array(Type itemType_) : itemType(std::move(itemType_)) {}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <mbgl/style/expression/collator.hpp>
|
||||
#include <mbgl/style/expression/formatted.hpp>
|
||||
#include <mbgl/style/expression/image.hpp>
|
||||
#include <mbgl/style/expression/type.hpp>
|
||||
#include <mbgl/style/position.hpp>
|
||||
#include <mbgl/style/types.hpp>
|
||||
@@ -19,16 +20,16 @@ namespace expression {
|
||||
|
||||
struct Value;
|
||||
|
||||
using ValueBase = variant<
|
||||
NullValue,
|
||||
bool,
|
||||
double,
|
||||
std::string,
|
||||
Color,
|
||||
Collator,
|
||||
Formatted,
|
||||
mapbox::util::recursive_wrapper<std::vector<Value>>,
|
||||
mapbox::util::recursive_wrapper<std::unordered_map<std::string, Value>>>;
|
||||
using ValueBase = variant<NullValue,
|
||||
bool,
|
||||
double,
|
||||
std::string,
|
||||
Color,
|
||||
Collator,
|
||||
Formatted,
|
||||
Image,
|
||||
mapbox::util::recursive_wrapper<std::vector<Value>>,
|
||||
mapbox::util::recursive_wrapper<std::unordered_map<std::string, Value>>>;
|
||||
struct Value : ValueBase {
|
||||
using ValueBase::ValueBase;
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@ public:
|
||||
void setBackgroundOpacityTransition(const TransitionOptions&);
|
||||
TransitionOptions getBackgroundOpacityTransition() const;
|
||||
|
||||
static PropertyValue<std::string> getDefaultBackgroundPattern();
|
||||
const PropertyValue<std::string>& getBackgroundPattern() const;
|
||||
void setBackgroundPattern(const PropertyValue<std::string>&);
|
||||
static PropertyValue<expression::Image> getDefaultBackgroundPattern();
|
||||
const PropertyValue<expression::Image>& getBackgroundPattern() const;
|
||||
void setBackgroundPattern(const PropertyValue<expression::Image>&);
|
||||
void setBackgroundPatternTransition(const TransitionOptions&);
|
||||
TransitionOptions getBackgroundPatternTransition() const;
|
||||
|
||||
|
||||
@@ -52,9 +52,9 @@ public:
|
||||
void setFillExtrusionOpacityTransition(const TransitionOptions&);
|
||||
TransitionOptions getFillExtrusionOpacityTransition() const;
|
||||
|
||||
static PropertyValue<std::string> getDefaultFillExtrusionPattern();
|
||||
const PropertyValue<std::string>& getFillExtrusionPattern() const;
|
||||
void setFillExtrusionPattern(const PropertyValue<std::string>&);
|
||||
static PropertyValue<expression::Image> getDefaultFillExtrusionPattern();
|
||||
const PropertyValue<expression::Image>& getFillExtrusionPattern() const;
|
||||
void setFillExtrusionPattern(const PropertyValue<expression::Image>&);
|
||||
void setFillExtrusionPatternTransition(const TransitionOptions&);
|
||||
TransitionOptions getFillExtrusionPatternTransition() const;
|
||||
|
||||
|
||||
@@ -52,9 +52,9 @@ public:
|
||||
void setFillOutlineColorTransition(const TransitionOptions&);
|
||||
TransitionOptions getFillOutlineColorTransition() const;
|
||||
|
||||
static PropertyValue<std::string> getDefaultFillPattern();
|
||||
const PropertyValue<std::string>& getFillPattern() const;
|
||||
void setFillPattern(const PropertyValue<std::string>&);
|
||||
static PropertyValue<expression::Image> getDefaultFillPattern();
|
||||
const PropertyValue<expression::Image>& getFillPattern() const;
|
||||
void setFillPattern(const PropertyValue<expression::Image>&);
|
||||
void setFillPatternTransition(const TransitionOptions&);
|
||||
TransitionOptions getFillPatternTransition() const;
|
||||
|
||||
|
||||
@@ -91,9 +91,9 @@ public:
|
||||
void setLineOpacityTransition(const TransitionOptions&);
|
||||
TransitionOptions getLineOpacityTransition() const;
|
||||
|
||||
static PropertyValue<std::string> getDefaultLinePattern();
|
||||
const PropertyValue<std::string>& getLinePattern() const;
|
||||
void setLinePattern(const PropertyValue<std::string>&);
|
||||
static PropertyValue<expression::Image> getDefaultLinePattern();
|
||||
const PropertyValue<expression::Image>& getLinePattern() const;
|
||||
void setLinePattern(const PropertyValue<expression::Image>&);
|
||||
void setLinePatternTransition(const TransitionOptions&);
|
||||
TransitionOptions getLinePatternTransition() const;
|
||||
|
||||
|
||||
@@ -42,9 +42,9 @@ public:
|
||||
const PropertyValue<bool>& getIconIgnorePlacement() const;
|
||||
void setIconIgnorePlacement(const PropertyValue<bool>&);
|
||||
|
||||
static PropertyValue<std::string> getDefaultIconImage();
|
||||
const PropertyValue<std::string>& getIconImage() const;
|
||||
void setIconImage(const PropertyValue<std::string>&);
|
||||
static PropertyValue<expression::Image> getDefaultIconImage();
|
||||
const PropertyValue<expression::Image>& getIconImage() const;
|
||||
void setIconImage(const PropertyValue<expression::Image>&);
|
||||
|
||||
static PropertyValue<bool> getDefaultIconKeepUpright();
|
||||
const PropertyValue<bool>& getIconKeepUpright() const;
|
||||
|
||||
@@ -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<float>&, const float) const noexcept;
|
||||
Range<float> getCoveringStops(const float, const float) const noexcept;
|
||||
const expression::Expression& getExpression() const noexcept;
|
||||
@@ -28,6 +28,7 @@ protected:
|
||||
variant<std::nullptr_t, const expression::Interpolate*, const expression::Step*> zoomCurve;
|
||||
bool isZoomConstant_;
|
||||
bool isFeatureConstant_;
|
||||
bool isRuntimeConstant_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@@ -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<T> typed = expression::fromExpressionValue<T>(*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<std::string>& 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<std::string>& 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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user