Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[core] Implement image expression (#15877)
Browse files Browse the repository at this point in the history
* [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
  • Loading branch information
alexshalamov committed Nov 11, 2019
1 parent e1556fc commit c6f3cc8
Show file tree
Hide file tree
Showing 86 changed files with 1,052 additions and 527 deletions.
18 changes: 15 additions & 3 deletions expression-test/expression_test_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,7 @@ optional<Value> toValue(const JSValue& jsvalue) {

style::expression::type::Type stringToType(const std::string& type) {
using namespace style::expression;
if (type == "string"s || type == "number-format"s ||
type == "image"s) { // TODO: replace once we implement image expressions
if (type == "string"s || type == "number-format"s) {
return type::String;
} else if (type == "number"s) {
return type::Number;
Expand All @@ -119,6 +118,8 @@ style::expression::type::Type stringToType(const std::string& type) {
return type::Value;
} else if (type == "formatted"s) {
return type::Formatted;
} else if (type == "resolvedImage"s) {
return type::Image;
}

// Should not reach.
Expand Down Expand Up @@ -253,6 +254,16 @@ bool parseInputs(const JSValue& inputsValue, TestData& data) {
heatmapDensity = evaluationContext["heatmapDensity"].GetDouble();
}

// Parse availableImages
std::set<std::string> availableImages;
if (evaluationContext.HasMember("availableImages")) {
assert(evaluationContext["availableImages"].IsArray());
for (const auto& image : evaluationContext["availableImages"].GetArray()) {
assert(image.IsString());
availableImages.emplace(toString(image));
}
}

// Parse feature properties
Feature feature(mapbox::geometry::point<double>(0.0, 0.0));
const auto& featureObject = input[1].GetObject();
Expand All @@ -271,7 +282,8 @@ bool parseInputs(const JSValue& inputsValue, TestData& data) {
feature.id = mapbox::geojson::convert<mapbox::feature::identifier>(featureObject["id"]);
}

data.inputs.emplace_back(std::move(zoom), std::move(heatmapDensity), std::move(feature));
data.inputs.emplace_back(
std::move(zoom), std::move(heatmapDensity), std::move(availableImages), std::move(feature));
}
return true;
}
Expand Down
10 changes: 8 additions & 2 deletions expression-test/expression_test_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,24 @@
#include <mbgl/util/optional.hpp>
#include <mbgl/util/rapidjson.hpp>

#include <vector>
#include <set>
#include <string>
#include <vector>

using namespace mbgl;

struct Input {
Input(optional<float> zoom_, optional<double> heatmapDensity_, Feature feature_)
Input(optional<float> zoom_,
optional<double> heatmapDensity_,
std::set<std::string> availableImages_,
Feature feature_)
: zoom(std::move(zoom_)),
heatmapDensity(std::move(heatmapDensity_)),
availableImages(std::move(availableImages_)),
feature(std::move(feature_)) {}
optional<float> zoom;
optional<double> heatmapDensity;
std::set<std::string> availableImages;
Feature feature;
};

Expand Down
3 changes: 2 additions & 1 deletion expression-test/expression_test_runner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ TestRunOutput runExpressionTest(TestData& data, const std::string& rootPath, con
std::vector<Value> outputs;
if (!data.inputs.empty()) {
for (const auto& input : data.inputs) {
auto evaluationResult = expression->evaluate(input.zoom, input.feature, input.heatmapDensity);
auto evaluationResult =
expression->evaluate(input.zoom, input.feature, input.heatmapDensity, input.availableImages);
if (!evaluationResult) {
std::unordered_map<std::string, Value> error{{"error", Value{evaluationResult.error().message}}};
outputs.emplace_back(Value{std::move(error)});
Expand Down
1 change: 1 addition & 0 deletions include/mbgl/style/conversion/function.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions include/mbgl/style/conversion/property_value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions include/mbgl/style/conversion_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
4 changes: 4 additions & 0 deletions include/mbgl/style/expression/dsl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>);
Expand Down Expand Up @@ -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
Expand Down
20 changes: 15 additions & 5 deletions include/mbgl/style/expression/expression.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ class EvaluationContext {
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_)
{}
Expand All @@ -50,13 +48,19 @@ class EvaluationContext {
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;
optional<double> colorRampParameter;
// 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>
Expand Down Expand Up @@ -155,7 +159,8 @@ enum class Kind : int32_t {
Comparison,
FormatExpression,
FormatSectionOverride,
NumberFormat
NumberFormat,
ImageExpression
};

class Expression {
Expand All @@ -172,9 +177,14 @@ class Expression {

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
Expand Down
2 changes: 1 addition & 1 deletion include/mbgl/style/expression/formatted.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct FormattedSection {
class Formatted {
public:
Formatted() = default;

Formatted(const char* plainU8String) {
sections.emplace_back(std::string(plainU8String), nullopt, nullopt, nullopt);
}
Expand Down
49 changes: 49 additions & 0 deletions include/mbgl/style/expression/image.hpp
Original file line number Diff line number Diff line change
@@ -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 changes: 33 additions & 0 deletions include/mbgl/style/expression/image_expression.hpp
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions include/mbgl/style/expression/is_constant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit c6f3cc8

Please sign in to comment.