| 1 | #pragma once |
| 2 | |
| 3 | #include <mbgl/style/expression/expression.hpp> |
| 4 | #include <mbgl/style/expression/value.hpp> |
| 5 | #include <mbgl/style/expression/is_constant.hpp> |
| 6 | #include <mbgl/style/expression/interpolate.hpp> |
| 7 | #include <mbgl/style/expression/step.hpp> |
| 8 | #include <mbgl/style/expression/find_zoom_curve.hpp> |
| 9 | #include <mbgl/util/range.hpp> |
| 10 | |
| 11 | namespace mbgl { |
| 12 | namespace style { |
| 13 | |
| 14 | template <class T> |
| 15 | class PropertyExpression { |
| 16 | public: |
| 17 | // Second parameter to be used only for conversions from legacy functions. |
| 18 | PropertyExpression(std::unique_ptr<expression::Expression> expression_, optional<T> defaultValue_ = {}) |
| 19 | : expression(std::move(expression_)), |
| 20 | defaultValue(std::move(defaultValue_)), |
| 21 | zoomCurve(expression::findZoomCurveChecked(e: expression.get())) { |
| 22 | } |
| 23 | |
| 24 | bool isZoomConstant() const { return expression::isZoomConstant(e: *expression); } |
| 25 | bool isFeatureConstant() const { return expression::isFeatureConstant(expression: *expression); } |
| 26 | |
| 27 | T evaluate(float zoom) const { |
| 28 | assert(!expression::isZoomConstant(*expression)); |
| 29 | assert(expression::isFeatureConstant(*expression)); |
| 30 | const expression::EvaluationResult result = expression->evaluate(params: expression::EvaluationContext(zoom, nullptr)); |
| 31 | if (result) { |
| 32 | const optional<T> typed = expression::fromExpressionValue<T>(*result); |
| 33 | return typed ? *typed : defaultValue ? *defaultValue : T(); |
| 34 | } |
| 35 | return defaultValue ? *defaultValue : T(); |
| 36 | } |
| 37 | |
| 38 | template <class Feature> |
| 39 | T evaluate(const Feature& feature, T finalDefaultValue) const { |
| 40 | assert(expression::isZoomConstant(*expression)); |
| 41 | assert(!expression::isFeatureConstant(*expression)); |
| 42 | const expression::EvaluationResult result = expression->evaluate(params: expression::EvaluationContext(&feature)); |
| 43 | if (result) { |
| 44 | const optional<T> typed = expression::fromExpressionValue<T>(*result); |
| 45 | return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue; |
| 46 | } |
| 47 | return defaultValue ? *defaultValue : finalDefaultValue; |
| 48 | } |
| 49 | |
| 50 | template <class Feature> |
| 51 | T evaluate(float zoom, const Feature& feature, T finalDefaultValue) const { |
| 52 | assert(!expression::isFeatureConstant(*expression)); |
| 53 | const expression::EvaluationResult result = expression->evaluate(params: expression::EvaluationContext({zoom}, &feature)); |
| 54 | if (result) { |
| 55 | const optional<T> typed = expression::fromExpressionValue<T>(*result); |
| 56 | return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue; |
| 57 | } |
| 58 | return defaultValue ? *defaultValue : finalDefaultValue; |
| 59 | } |
| 60 | |
| 61 | float interpolationFactor(const Range<float>& inputLevels, const float inputValue) const { |
| 62 | return zoomCurve.match( |
| 63 | [](std::nullptr_t) { |
| 64 | assert(false); |
| 65 | return 0.0f; |
| 66 | }, |
| 67 | [&](const expression::Interpolate* z) { |
| 68 | return z->interpolationFactor(inputLevels: Range<double> { inputLevels.min, inputLevels.max }, inputValue); |
| 69 | }, |
| 70 | [&](const expression::Step*) { |
| 71 | return 0.0f; |
| 72 | } |
| 73 | ); |
| 74 | } |
| 75 | |
| 76 | Range<float> getCoveringStops(const float lower, const float upper) const { |
| 77 | return zoomCurve.match( |
| 78 | [](std::nullptr_t) { |
| 79 | assert(false); |
| 80 | return Range<float>(0.0f, 0.0f); |
| 81 | }, |
| 82 | [&](auto z) { |
| 83 | return z->getCoveringStops(lower, upper); |
| 84 | } |
| 85 | ); |
| 86 | } |
| 87 | |
| 88 | // Return the range obtained by evaluating the function at each of the zoom levels in zoomRange |
| 89 | template <class Feature> |
| 90 | Range<T> evaluate(const Range<float>& zoomRange, const Feature& feature, T finalDefaultValue) { |
| 91 | return Range<T> { |
| 92 | evaluate(zoomRange.min, feature, finalDefaultValue), |
| 93 | evaluate(zoomRange.max, feature, finalDefaultValue) |
| 94 | }; |
| 95 | } |
| 96 | |
| 97 | std::vector<optional<T>> possibleOutputs() const { |
| 98 | return expression::fromExpressionValues<T>(expression->possibleOutputs()); |
| 99 | } |
| 100 | |
| 101 | const expression::Expression& getExpression() const { return *expression; } |
| 102 | |
| 103 | bool useIntegerZoom = false; |
| 104 | |
| 105 | friend bool operator==(const PropertyExpression& lhs, |
| 106 | const PropertyExpression& rhs) { |
| 107 | return *lhs.expression == *rhs.expression; |
| 108 | } |
| 109 | |
| 110 | private: |
| 111 | std::shared_ptr<const expression::Expression> expression; |
| 112 | optional<T> defaultValue; |
| 113 | variant<std::nullptr_t, const expression::Interpolate*, const expression::Step*> zoomCurve; |
| 114 | }; |
| 115 | |
| 116 | } // namespace style |
| 117 | } // namespace mbgl |
| 118 | |