diff options
author | Anand Thakker <github@anandthakker.net> | 2017-08-11 14:56:17 -0400 |
---|---|---|
committer | Anand Thakker <github@anandthakker.net> | 2017-08-11 21:55:04 -0400 |
commit | ea1ba8b7072cab9bf442ee4c37fe8051494aa9bd (patch) | |
tree | 3c6c0650e4a0b393721605ef0f324f1608f9904b | |
parent | 71a23a70a1220a62d38fb6dde47516ce50a783e5 (diff) | |
download | qtlocation-mapboxgl-ea1ba8b7072cab9bf442ee4c37fe8051494aa9bd.tar.gz |
Move stops out of Curve interpolators
-rw-r--r-- | include/mbgl/style/expression/curve.hpp | 163 | ||||
-rw-r--r-- | include/mbgl/style/function/convert.hpp | 119 |
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> { |