#pragma once #include #include #include #include #include #include #include #include #include namespace mbgl { class GeometryTileFeature; namespace style { template class Transitioning { public: Transitioning() = default; explicit Transitioning(Value value_) : value(std::move(value_)) { } Transitioning(Value value_, Transitioning prior_, const 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.isDefined()) { prior = { std::move(prior_) }; } } template auto evaluate(const Evaluator& evaluator, TimePoint now) const { 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 (value.isDataDriven()) { // Transitions to data-driven properties are not supported. // We snap immediately to the data-driven value so that, when we perform layout, // we see the data-driven function and can use it to populate vertex buffers. 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: mutable optional>> prior; TimePoint begin; TimePoint end; Value value; }; template class Transitionable { public: Value value; TransitionOptions options; Transitioning transition(const TransitionParameters& params, Transitioning prior) const { return Transitioning(value, std::move(prior), options.reverseMerge(params.transition), params.now); } }; template struct IsDataDriven : std::integral_constant {}; template struct IsOverridable : std::integral_constant {}; template struct ConstantsMask; template struct ConstantsMask> { template static unsigned long getMask(const Properties& properties) { std::bitset result; util::ignore({ result.set(TypeIndex::value, properties.template get().isConstant())... }); return result.to_ulong(); } }; template class Properties { public: /* For style properties we implement a two step evaluation process: if you have a zoom level, you can evaluate a set of unevaluated property values, producing a set of possibly evaluated values, where undefined, constant, or camera function values have been fully evaluated, and source or composite function values have not. Once you also have a particular feature, you can evaluate that set of possibly evaluated values fully, producing a set of fully evaluated values. This is in theory maximally efficient in terms of avoiding repeated evaluation of camera functions, though it's more of a historical accident than a purposeful optimization. */ using PropertyTypes = TypeList; using TransitionableTypes = TypeList; using UnevaluatedTypes = TypeList; using PossiblyEvaluatedTypes = TypeList; using EvaluatedTypes = TypeList; using DataDrivenProperties = FilteredTypeList; using OverridableProperties = FilteredTypeList; template using Tuple = IndexedTuple; class Evaluated : public Tuple { public: template Evaluated(Us&&... us) : Tuple(std::forward(us)...) { } }; class PossiblyEvaluated : public Tuple { public: template PossiblyEvaluated(Us&&... us) : Tuple(std::forward(us)...) { } template static T evaluate(float, const GeometryTileFeature&, const T& t, const T&) { return t; } template static T evaluate(float, const GeometryTileFeature&, const CanonicalTileID&, const T& t, const T&) { return t; } template static T evaluate(float z, const GeometryTileFeature& feature, const PossiblyEvaluatedPropertyValue& v, const T& defaultValue) { return v.match( [&] (const T& t) { return t; }, [&] (const PropertyExpression& t) { return t.evaluate(z, feature, defaultValue); }); } template static T evaluate(float z, const GeometryTileFeature& feature, const PossiblyEvaluatedPropertyValue& v, const T& defaultValue, const std::set& availableImages) { return v.match( [&](const T& t) { return t; }, [&](const PropertyExpression& t) { return t.evaluate(z, feature, availableImages, defaultValue); }); } template static T evaluate(float z, const GeometryTileFeature& feature, const PossiblyEvaluatedPropertyValue& v, const T& defaultValue, const std::set& availableImages, const CanonicalTileID& canonical) { return v.match([&](const T& t) { return t; }, [&](const PropertyExpression& t) { return t.evaluate(z, feature, availableImages, canonical, defaultValue); }); } template static T evaluate(float z, const GeometryTileFeature& feature, const CanonicalTileID& canonical, const PossiblyEvaluatedPropertyValue& v, const T& defaultValue) { return v.match( [&](const T& t) { return t; }, [&](const PropertyExpression& t) { return t.evaluate(z, feature, canonical, defaultValue); }); } template static T evaluate(float z, const GeometryTileFeature& feature, const FeatureState& state, const PossiblyEvaluatedPropertyValue& v, const T& defaultValue) { return v.match([&](const T& t) { return t; }, [&](const PropertyExpression& t) { return t.evaluate(z, feature, state, defaultValue); }); } template auto evaluate(float z, const GeometryTileFeature& feature) const { return evaluate(z, feature, this->template get

(), P::defaultValue()); } template auto evaluate(float z, const GeometryTileFeature& feature, const CanonicalTileID& canonical) const { return evaluate(z, feature, canonical, this->template get

(), P::defaultValue()); } template auto evaluate(float z, const GeometryTileFeature& feature, const FeatureState& state) const { return evaluate(z, feature, state, this->template get

(), P::defaultValue()); } template auto evaluate(float z, const GeometryTileFeature& feature, const std::set& availableImages) const { return evaluate(z, feature, this->template get

(), P::defaultValue(), availableImages); } template auto evaluate(float z, const GeometryTileFeature& feature, const std::set& availableImages, const CanonicalTileID& canonical) const { return evaluate(z, feature, this->template get

(), P::defaultValue(), availableImages, canonical); } Evaluated evaluate(float z, const GeometryTileFeature& feature) const { return Evaluated { evaluate(z, feature)... }; } unsigned long constantsMask() const { return ConstantsMask::getMask(*this); } }; class Unevaluated : public Tuple { public: template Unevaluated(Us&&... us) : Tuple(std::forward(us)...) { } bool hasTransition() const { bool result = false; util::ignore({ result |= this->template get().hasTransition()... }); return result; } template auto evaluate(const PropertyEvaluationParameters& parameters) const { using Evaluator = typename P::EvaluatorType; return this->template get

() .evaluate(Evaluator(parameters, P::defaultValue()), parameters.now); } PossiblyEvaluated evaluate(const PropertyEvaluationParameters& parameters) const { return PossiblyEvaluated { evaluate(parameters)... }; } template void stringify(Writer& writer) const { writer.StartObject(); util::ignore({ (conversion::stringify(writer, this->template get()), 0)... }); writer.EndObject(); } }; class Transitionable : public Tuple { public: template Transitionable(Us&&... us) : Tuple(std::forward(us)...) { } Unevaluated transitioned(const TransitionParameters& parameters, Unevaluated&& prior) const { return Unevaluated { this->template get() .transition(parameters, std::move(prior.template get()))... }; } Unevaluated untransitioned() const { return Unevaluated { typename Ps::UnevaluatedType(this->template get().value)... }; } bool hasDataDrivenPropertyDifference(const Transitionable& other) const { bool result = false; util::ignore({ (result |= this->template get().value.hasDataDrivenPropertyDifference(other.template get().value))... }); return result; } }; }; template using ConcatenateProperties = typename TypeListConcat::template ExpandInto; } // namespace style } // namespace mbgl