#pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { namespace style { template class UnevaluatedPaintProperty { public: using Result = typename Evaluator::ResultType; UnevaluatedPaintProperty() = default; UnevaluatedPaintProperty(PropertyValue value_, UnevaluatedPaintProperty prior_, TransitionOptions transition, TimePoint now) : begin(now + transition.delay.value_or(Duration::zero())), end(begin + transition.duration.value_or(Duration::zero())), value(std::move(value_)) { if (transition) { prior = { std::move(prior_) }; } } Result evaluate(const PropertyEvaluationParameters& parameters, T defaultValue) { Result finalValue = value.evaluate(Evaluator(parameters, defaultValue)); if (!prior) { // No prior value. return finalValue; } else if (parameters.now >= end) { // Transition from prior value is now complete. prior = {}; return finalValue; } else { // Interpolate between recursively-calculated prior value and final. float t = std::chrono::duration(parameters.now - begin) / (end - begin); return util::interpolate(prior->get().evaluate(parameters, defaultValue), finalValue, util::DEFAULT_TRANSITION_EASE.solve(t, 0.001)); } } bool hasTransition() const { return bool(prior); } bool isUndefined() const { return value.isUndefined(); } private: optional>> prior; TimePoint begin; TimePoint end; PropertyValue value; }; template class CascadingPaintProperty { public: bool isUndefined() const { return values.find(ClassID::Default) == values.end(); } const PropertyValue& get(const optional& klass) const { static const PropertyValue staticValue; const auto it = values.find(klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default); return it == values.end() ? staticValue : it->second; } void set(const PropertyValue& value_, const optional& klass) { values[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = value_; } void setTransition(const TransitionOptions& transition, const optional& klass) { transitions[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = transition; } template UnevaluatedPaintProperty cascade(const CascadeParameters& params, UnevaluatedPaintProperty prior) const { TransitionOptions transition; PropertyValue value; for (const auto classID : params.classes) { if (values.find(classID) != values.end()) { value = values.at(classID); break; } } for (const auto classID : params.classes) { if (transitions.find(classID) != transitions.end()) { transition = transitions.at(classID).reverseMerge(transition); break; } } return UnevaluatedPaintProperty(std::move(value), std::move(prior), transition.reverseMerge(params.transition), params.now); } private: std::unordered_map> values; std::unordered_map transitions; }; template class PaintProperty { public: using ValueType = PropertyValue; using CascadingType = CascadingPaintProperty; using EvaluatorType = PropertyEvaluator; using UnevaluatedType = UnevaluatedPaintProperty; using EvaluatedType = T; }; template class CrossFadedPaintProperty { public: using ValueType = PropertyValue; using CascadingType = CascadingPaintProperty; using EvaluatorType = CrossFadedPropertyEvaluator; using UnevaluatedType = UnevaluatedPaintProperty; using EvaluatedType = Faded; }; template class PaintProperties { public: using Properties = TypeList; using EvaluatedTypes = TypeList; using UnevaluatedTypes = TypeList; using CascadingTypes = TypeList; template using Tuple = IndexedTuple; class Evaluated : public Tuple { public: using Tuple::Tuple; }; class Unevaluated : public Tuple { public: using Tuple::Tuple; }; class Cascading : public Tuple { public: using Tuple::Tuple; }; template auto get(const optional& klass) const { return cascading.template get

().get(klass); } template void set(const typename P::ValueType& value, const optional& klass) { cascading.template get

().set(value, klass); } void cascade(const CascadeParameters& parameters) { unevaluated = Unevaluated { cascading.template get().cascade(parameters, std::move(unevaluated.template get()))... }; } template auto evaluate(const PropertyEvaluationParameters& parameters) { return unevaluated.template get

().evaluate(parameters, P::defaultValue()); } void evaluate(const PropertyEvaluationParameters& parameters) { evaluated = Evaluated { evaluate(parameters)... }; } bool hasTransition() const { bool result = false; util::ignore({ result |= unevaluated.template get().hasTransition()... }); return result; } Cascading cascading; Unevaluated unevaluated; Evaluated evaluated; }; } // namespace style } // namespace mbgl