#pragma once #include #include #include #include #include #include #include #include #include namespace mbgl { namespace style { namespace expression { class ExponentialInterpolator { public: ExponentialInterpolator(double base_) : base(base_) {} double base; double interpolationFactor(const Range& inputLevels, const double input) const { return util::interpolationFactor(base, Range { static_cast(inputLevels.min), static_cast(inputLevels.max) }, input); } bool operator==(const ExponentialInterpolator& rhs) const { return base == rhs.base; } }; class CubicBezierInterpolator { public: CubicBezierInterpolator(double x1_, double y1_, double x2_, double y2_) : ub(x1_, y1_, x2_, y2_) {} double interpolationFactor(const Range& inputLevels, const double input) const { return ub.solve(input / (inputLevels.max - inputLevels.min), 1e-6); } bool operator==(const CubicBezierInterpolator& rhs) const { return ub == rhs.ub; } util::UnitBezier ub; }; ParseResult parseInterpolate(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx); class InterpolateBase : public Expression { public: using Interpolator = variant; InterpolateBase(const type::Type& type_, Interpolator interpolator_, std::unique_ptr input_, std::map> stops_ ) : Expression(type_), interpolator(std::move(interpolator_)), input(std::move(input_)), stops(std::move(stops_)) {} const std::unique_ptr& getInput() const { return input; } void eachChild(const std::function& visit) const override { visit(*input); for (const auto& stop : stops) { visit(*stop.second); } } // Return the smallest range of stops that covers the interval [lower, upper] Range getCoveringStops(const double lower, const double upper) const { return ::mbgl::style::expression::getCoveringStops(stops, lower, upper); } double interpolationFactor(const Range& inputLevels, const double inputValue) const { return interpolator.match( [&](const auto& interp) { return interp.interpolationFactor(inputLevels, inputValue); } ); } protected: const Interpolator interpolator; const std::unique_ptr input; const std::map> stops; }; template class Interpolate : public InterpolateBase { public: Interpolate(type::Type type_, Interpolator interpolator_, std::unique_ptr input_, std::map> stops_ ) : InterpolateBase(std::move(type_), std::move(interpolator_), std::move(input_), std::move(stops_)) { static_assert(util::Interpolatable::value, "Interpolate expression requires an interpolatable value type."); } EvaluationResult evaluate(const EvaluationContext& params) const override { const EvaluationResult evaluatedInput = input->evaluate(params); if (!evaluatedInput) { return evaluatedInput.error(); } float x = *fromExpressionValue(*evaluatedInput); 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 = 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(); } if (!lower->is()) { return EvaluationError { "Expected value to be of type " + toString(valueTypeToExpressionType()) + ", but found " + toString(typeOf(*lower)) + " instead." }; } if (!upper->is()) { return EvaluationError { "Expected value to be of type " + toString(valueTypeToExpressionType()) + ", but found " + toString(typeOf(*upper)) + " instead." }; } return util::interpolate(lower->get(), upper->get(), t); } } bool operator==(const Expression& e) const override { if (auto rhs = dynamic_cast(&e)) { if (interpolator != rhs->interpolator || *input != *(rhs->input) || stops.size() != rhs->stops.size()) { return false; } return Expression::childrenEqual(stops, rhs->stops); } return false; } }; } // namespace expression } // namespace style } // namespace mbgl