| 1 | #pragma once |
| 2 | |
| 3 | #include <mbgl/util/color.hpp> |
| 4 | #include <mbgl/util/range.hpp> |
| 5 | #include <mbgl/style/position.hpp> |
| 6 | #include <mbgl/style/expression/value.hpp> |
| 7 | |
| 8 | #include <array> |
| 9 | #include <vector> |
| 10 | #include <string> |
| 11 | #include <type_traits> |
| 12 | #include <utility> |
| 13 | |
| 14 | namespace mbgl { |
| 15 | namespace util { |
| 16 | |
| 17 | float interpolationFactor(float base, Range<float> range, float z); |
| 18 | |
| 19 | template <class T, class Enabled = void> |
| 20 | struct Interpolator; |
| 21 | |
| 22 | template <typename T> |
| 23 | T interpolate(const T& a, const T& b, const double t) { |
| 24 | return Interpolator<T>()(a, b, t); |
| 25 | } |
| 26 | |
| 27 | |
| 28 | template <class T, class Enabled> |
| 29 | struct Interpolator { |
| 30 | T operator()(const T& a, const T& b, const double t) const { |
| 31 | return a * (1.0 - t) + b * t; |
| 32 | } |
| 33 | }; |
| 34 | |
| 35 | template <class T, std::size_t N> |
| 36 | struct Interpolator<std::array<T, N>> { |
| 37 | private: |
| 38 | using Array = std::array<T, N>; |
| 39 | |
| 40 | template <std::size_t... I> |
| 41 | Array operator()(const Array& a, const Array& b, const double t, std::index_sequence<I...>) { |
| 42 | return {{ interpolate(a[I], b[I], t)... }}; |
| 43 | } |
| 44 | |
| 45 | public: |
| 46 | Array operator()(const Array& a, const Array& b, const double t) { |
| 47 | return operator()(a, b, t, std::make_index_sequence<N>()); |
| 48 | } |
| 49 | }; |
| 50 | |
| 51 | |
| 52 | // In order to accept Array<Number, N> as an output value for Curve |
| 53 | // expressions, we need to have an interpolatable std::vector type. |
| 54 | // However, style properties like line-dasharray are represented using |
| 55 | // std::vector<float>, and should NOT be considered interpolatable. |
| 56 | // So, we use std::vector<Value> to represent expression array values, |
| 57 | // asserting that (a) the vectors are the same size, and (b) they contain |
| 58 | // only numeric values. (These invariants should be relatively safe, |
| 59 | // being enforced by the expression type system.) |
| 60 | template<> |
| 61 | struct Interpolator<std::vector<style::expression::Value>> { |
| 62 | std::vector<style::expression::Value> operator()(const std::vector<style::expression::Value>& a, |
| 63 | const std::vector<style::expression::Value>& b, |
| 64 | const double t) const { |
| 65 | assert(a.size() == b.size()); |
| 66 | if (a.size() == 0) return {}; |
| 67 | std::vector<style::expression::Value> result; |
| 68 | for (std::size_t i = 0; i < a.size(); i++) { |
| 69 | assert(a[i].template is<double>()); |
| 70 | assert(b[i].template is<double>()); |
| 71 | style::expression::Value item = interpolate( |
| 72 | a: a[i].template get<double>(), |
| 73 | b: b[i].template get<double>(), |
| 74 | t); |
| 75 | result.push_back(x: item); |
| 76 | } |
| 77 | return result; |
| 78 | } |
| 79 | }; |
| 80 | |
| 81 | template <> |
| 82 | struct Interpolator<style::Position> { |
| 83 | public: |
| 84 | style::Position operator()(const style::Position& a, const style::Position& b, const double t) { |
| 85 | auto pos = style::Position(); |
| 86 | auto interpolated = interpolate(a: a.getCartesian(), b: b.getCartesian(), t); |
| 87 | pos.setCartesian(interpolated); |
| 88 | return { pos }; |
| 89 | } |
| 90 | }; |
| 91 | |
| 92 | template <> |
| 93 | struct Interpolator<Color> { |
| 94 | public: |
| 95 | Color operator()(const Color& a, const Color& b, const double t) { |
| 96 | return { |
| 97 | interpolate(a: a.r, b: b.r, t), |
| 98 | interpolate(a: a.g, b: b.g, t), |
| 99 | interpolate(a: a.b, b: b.b, t), |
| 100 | interpolate(a: a.a, b: b.a, t) |
| 101 | }; |
| 102 | } |
| 103 | }; |
| 104 | |
| 105 | struct Uninterpolated { |
| 106 | template <class T> |
| 107 | T operator()(const T& a, const T&, const double) const { |
| 108 | return a; |
| 109 | } |
| 110 | }; |
| 111 | |
| 112 | template <> |
| 113 | struct Interpolator<bool> |
| 114 | : Uninterpolated {}; |
| 115 | |
| 116 | template <class T> |
| 117 | struct Interpolator<T, typename std::enable_if_t<std::is_enum<T>::value>> |
| 118 | : Uninterpolated {}; |
| 119 | |
| 120 | template <> |
| 121 | struct Interpolator<std::string> |
| 122 | : Uninterpolated {}; |
| 123 | |
| 124 | template <class T> |
| 125 | struct Interpolator<std::vector<T>> |
| 126 | : Uninterpolated {}; |
| 127 | |
| 128 | template <class T> |
| 129 | struct Interpolatable |
| 130 | : std::conditional_t< |
| 131 | !std::is_base_of<Uninterpolated, Interpolator<T>>::value, |
| 132 | std::true_type, |
| 133 | std::false_type> {}; |
| 134 | |
| 135 | |
| 136 | |
| 137 | } // namespace util |
| 138 | } // namespace mbgl |
| 139 | |