#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { class GeometryTileFeature; namespace style { template class UnevaluatedPaintProperty { public: UnevaluatedPaintProperty() = default; UnevaluatedPaintProperty(Value 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_) }; } } template auto evaluate(const Evaluator& evaluator, TimePoint now) { auto finalValue = value.evaluate(evaluator); if (!prior) { // No prior value. return finalValue; } else if (now >= end) { // Transition from prior value is now complete. prior = {}; return finalValue; } else if (now < begin) { // Transition hasn't started yet. return prior->get().evaluate(evaluator, now); } else { // Interpolate between recursively-calculated prior value and final. float t = std::chrono::duration(now - begin) / (end - begin); return util::interpolate(prior->get().evaluate(evaluator, now), finalValue, util::DEFAULT_TRANSITION_EASE.solve(t, 0.001)); } } bool hasTransition() const { return bool(prior); } bool isUndefined() const { return value.isUndefined(); } const Value& getValue() const { return value; } private: optional>> prior; TimePoint begin; TimePoint end; Value value; }; template class CascadingPaintProperty { public: bool isUndefined() const { return values.find(ClassID::Default) == values.end(); } const Value& get(const optional& klass) const { static const Value staticValue{}; const auto it = values.find(klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default); return it == values.end() ? staticValue : it->second; } void set(const Value& 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; Value 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 UnevaluatedType = UnevaluatedPaintProperty; using EvaluatorType = PropertyEvaluator; using EvaluatedType = T; static constexpr bool IsDataDriven = false; }; template class DataDrivenPaintProperty { public: using ValueType = DataDrivenPropertyValue; using CascadingType = CascadingPaintProperty; using UnevaluatedType = UnevaluatedPaintProperty; using EvaluatorType = DataDrivenPropertyEvaluator; using EvaluatedType = PossiblyEvaluatedPropertyValue; static constexpr bool IsDataDriven = true; using Type = T; using Attribute = A; }; template class CrossFadedPaintProperty { public: using ValueType = PropertyValue; using CascadingType = CascadingPaintProperty; using UnevaluatedType = UnevaluatedPaintProperty; using EvaluatorType = CrossFadedPropertyEvaluator; using EvaluatedType = Faded; static constexpr bool IsDataDriven = false; }; template struct IsDataDriven : std::integral_constant {}; template class PaintProperties { public: using Properties = TypeList; using DataDrivenProperties = FilteredTypeList; using Binders = PaintPropertyBinders; 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) { using Evaluator = typename P::EvaluatorType; return unevaluated.template get

() .evaluate(Evaluator(parameters, P::defaultValue()), parameters.now); } 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