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 | |