[core] Convert legacy functions directly to expressions

This commit is contained in:
John Firebaugh
2018-06-29 12:52:08 -07:00
parent bea8f8d177
commit a6727921fc
22 changed files with 777 additions and 1193 deletions

View File

@@ -3,224 +3,15 @@
#include <mbgl/style/function/camera_function.hpp>
#include <mbgl/style/function/source_function.hpp>
#include <mbgl/style/function/composite_function.hpp>
#include <mbgl/style/function/convert.hpp>
#include <mbgl/style/function/categorical_stops.hpp>
#include <mbgl/style/function/exponential_stops.hpp>
#include <mbgl/style/function/interval_stops.hpp>
#include <mbgl/style/function/identity_stops.hpp>
#include <mbgl/style/function/composite_exponential_stops.hpp>
#include <mbgl/style/function/composite_interval_stops.hpp>
#include <mbgl/style/function/composite_categorical_stops.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/util/ignore.hpp>
#include <mbgl/util/variant.hpp>
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/value.hpp>
namespace mbgl {
namespace style {
namespace conversion {
template <class D, class R>
optional<std::map<D, R>> convertStops(const Convertible& value, Error& error) {
auto stopsValue = objectMember(value, "stops");
if (!stopsValue) {
error = { "function value must specify stops" };
return {};
}
if (!isArray(*stopsValue)) {
error = { "function stops must be an array" };
return {};
}
if (arrayLength(*stopsValue) == 0) {
error = { "function must have at least one stop" };
return {};
}
std::map<D, R> stops;
for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) {
const auto& stopValue = arrayMember(*stopsValue, i);
if (!isArray(stopValue)) {
error = { "function stop must be an array" };
return {};
}
if (arrayLength(stopValue) != 2) {
error = { "function stop must have two elements" };
return {};
}
optional<D> d = convert<D>(arrayMember(stopValue, 0), error);
if (!d) {
return {};
}
optional<R> r = convert<R>(arrayMember(stopValue, 1), error);
if (!r) {
return {};
}
stops.emplace(*d, *r);
}
return stops;
}
template <class T>
struct Converter<ExponentialStops<T>> {
static constexpr const char * type = "exponential";
optional<ExponentialStops<T>> operator()(const Convertible& value, Error& error) const {
auto stops = convertStops<float, T>(value, error);
if (!stops) {
return {};
}
auto baseValue = objectMember(value, "base");
if (!baseValue) {
return ExponentialStops<T>(*stops);
}
optional<float> base = toNumber(*baseValue);
if (!base) {
error = { "function base must be a number"};
return {};
}
return ExponentialStops<T>(*stops, *base);
}
};
template <class T>
struct Converter<IntervalStops<T>> {
static constexpr const char * type = "interval";
optional<IntervalStops<T>> operator()(const Convertible& value, Error& error) const {
auto stops = convertStops<float, T>(value, error);
if (!stops) {
return {};
}
return IntervalStops<T>(*stops);
}
};
template <>
struct Converter<CategoricalValue> {
optional<CategoricalValue> operator()(const Convertible& value, Error& error) const {
auto b = toBool(value);
if (b) {
return { *b };
}
auto n = toNumber(value);
if (n) {
return { int64_t(*n) };
}
auto s = toString(value);
if (s) {
return { *s };
}
error = { "stop domain value must be a number, string, or boolean" };
return {};
}
};
template <class T>
struct Converter<CategoricalStops<T>> {
static constexpr const char * type = "categorical";
optional<CategoricalStops<T>> operator()(const Convertible& value, Error& error) const {
auto stops = convertStops<CategoricalValue, T>(value, error);
if (!stops) {
return {};
}
return CategoricalStops<T>(
std::map<CategoricalValue, T>((*stops).begin(), (*stops).end()));
}
};
template <class T>
struct Converter<IdentityStops<T>> {
static constexpr const char * type = "identity";
optional<IdentityStops<T>> operator()(const Convertible&, Error&) const {
return IdentityStops<T>();
}
};
template <class, class>
struct StopsConverter;
template <class T, class... Ts>
struct StopsConverter<T, variant<Ts...>> {
public:
optional<variant<Ts...>> operator()(const Convertible& value, Error& error) const {
std::string type = util::Interpolatable<T>::value ? "exponential" : "interval";
auto typeValue = objectMember(value, "type");
if (typeValue && toString(*typeValue)) {
type = *toString(*typeValue);
}
bool matched = false;
optional<variant<Ts...>> result;
// Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226
auto tryConvert = [&] (auto* tp) {
using Stops = std::decay_t<decltype(*tp)>;
if (type == Converter<Stops>::type) {
matched = true;
optional<Stops> stops = convert<Stops>(value, error);
if (stops) {
result = variant<Ts...>(*stops);
}
}
};
util::ignore({
(tryConvert((Ts*)nullptr), 0)...
});
if (!matched) {
error = { "unsupported function type" };
return {};
}
return result;
}
};
template <class T>
struct Converter<CameraFunction<T>> {
optional<CameraFunction<T>> operator()(const Convertible& value, Error& error) const {
if (!isObject(value)) {
error = { "function must be an object" };
return {};
}
using Stops = std::conditional_t<
util::Interpolatable<T>::value,
variant<
ExponentialStops<T>,
IntervalStops<T>>,
variant<
IntervalStops<T>>>;
auto stops = StopsConverter<T, Stops>()(value, error);
if (!stops) {
return {};
}
return CameraFunction<T>((*stops).match([&] (const auto& s) {
return expression::Convert::toExpression(s);
}), false);
}
};
template <class T>
optional<optional<T>> convertDefaultValue(const Convertible& value, Error& error) {
auto defaultValueValue = objectMember(value, "default");
@@ -237,199 +28,48 @@ optional<optional<T>> convertDefaultValue(const Convertible& value, Error& error
return { *defaultValue };
}
optional<std::unique_ptr<expression::Expression>> convertCameraFunctionToExpression(expression::type::Type, const Convertible&, Error&);
optional<std::unique_ptr<expression::Expression>> convertSourceFunctionToExpression(expression::type::Type, const Convertible&, Error&);
optional<std::unique_ptr<expression::Expression>> convertCompositeFunctionToExpression(expression::type::Type, const Convertible&, Error&);
template <class T>
struct Converter<CameraFunction<T>> {
optional<CameraFunction<T>> operator()(const Convertible& value, Error& error) const {
auto expression = convertCameraFunctionToExpression(expression::valueTypeToExpressionType<T>(), value, error);
if (!expression) {
return {};
}
return CameraFunction<T>(std::move(*expression), false);
}
};
template <class T>
struct Converter<SourceFunction<T>> {
optional<SourceFunction<T>> operator()(const Convertible& value, Error& error) const {
if (!isObject(value)) {
error = { "function must be an object" };
auto expression = convertSourceFunctionToExpression(expression::valueTypeToExpressionType<T>(), value, error);
if (!expression) {
return {};
}
auto propertyValue = objectMember(value, "property");
if (!propertyValue) {
error = { "function must specify property" };
return {};
}
auto propertyString = toString(*propertyValue);
if (!propertyString) {
error = { "function property must be a string" };
return {};
}
using Stops = std::conditional_t<
util::Interpolatable<T>::value,
variant<
ExponentialStops<T>,
IntervalStops<T>,
CategoricalStops<T>,
IdentityStops<T>>,
variant<
IntervalStops<T>,
CategoricalStops<T>,
IdentityStops<T>>>;
auto stops = StopsConverter<T, Stops>()(value, error);
if (!stops) {
return {};
}
auto defaultValue = convertDefaultValue<T>(value, error);
if (!defaultValue) {
return {};
}
return SourceFunction<T>((*stops).match([&] (const auto& s) {
return expression::Convert::toExpression(*propertyString, s);
}), *defaultValue);
}
};
template <class S>
struct CompositeValue : std::pair<float, S> {
using std::pair<float, S>::pair;
};
template <class S>
struct Converter<CompositeValue<S>> {
optional<CompositeValue<S>> operator()(const Convertible& value, Error& error) const {
if (!isObject(value)) {
error = { "stop must be an object" };
return {};
}
auto zoomValue = objectMember(value, "zoom");
if (!zoomValue) {
error = { "stop must specify zoom" };
return {};
}
auto propertyValue = objectMember(value, "value");
if (!propertyValue) {
error = { "stop must specify value" };
return {};
}
optional<float> z = convert<float>(*zoomValue, error);
if (!z) {
return {};
}
optional<S> s = convert<S>(*propertyValue, error);
if (!s) {
return {};
}
return CompositeValue<S> { *z, *s };
}
};
template <class T>
struct Converter<CompositeExponentialStops<T>> {
static constexpr const char * type = "exponential";
optional<CompositeExponentialStops<T>> operator()(const Convertible& value, Error& error) const {
auto stops = convertStops<CompositeValue<float>, T>(value, error);
if (!stops) {
return {};
}
auto base = 1.0f;
auto baseValue = objectMember(value, "base");
if (baseValue && toNumber(*baseValue)) {
base = *toNumber(*baseValue);
}
std::map<float, std::map<float, T>> convertedStops;
for (const auto& stop : *stops) {
convertedStops[stop.first.first].emplace(stop.first.second, stop.second);
}
return CompositeExponentialStops<T>(convertedStops, base);
}
};
template <class T>
struct Converter<CompositeIntervalStops<T>> {
static constexpr const char * type = "interval";
optional<CompositeIntervalStops<T>> operator()(const Convertible& value, Error& error) const {
auto stops = convertStops<CompositeValue<float>, T>(value, error);
if (!stops) {
return {};
}
std::map<float, std::map<float, T>> convertedStops;
for (const auto& stop : *stops) {
convertedStops[stop.first.first].emplace(stop.first.second, stop.second);
}
return CompositeIntervalStops<T>(convertedStops);
}
};
template <class T>
struct Converter<CompositeCategoricalStops<T>> {
static constexpr const char * type = "categorical";
optional<CompositeCategoricalStops<T>> operator()(const Convertible& value, Error& error) const {
auto stops = convertStops<CompositeValue<CategoricalValue>, T>(value, error);
if (!stops) {
return {};
}
std::map<float, std::map<CategoricalValue, T>> convertedStops;
for (const auto& stop : *stops) {
convertedStops[stop.first.first].emplace(stop.first.second, stop.second);
}
return CompositeCategoricalStops<T>(convertedStops);
return SourceFunction<T>(std::move(*expression), *defaultValue);
}
};
template <class T>
struct Converter<CompositeFunction<T>> {
optional<CompositeFunction<T>> operator()(const Convertible& value, Error& error) const {
if (!isObject(value)) {
error = { "function must be an object" };
auto expression = convertCompositeFunctionToExpression(expression::valueTypeToExpressionType<T>(), value, error);
if (!expression) {
return {};
}
auto propertyValue = objectMember(value, "property");
if (!propertyValue) {
error = { "function must specify property" };
return {};
}
auto propertyString = toString(*propertyValue);
if (!propertyString) {
error = { "function property must be a string" };
return {};
}
using Stops = std::conditional_t<
util::Interpolatable<T>::value,
variant<
CompositeExponentialStops<T>,
CompositeIntervalStops<T>,
CompositeCategoricalStops<T>>,
variant<
CompositeIntervalStops<T>,
CompositeCategoricalStops<T>>>;
auto stops = StopsConverter<T, Stops>()(value, error);
if (!stops) {
return {};
}
auto defaultValue = convertDefaultValue<T>(value, error);
if (!defaultValue) {
return {};
}
return CompositeFunction<T>((*stops).match([&] (const auto& s) {
return expression::Convert::toExpression(*propertyString, s);
}), *defaultValue);
return CompositeFunction<T>(std::move(*expression), *defaultValue);
}
};

View File

@@ -9,6 +9,7 @@
#include <mbgl/style/expression/is_expression.hpp>
#include <mbgl/style/expression/find_zoom_curve.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/expression/literal.hpp>
namespace mbgl {
namespace style {

View File

@@ -5,6 +5,7 @@
#include <mbgl/style/expression/interpolator.hpp>
#include <memory>
#include <string>
#include <initializer_list>
namespace mbgl {
@@ -15,6 +16,8 @@ namespace dsl {
// This convenience API does little to no expression validation or type-checking, and is intended for
// use only by test and other non-production code.
std::unique_ptr<Expression> error(std::string);
std::unique_ptr<Expression> literal(const char* value);
std::unique_ptr<Expression> literal(Value value);
std::unique_ptr<Expression> literal(std::initializer_list<double> value);
@@ -22,6 +25,7 @@ std::unique_ptr<Expression> literal(std::initializer_list<const char *> value);
std::unique_ptr<Expression> number(std::unique_ptr<Expression>);
std::unique_ptr<Expression> string(std::unique_ptr<Expression>);
std::unique_ptr<Expression> boolean(std::unique_ptr<Expression>);
std::unique_ptr<Expression> toColor(const char* value);
std::unique_ptr<Expression> toColor(std::unique_ptr<Expression>);

View File

@@ -0,0 +1,39 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
#include <string>
namespace mbgl {
namespace style {
namespace expression {
class Error : public Expression {
public:
Error(std::string message_)
: Expression(type::Error),
message(std::move(message_)) {}
void eachChild(const std::function<void(const Expression&)>&) const override {}
bool operator==(const Expression& e) const override {
return dynamic_cast<const Error*>(&e);
}
EvaluationResult evaluate(const EvaluationContext&) const override {
return EvaluationError{message};
}
std::vector<optional<Value>> possibleOutputs() const override {
return {};
}
std::string getOperator() const override { return "error"; }
private:
std::string message;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -1,40 +0,0 @@
#pragma once
#include <mbgl/util/feature.hpp>
#include <mbgl/util/variant.hpp>
#include <cassert>
#include <utility>
#include <map>
namespace mbgl {
namespace style {
class CategoricalValue : public variant<bool, int64_t, std::string> {
public:
using variant<bool, int64_t, std::string>::variant;
};
template <class T>
class CategoricalStops {
public:
using Stops = std::map<CategoricalValue, T>;
Stops stops;
CategoricalStops() = default;
CategoricalStops(Stops stops_)
: stops(std::move(stops_)) {
assert(stops.size() > 0);
}
optional<T> evaluate(const Value&) const;
friend bool operator==(const CategoricalStops& lhs,
const CategoricalStops& rhs) {
return lhs.stops == rhs.stops;
}
};
} // namespace style
} // namespace mbgl

View File

@@ -1,30 +0,0 @@
#pragma once
#include <mbgl/style/function/categorical_stops.hpp>
namespace mbgl {
namespace style {
template <class T>
class CompositeCategoricalStops {
public:
using Stops = std::map<float, std::map<CategoricalValue, T>>;
Stops stops;
CompositeCategoricalStops() = default;
CompositeCategoricalStops(Stops stops_)
: stops(std::move(stops_)) {
}
CategoricalStops<T> innerStops(const std::map<CategoricalValue, T>& stops_) const {
return CategoricalStops<T>(stops_);
}
friend bool operator==(const CompositeCategoricalStops& lhs,
const CompositeCategoricalStops& rhs) {
return lhs.stops == rhs.stops;
}
};
} // namespace style
} // namespace mbgl

View File

@@ -1,35 +0,0 @@
#pragma once
#include <mbgl/style/function/exponential_stops.hpp>
#include <map>
namespace mbgl {
namespace style {
template <class T>
class CompositeExponentialStops {
public:
using Stops = std::map<float, std::map<float, T>>;
Stops stops;
float base = 1.0f;
CompositeExponentialStops() = default;
CompositeExponentialStops(Stops stops_, float base_ = 1.0f)
: stops(std::move(stops_)),
base(base_) {
}
ExponentialStops<T> innerStops(const std::map<float, T>& stops_) const {
return ExponentialStops<T>(stops_, base);
}
friend bool operator==(const CompositeExponentialStops& lhs,
const CompositeExponentialStops& rhs) {
return lhs.stops == rhs.stops && lhs.base == rhs.base;
}
};
} // namespace style
} // namespace mbgl

View File

@@ -1,32 +0,0 @@
#pragma once
#include <mbgl/style/function/interval_stops.hpp>
#include <map>
namespace mbgl {
namespace style {
template <class T>
class CompositeIntervalStops {
public:
using Stops = std::map<float, std::map<float, T>>;
Stops stops;
CompositeIntervalStops() = default;
CompositeIntervalStops(Stops stops_)
: stops(std::move(stops_)) {
}
IntervalStops<T> innerStops(const std::map<float, T>& stops_) const {
return IntervalStops<T>(stops_);
}
friend bool operator==(const CompositeIntervalStops& lhs,
const CompositeIntervalStops& rhs) {
return lhs.stops == rhs.stops;
}
};
} // namespace style
} // namespace mbgl

View File

@@ -1,322 +0,0 @@
#pragma once
#include <mbgl/style/expression/array_assertion.hpp>
#include <mbgl/style/expression/assertion.hpp>
#include <mbgl/style/expression/case.hpp>
#include <mbgl/style/expression/coalesce.hpp>
#include <mbgl/style/expression/compound_expression.hpp>
#include <mbgl/style/expression/coercion.hpp>
#include <mbgl/style/expression/interpolate.hpp>
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/literal.hpp>
#include <mbgl/style/expression/match.hpp>
#include <mbgl/style/expression/step.hpp>
#include <mbgl/style/function/exponential_stops.hpp>
#include <mbgl/style/function/interval_stops.hpp>
#include <mbgl/style/function/categorical_stops.hpp>
#include <mbgl/style/function/composite_exponential_stops.hpp>
#include <mbgl/style/function/composite_interval_stops.hpp>
#include <mbgl/style/function/composite_categorical_stops.hpp>
#include <mbgl/style/function/identity_stops.hpp>
#include <mbgl/util/enum.hpp>
#include <mbgl/style/types.hpp>
#include <string>
namespace mbgl {
namespace style {
namespace expression {
namespace detail {
class ErrorExpression : public Expression {
public:
ErrorExpression(std::string message_) : Expression(type::Error), message(std::move(message_)) {}
void eachChild(const std::function<void(const Expression&)>&) const override {}
bool operator==(const Expression& e) const override {
return dynamic_cast<const ErrorExpression*>(&e);
}
EvaluationResult evaluate(const EvaluationContext&) const override {
return EvaluationError{message};
}
std::vector<optional<Value>> possibleOutputs() const override {
return {};
}
std::string getOperator() const override { return "error"; }
private:
std::string message;
};
} // namespace detail
// Create expressions representing 'classic' (i.e. stop-based) style functions
struct Convert {
template <typename T>
static std::unique_ptr<Literal> makeLiteral(const T& value) {
return std::make_unique<Literal>(Value(toExpressionValue(value)));
}
static std::unique_ptr<Expression> makeGet(type::Type type, const std::string& property) {
ParsingContext ctx;
std::vector<std::unique_ptr<Expression>> getArgs;
getArgs.push_back(makeLiteral(property));
ParseResult get = createCompoundExpression("get", std::move(getArgs), ctx);
assert(get);
assert(ctx.getErrors().size() == 0);
std::vector<std::unique_ptr<Expression>> assertionArgs;
assertionArgs.push_back(std::move(*get));
return std::make_unique<Assertion>(type, std::move(assertionArgs));
}
static std::unique_ptr<Expression> makeZoom() {
ParsingContext ctx;
ParseResult zoom = createCompoundExpression("zoom", std::vector<std::unique_ptr<Expression>>(), ctx);
assert(zoom);
assert(ctx.getErrors().size() == 0);
return std::move(*zoom);
}
static std::unique_ptr<Expression> makeError(std::string message) {
return std::make_unique<detail::ErrorExpression>(message);
}
template <typename Key>
static ParseResult makeMatch(type::Type type,
std::unique_ptr<Expression> input,
std::map<CategoricalValue, std::unique_ptr<Expression>> stops) {
// match expression
typename Match<Key>::Branches branches;
for(auto it = stops.begin(); it != stops.end(); it++) {
assert(it->first.template is<Key>());
Key key = it->first.template get<Key>();
branches.emplace(
std::move(key),
std::move(it->second)
);
}
return ParseResult(std::make_unique<Match<Key>>(std::move(type),
std::move(input),
std::move(branches),
makeError("No matching label")));
}
static ParseResult makeCase(type::Type type,
std::unique_ptr<Expression> input,
std::map<CategoricalValue, std::unique_ptr<Expression>> stops) {
// case expression
std::vector<typename Case::Branch> branches;
auto it = stops.find(true);
std::unique_ptr<Expression> true_case = it == stops.end() ?
makeError("No matching label") :
std::move(it->second);
it = stops.find(false);
std::unique_ptr<Expression> false_case = it == stops.end() ?
makeError("No matching label") :
std::move(it->second);
branches.push_back(std::make_pair(std::move(input), std::move(true_case)));
return ParseResult(std::make_unique<Case>(std::move(type), std::move(branches), std::move(false_case)));
}
template <typename T>
static ParseResult fromCategoricalStops(std::map<CategoricalValue, T> stops, const std::string& property) {
assert(stops.size() > 0);
std::map<CategoricalValue, std::unique_ptr<Expression>> convertedStops;
for(const std::pair<CategoricalValue, T>& stop : stops) {
convertedStops.emplace(
stop.first,
makeLiteral(stop.second)
);
}
type::Type type = valueTypeToExpressionType<T>();
const CategoricalValue& firstKey = stops.begin()->first;
return firstKey.match(
[&](bool) {
return makeCase(type, makeGet(type::Boolean, property), std::move(convertedStops));
},
[&](const std::string&) {
return makeMatch<std::string>(type, makeGet(type::String, property), std::move(convertedStops));
},
[&](int64_t) {
return makeMatch<int64_t>(type, makeGet(type::Number, property), std::move(convertedStops));
}
);
}
template <typename T>
static std::map<double, std::unique_ptr<Expression>> convertStops(const std::map<float, T>& stops) {
std::map<double, std::unique_ptr<Expression>> convertedStops;
for(const auto& stop : stops) {
convertedStops.emplace(
stop.first,
makeLiteral(stop.second)
);
}
return convertedStops;
}
template <typename T>
static std::unique_ptr<Expression> toExpression(const ExponentialStops<T>& stops)
{
ParsingContext ctx;
ParseResult e = createInterpolate(valueTypeToExpressionType<T>(),
ExponentialInterpolator(stops.base),
makeZoom(),
convertStops(stops.stops),
ctx);
assert(e);
return std::move(*e);
}
template <typename T>
static std::unique_ptr<Expression> toExpression(const IntervalStops<T>& stops)
{
ParseResult e(std::make_unique<Step>(valueTypeToExpressionType<T>(),
makeZoom(),
convertStops(stops.stops)));
assert(e);
return std::move(*e);
}
template <typename T>
static std::unique_ptr<Expression> toExpression(const std::string& property,
const ExponentialStops<T>& stops)
{
ParsingContext ctx;
ParseResult e = createInterpolate(valueTypeToExpressionType<T>(),
ExponentialInterpolator(stops.base),
makeGet(type::Number, property),
convertStops(stops.stops),
ctx);
assert(e);
return std::move(*e);
}
template <typename T>
static std::unique_ptr<Expression> toExpression(const std::string& property,
const IntervalStops<T>& stops)
{
std::unique_ptr<Expression> get = makeGet(type::Number, property);
ParseResult e(std::make_unique<Step>(valueTypeToExpressionType<T>(),
std::move(get),
convertStops(stops.stops)));
assert(e);
return std::move(*e);
}
template <typename T>
static std::unique_ptr<Expression> toExpression(const std::string& property,
const CategoricalStops<T>& stops)
{
ParseResult expr = fromCategoricalStops(stops.stops, property);
assert(expr);
return std::move(*expr);
}
// interpolatable zoom curve
template <typename T>
static typename std::enable_if_t<util::Interpolatable<T>::value,
ParseResult> makeZoomCurve(std::map<double, std::unique_ptr<Expression>> stops) {
ParsingContext ctx;
return createInterpolate(valueTypeToExpressionType<T>(),
ExponentialInterpolator(1.0),
makeZoom(),
std::move(stops),
ctx);
}
// non-interpolatable zoom curve
template <typename T>
static typename std::enable_if_t<!util::Interpolatable<T>::value,
ParseResult> makeZoomCurve(std::map<double, std::unique_ptr<Expression>> stops) {
return ParseResult(std::make_unique<Step>(valueTypeToExpressionType<T>(), makeZoom(), std::move(stops)));
}
template <typename T>
static std::unique_ptr<Expression> toExpression(const std::string& property,
const CompositeExponentialStops<T>& stops)
{
ParsingContext ctx;
std::map<double, std::unique_ptr<Expression>> outerStops;
for (const std::pair<float, std::map<float, T>>& stop : stops.stops) {
ParseResult innerInterpolate = createInterpolate(valueTypeToExpressionType<T>(),
ExponentialInterpolator(stops.base),
makeGet(type::Number, property),
convertStops(stop.second),
ctx);
assert(innerInterpolate);
outerStops.emplace(stop.first, std::move(*innerInterpolate));
}
ParseResult zoomCurve = makeZoomCurve<T>(std::move(outerStops));
assert(zoomCurve);
return std::move(*zoomCurve);
}
template <typename T>
static std::unique_ptr<Expression> toExpression(const std::string& property,
const CompositeIntervalStops<T>& stops)
{
std::map<double, std::unique_ptr<Expression>> outerStops;
for (const std::pair<float, std::map<float, T>>& stop : stops.stops) {
std::unique_ptr<Expression> get = makeGet(type::Number, property);
ParseResult innerInterpolate(std::make_unique<Step>(valueTypeToExpressionType<T>(),
std::move(get),
convertStops(stop.second)));
assert(innerInterpolate);
outerStops.emplace(stop.first, std::move(*innerInterpolate));
}
ParseResult zoomCurve = makeZoomCurve<T>(std::move(outerStops));
assert(zoomCurve);
return std::move(*zoomCurve);
}
template <typename T>
static std::unique_ptr<Expression> toExpression(const std::string& property,
const CompositeCategoricalStops<T>& stops)
{
std::map<double, std::unique_ptr<Expression>> outerStops;
for (const std::pair<float, std::map<CategoricalValue, T>>& stop : stops.stops) {
ParseResult innerInterpolate = fromCategoricalStops(stop.second, property);
assert(innerInterpolate);
outerStops.emplace(stop.first, std::move(*innerInterpolate));
}
ParseResult zoomCurve = makeZoomCurve<T>(std::move(outerStops));
assert(zoomCurve);
return std::move(*zoomCurve);
}
template <typename T>
static std::unique_ptr<Expression> toExpression(const std::string& property,
const IdentityStops<T>&)
{
return fromIdentityFunction(property, expression::valueTypeToExpressionType<T>());
}
private:
static std::unique_ptr<Expression> fromIdentityFunction(const std::string& property, type::Type type);
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -1,56 +0,0 @@
#pragma once
#include <mbgl/util/feature.hpp>
#include <mbgl/util/interpolate.hpp>
#include <map>
namespace mbgl {
namespace style {
template <class T>
class ExponentialStops {
public:
using Stops = std::map<float, T>;
Stops stops;
float base = 1.0f;
ExponentialStops() = default;
ExponentialStops(Stops stops_, float base_ = 1.0f)
: stops(std::move(stops_)),
base(base_) {
}
optional<T> evaluate(float z) const {
if (stops.empty()) {
return {};
}
auto it = stops.upper_bound(z);
if (it == stops.end()) {
return stops.rbegin()->second;
} else if (it == stops.begin()) {
return stops.begin()->second;
} else {
return util::interpolate(std::prev(it)->second, it->second,
util::interpolationFactor(base, { std::prev(it)->first, it->first }, z));
}
}
optional<T> evaluate(const Value& value) const {
optional<float> z = numericValue<float>(value);
if (!z) {
return {};
}
return evaluate(*z);
}
friend bool operator==(const ExponentialStops& lhs,
const ExponentialStops& rhs) {
return lhs.stops == rhs.stops && lhs.base == rhs.base;
}
};
} // namespace style
} // namespace mbgl

View File

@@ -1,20 +0,0 @@
#pragma once
#include <mbgl/util/feature.hpp>
namespace mbgl {
namespace style {
template <class T>
class IdentityStops {
public:
optional<T> evaluate(const Value&) const;
friend bool operator==(const IdentityStops&,
const IdentityStops&) {
return true;
}
};
} // namespace style
} // namespace mbgl

View File

@@ -1,51 +0,0 @@
#pragma once
#include <mbgl/util/feature.hpp>
#include <map>
namespace mbgl {
namespace style {
template <class T>
class IntervalStops {
public:
using Stops = std::map<float, T>;
Stops stops;
IntervalStops() = default;
IntervalStops(Stops stops_)
: stops(std::move(stops_)) {
}
optional<T> evaluate(float z) const {
if (stops.empty()) {
return {};
}
auto it = stops.upper_bound(z);
if (it == stops.end()) {
return stops.rbegin()->second;
} else if (it == stops.begin()) {
return stops.begin()->second;
} else {
return std::prev(it)->second;
}
}
optional<T> evaluate(const Value& value) const {
optional<float> z = numericValue<float>(value);
if (!z) {
return {};
}
return evaluate(*z);
}
friend bool operator==(const IntervalStops& lhs,
const IntervalStops& rhs) {
return lhs.stops == rhs.stops;
}
};
} // namespace style
} // namespace mbgl