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.
PropertyExpression(std::unique_ptr<expression::Expression> expression_,optional<T> defaultValue_={})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(expression.get())) {
22     }
23 
isZoomConstant() const24     bool isZoomConstant() const { return expression::isZoomConstant(*expression); }
isFeatureConstant() const25     bool isFeatureConstant() const { return expression::isFeatureConstant(*expression); }
26 
evaluate(float zoom) const27     T evaluate(float zoom) const {
28         assert(!expression::isZoomConstant(*expression));
29         assert(expression::isFeatureConstant(*expression));
30         const expression::EvaluationResult result = expression->evaluate(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>
evaluate(const Feature & feature,T finalDefaultValue) const39     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(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>
evaluate(float zoom,const Feature & feature,T finalDefaultValue) const51     T evaluate(float zoom, const Feature& feature, T finalDefaultValue) const {
52         assert(!expression::isFeatureConstant(*expression));
53         const expression::EvaluationResult result = expression->evaluate(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 
interpolationFactor(const Range<float> & inputLevels,const float inputValue) const61     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(Range<double> { inputLevels.min, inputLevels.max }, inputValue);
69             },
70             [&](const expression::Step*) {
71                 return 0.0f;
72             }
73         );
74     }
75 
getCoveringStops(const float lower,const float upper) const76     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>
evaluate(const Range<float> & zoomRange,const Feature & feature,T finalDefaultValue)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 
possibleOutputs() const97     std::vector<optional<T>> possibleOutputs() const {
98         return expression::fromExpressionValues<T>(expression->possibleOutputs());
99     }
100 
getExpression() const101     const expression::Expression& getExpression() const { return *expression; }
102 
103     bool useIntegerZoom = false;
104 
operator ==(const PropertyExpression & lhs,const PropertyExpression & rhs)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