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

[core] Implement image expression #15877

Merged
merged 10 commits into from
Nov 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
pozdnyakov marked this conversation as resolved.
Show resolved Hide resolved
Image(std::string imageID);
alexshalamov marked this conversation as resolved.
Show resolved Hide resolved
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