summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnand Thakker <github@anandthakker.net>2017-08-11 14:56:17 -0400
committerAnand Thakker <github@anandthakker.net>2017-08-11 21:55:04 -0400
commitea1ba8b7072cab9bf442ee4c37fe8051494aa9bd (patch)
tree3c6c0650e4a0b393721605ef0f324f1608f9904b
parent71a23a70a1220a62d38fb6dde47516ce50a783e5 (diff)
downloadqtlocation-mapboxgl-ea1ba8b7072cab9bf442ee4c37fe8051494aa9bd.tar.gz
Move stops out of Curve interpolators
-rw-r--r--include/mbgl/style/expression/curve.hpp163
-rw-r--r--include/mbgl/style/function/convert.hpp119
2 files changed, 166 insertions, 116 deletions
diff --git a/include/mbgl/style/expression/curve.hpp b/include/mbgl/style/expression/curve.hpp
index 08a9573e71..2a4a3574dd 100644
--- a/include/mbgl/style/expression/curve.hpp
+++ b/include/mbgl/style/expression/curve.hpp
@@ -2,6 +2,7 @@
#include <map>
#include <mbgl/util/interpolate.hpp>
+#include <mbgl/util/range.hpp>
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/conversion.hpp>
@@ -11,60 +12,47 @@ namespace style {
namespace expression {
template <class T>
-class ExponentialCurve {
+class ExponentialInterpolator {
public:
- using Stops = std::map<float, std::unique_ptr<Expression>>;
+ ExponentialInterpolator(float base_) : base(base_) {}
- ExponentialCurve(Stops stops_, float base_)
- : stops(std::move(stops_)),
- base(base_)
- {}
-
- Stops stops;
float base;
-
- EvaluationResult evaluate(float x, const EvaluationParameters& parameters) const {
- if (stops.empty()) {
- return EvaluationError { "No stops in exponential curve." };
+
+ float interpolationFactor(const Range<float>& inputLevels, const float& input) const {
+ return util::interpolationFactor(base, inputLevels, input);
+ }
+
+ EvaluationResult interpolate(const Range<Value>& outputs, const float& t) const {
+ optional<T> lower = fromExpressionValue<T>(outputs.min);
+ if (!lower) {
+ // TODO - refactor fromExpressionValue to return EvaluationResult<T> so as to
+ // consolidate DRY up producing this error message.
+ return EvaluationError {
+ "Expected value to be of type " + toString(valueTypeToExpressionType<T>()) +
+ ", but found " + toString(typeOf(outputs.min)) + " instead."
+ };
}
-
- auto it = stops.upper_bound(x);
- if (it == stops.end()) {
- return stops.rbegin()->second->evaluate(parameters);
- } else if (it == stops.begin()) {
- return stops.begin()->second->evaluate(parameters);
- } else {
- const auto& lower = std::prev(it)->second->template evaluate<T>(parameters);
- if (!lower) { return lower.error(); }
- const auto& upper = it->second->template evaluate<T>(parameters);
- if (!upper) { return upper.error(); }
- T result = util::interpolate(*lower, *upper,
- util::interpolationFactor(base, { std::prev(it)->first, it->first }, x));
- return toExpressionValue(result);
+ const auto& upper = fromExpressionValue<T>(outputs.max);
+ if (!upper) {
+ return EvaluationError {
+ "Expected value to be of type " + toString(valueTypeToExpressionType<T>()) +
+ ", but found " + toString(typeOf(outputs.min)) + " instead."
+ };
}
+ T result = util::interpolate(*lower, *upper, t);
+ return toExpressionValue(result);
}
};
-class StepCurve {
+class StepInterpolator {
public:
- using Stops = std::map<float, std::unique_ptr<Expression>>;
- StepCurve(Stops stops_) : stops(std::move(stops_)) {}
-
- Stops stops;
-
- EvaluationResult evaluate(float x, const EvaluationParameters& parameters) const {
- if (stops.empty()) {
- return EvaluationError { "No stops in exponential curve." };
- }
-
- auto it = stops.upper_bound(x);
- if (it == stops.end()) {
- return stops.rbegin()->second->evaluate(parameters);
- } else if (it == stops.begin()) {
- return stops.begin()->second->evaluate(parameters);
- } else {
- return std::prev(it)->second->evaluate(parameters);
- }
+ float interpolationFactor(const Range<float>&, const float&) const {
+ return 0;
+ }
+ float interpolate(const Range<Value>&, const float&) const {
+ // Assume that Curve::evaluate() will always short circuit due to
+ // interpolationFactor always returning 0.
+ assert(false);
}
};
@@ -74,26 +62,63 @@ namespace detail {
struct ExponentialInterpolation { float base; std::string name = "exponential"; };
struct StepInterpolation {};
-}
+} // namespace detail
+
-template <typename CurveType>
+template <typename InterpolatorT>
class Curve : public Expression {
public:
- Curve(const type::Type& type, std::unique_ptr<Expression> input_, CurveType curve_) :
- Expression(type),
+ using Interpolator = InterpolatorT;
+
+ Curve(const type::Type& type,
+ Interpolator interpolator_,
+ std::unique_ptr<Expression> input_,
+ std::map<float, std::unique_ptr<Expression>> stops_
+ ) : Expression(type),
+ interpolator(std::move(interpolator_)),
input(std::move(input_)),
- curve(std::move(curve_))
+ stops(std::move(stops_))
{}
EvaluationResult evaluate(const EvaluationParameters& params) const override {
const auto& x = input->evaluate<float>(params);
if (!x) { return x.error(); }
- return curve.evaluate(*x, params);
+
+ if (stops.empty()) {
+ return EvaluationError { "No stops in exponential curve." };
+ }
+
+ auto it = stops.upper_bound(*x);
+ if (it == stops.end()) {
+ return stops.rbegin()->second->evaluate(params);
+ } else if (it == stops.begin()) {
+ return stops.begin()->second->evaluate(params);
+ } else {
+ float t = interpolator.interpolationFactor({ std::prev(it)->first, it->first }, *x);
+ if (t == 0.0f) {
+ return std::prev(it)->second->evaluate(params);
+ }
+ if (t == 1.0f) {
+ return it->second->evaluate(params);
+ }
+
+ EvaluationResult lower = std::prev(it)->second->evaluate(params);
+ if (!lower) {
+ return lower.error();
+ }
+ EvaluationResult upper = it->second->evaluate(params);
+ if (!upper) {
+ return upper.error();
+ }
+
+ return interpolator.interpolate({*lower, *upper}, t);
+ }
+
}
bool isFeatureConstant() const override {
if (!input->isFeatureConstant()) { return false; }
- for (const auto& stop : curve.stops) {
+ for (const auto& stop : stops) {
if (!stop.second->isFeatureConstant()) { return false; }
}
return true;
@@ -101,15 +126,23 @@ public:
bool isZoomConstant() const override {
if (!input->isZoomConstant()) { return false; }
- for (const auto& stop : curve.stops) {
+ for (const auto& stop : stops) {
if (!stop.second->isZoomConstant()) { return false; }
}
return true;
}
+ bool isZoomCurve() const {
+ if (auto z = dynamic_cast<CompoundExpressionBase*>(input.get())) {
+ return z->getName() == "zoom";
+ }
+ return false;
+ }
+
private:
+ Interpolator interpolator;
std::unique_ptr<Expression> input;
- CurveType curve;
+ std::map<float, std::unique_ptr<Expression>> stops;
};
struct ParseCurve {
@@ -207,41 +240,45 @@ struct ParseCurve {
{
ctx.error("Type " + toString(*outputType) +
" is not interpolatable, and thus cannot be used as a " +
- *interpName + " curve's output type");
+ *interpName + " curve's output type.");
return ParseResult();
}
return interpolation.match(
[&](const detail::StepInterpolation&) -> ParseResult {
- return ParseResult(std::make_unique<Curve<StepCurve>>(
+ return ParseResult(std::make_unique<Curve<StepInterpolator>>(
*outputType,
+ StepInterpolator(),
std::move(*input),
- StepCurve(std::move(stops))
+ std::move(stops)
));
},
[&](const detail::ExponentialInterpolation& exponentialInterpolation) -> ParseResult {
const float base = exponentialInterpolation.base;
return outputType->match(
[&](const type::NumberType&) -> ParseResult {
- return ParseResult(std::make_unique<Curve<ExponentialCurve<float>>>(
+ return ParseResult(std::make_unique<Curve<ExponentialInterpolator<float>>>(
*outputType,
+ ExponentialInterpolator<float>(base),
std::move(*input),
- ExponentialCurve<float>(std::move(stops), base)
+ std::move(stops)
));
},
[&](const type::ColorType&) -> ParseResult {
- return ParseResult(std::make_unique<Curve<ExponentialCurve<mbgl::Color>>>(
+ return ParseResult(std::make_unique<Curve<ExponentialInterpolator<mbgl::Color>>>(
*outputType,
+ ExponentialInterpolator<mbgl::Color>(base),
std::move(*input),
- ExponentialCurve<mbgl::Color>(std::move(stops), base)
+ std::move(stops)
));
},
[&](const type::Array& arrayType) -> ParseResult {
if (arrayType.itemType == type::Number && arrayType.N) {
- return ParseResult(std::make_unique<Curve<ExponentialCurve<std::vector<float>>>>(
+ return ParseResult(std::make_unique<Curve<ExponentialInterpolator<std::vector<float>>>>(
*outputType,
+ ExponentialInterpolator<std::vector<float>>(base),
std::move(*input),
- ExponentialCurve<std::vector<float>>(std::move(stops), base)
+ std::move(stops)
));
} else {
assert(false); // interpolability already checked above.
diff --git a/include/mbgl/style/function/convert.hpp b/include/mbgl/style/function/convert.hpp
index edbd0c6fa0..dc44807a18 100644
--- a/include/mbgl/style/function/convert.hpp
+++ b/include/mbgl/style/function/convert.hpp
@@ -92,7 +92,7 @@ struct Convert {
template <typename T>
static std::map<float, std::unique_ptr<Expression>> convertStops(const std::map<float, T>& stops) {
std::map<float, std::unique_ptr<Expression>> convertedStops;
- for(const auto& stop : stops) {
+ for(const std::pair<float, T>& stop : stops) {
convertedStops.emplace(
stop.first,
makeLiteral(stop.second)
@@ -103,39 +103,40 @@ struct Convert {
template <typename T>
static ParseResult makeExponentialCurve(std::unique_ptr<Expression> input,
- const ExponentialStops<T>& stops,
+ std::map<float, std::unique_ptr<Expression>> convertedStops,
+ float base,
optional<T> defaultValue)
{
- std::map<float, std::unique_ptr<Expression>> convertedStops = convertStops(stops.stops);
ParseResult curve = valueTypeToExpressionType<T>().match(
[&](const type::NumberType& t) -> ParseResult {
- return ParseResult(std::make_unique<Curve<ExponentialCurve<float>>>(
+ return ParseResult(std::make_unique<Curve<ExponentialInterpolator<float>>>(
t,
+ ExponentialInterpolator<float>(base),
std::move(input),
- ExponentialCurve<float>(std::move(convertedStops), stops.base)
+ std::move(convertedStops)
));
},
[&](const type::ColorType& t) -> ParseResult {
- return ParseResult(std::make_unique<Curve<ExponentialCurve<mbgl::Color>>>(
+ return ParseResult(std::make_unique<Curve<ExponentialInterpolator<mbgl::Color>>>(
t,
+ ExponentialInterpolator<mbgl::Color>(base),
std::move(input),
- ExponentialCurve<mbgl::Color>(std::move(convertedStops), stops.base)
+ std::move(convertedStops)
));
},
[&](const type::Array& arrayType) -> ParseResult {
if (arrayType.itemType == type::Number && arrayType.N) {
- return ParseResult(std::make_unique<Curve<ExponentialCurve<std::vector<Value>>>>(
+ return ParseResult(std::make_unique<Curve<ExponentialInterpolator<std::vector<Value>>>>(
arrayType,
+ ExponentialInterpolator<std::vector<Value>>(base),
std::move(input),
- ExponentialCurve<std::vector<Value>>(std::move(convertedStops), stops.base)
+ std::move(convertedStops)
));
} else {
- // never: interpolability ensured by ExponentialStops<T>.
return ParseResult();
}
},
[&](const auto&) -> ParseResult {
- // never: interpolability ensured by ExponentialStops<T>.
return ParseResult();
}
);
@@ -146,24 +147,25 @@ struct Convert {
template <typename T>
static ParseResult makeStepCurve(std::unique_ptr<Expression> input,
- const IntervalStops<T>& stops,
+ const std::map<float, T>& stops,
optional<T> defaultValue)
{
- std::map<float, std::unique_ptr<Expression>> convertedStops = convertStops(stops.stops);
- auto curve = std::make_unique<Curve<StepCurve>>(valueTypeToExpressionType<T>(),
- std::move(input),
- StepCurve(std::move(convertedStops)));
+ std::map<float, std::unique_ptr<Expression>> convertedStops = convertStops(stops);
+ auto curve = std::make_unique<Curve<StepInterpolator>>(valueTypeToExpressionType<T>(),
+ StepInterpolator(),
+ std::move(input),
+ std::move(convertedStops));
return makeCoalesceToDefault(std::move(curve), defaultValue);
}
template <typename Key, typename T>
static ParseResult makeMatch(std::unique_ptr<Expression> input,
- const CategoricalStops<T>& stops) {
+ const std::map<CategoricalValue, T>& stops) {
// match expression
typename Match<Key>::Cases cases;
- for(const auto& stop : stops.stops) {
+ for(const std::pair<CategoricalValue, T>& stop : stops) {
assert(stop.first.template is<Key>());
- auto key = stop.first.template get<Key>();
+ Key key = stop.first.template get<Key>();
cases.emplace(
std::move(key),
makeLiteral(stop.second)
@@ -178,24 +180,53 @@ struct Convert {
template <typename T>
static ParseResult makeCase(std::unique_ptr<Expression> input,
- const CategoricalStops<T>& stops) {
+ const std::map<CategoricalValue, T>& stops) {
// case expression
std::vector<typename Case::Branch> cases;
- auto true_case = stops.stops.find(true) == stops.stops.end() ?
+
+ auto it = stops.find(true);
+ std::unique_ptr<Expression> true_case = it == stops.end() ?
makeError("No matching label") :
- makeLiteral(stops.stops.at(true));
- auto false_case = stops.stops.find(false) == stops.stops.end() ?
+ makeLiteral(it->second);
+
+ it = stops.find(false);
+ std::unique_ptr<Expression> false_case = it == stops.end() ?
makeError("No matching label") :
- makeLiteral(stops.stops.at(false));
+ makeLiteral(it->second);
+
cases.push_back(std::make_pair(std::move(input), std::move(true_case)));
return ParseResult(std::make_unique<Case>(valueTypeToExpressionType<T>(), std::move(cases), std::move(false_case)));
}
template <typename T>
+ static ParseResult convertCategoricalStops(std::map<CategoricalValue, T> stops, const std::string& property) {
+ assert(stops.size() > 0);
+
+ std::vector<ParsingError> errors;
+ ParsingContext ctx(errors);
+
+ const CategoricalValue& firstKey = stops.begin()->first;
+ return firstKey.match(
+ [&](bool) {
+ return makeCase(makeGet("boolean", property, ctx), stops);
+ },
+ [&](const std::string&) {
+ return makeMatch<std::string>(makeGet("string", property, ctx), stops);
+ },
+ [&](int64_t) {
+ return makeMatch<int64_t>(makeGet("number", property, ctx), stops);
+ }
+ );
+ }
+
+ template <typename T>
static std::unique_ptr<Expression> toExpression(const ExponentialStops<T>& stops)
{
std::vector<ParsingError> errors;
- ParseResult e = makeExponentialCurve(makeZoom(ParsingContext(errors)), stops, optional<T>());
+ ParseResult e = makeExponentialCurve(makeZoom(ParsingContext(errors)),
+ convertStops(stops.stops),
+ stops.base,
+ optional<T>());
assert(e);
return std::move(*e);
}
@@ -204,7 +235,7 @@ struct Convert {
static std::unique_ptr<Expression> toExpression(const IntervalStops<T>& stops)
{
std::vector<ParsingError> errors;
- ParseResult e = makeStepCurve(makeZoom(ParsingContext(errors)), stops, optional<T>());
+ ParseResult e = makeStepCurve(makeZoom(ParsingContext(errors)), stops.stops, optional<T>());
assert(e);
return std::move(*e);
}
@@ -215,7 +246,10 @@ struct Convert {
optional<T> defaultValue)
{
std::vector<ParsingError> errors;
- ParseResult e = makeExponentialCurve(makeGet("number", property, ParsingContext(errors)), stops, defaultValue);
+ ParseResult e = makeExponentialCurve(makeGet("number", property, ParsingContext(errors)),
+ convertStops(stops.stops),
+ stops.base,
+ defaultValue);
assert(e);
return std::move(*e);
}
@@ -226,7 +260,7 @@ struct Convert {
optional<T> defaultValue)
{
std::vector<ParsingError> errors;
- ParseResult e = makeStepCurve(makeGet("number", property, ParsingContext(errors)), stops, defaultValue);
+ ParseResult e = makeStepCurve(makeGet("number", property, ParsingContext(errors)), stops.stops, defaultValue);
assert(e);
return std::move(*e);
}
@@ -236,29 +270,8 @@ struct Convert {
const CategoricalStops<T>& stops,
optional<T> defaultValue)
{
- assert(stops.stops.size() > 0);
-
- std::vector<ParsingError> errors;
-
- const auto& firstKey = stops.stops.begin()->first;
- ParseResult expr = firstKey.match(
- [&](bool) {
- auto input = makeGet("boolean", property, ParsingContext(errors));
- return makeCase(std::move(input), stops);
- },
- [&](const std::string&) {
- auto input = makeGet("string", property, ParsingContext(errors));
- return makeMatch<std::string>(std::move(input), stops);
- },
- [&](int64_t) {
- auto input = makeGet("number", property, ParsingContext(errors));
- return makeMatch<int64_t>(std::move(input), stops);
- }
-
- );
-
+ ParseResult expr = convertCategoricalStops(stops.stops, property);
assert(expr);
-
ParseResult e = makeCoalesceToDefault(std::move(*expr), defaultValue);
assert(e);
return std::move(*e);
@@ -284,9 +297,9 @@ struct Convert {
[&] (const type::Array& arr) {
std::vector<std::unique_ptr<Expression>> getArgs;
getArgs.push_back(makeLiteral(property));
- auto get = CompoundExpressions::create(CompoundExpressions::definitions.at("get"),
- std::move(getArgs),
- ParsingContext(errors));
+ ParseResult get = CompoundExpressions::create(CompoundExpressions::definitions.at("get"),
+ std::move(getArgs),
+ ParsingContext(errors));
return std::make_unique<ArrayAssertion>(arr, std::move(*get));
},
[&] (const auto&) -> std::unique_ptr<Expression> {