#pragma once #include #include #include #include #include #include #include #include namespace mbgl { class GeometryTileFeature; namespace style { // A CompositeFunction consists of an outer zoom function whose stop range values are // "inner" source functions. It provides the GL Native implementation of // "zoom-and-property" functions from the style spec. template class CompositeFunction { public: using InnerStops = std::conditional_t< util::Interpolatable, variant< ExponentialStops, IntervalStops, CategoricalStops>, variant< IntervalStops, CategoricalStops>>; using Stops = std::conditional_t< util::Interpolatable, variant< CompositeExponentialStops, CompositeIntervalStops, CompositeCategoricalStops>, variant< CompositeIntervalStops, CompositeCategoricalStops>>; CompositeFunction(std::string property_, Stops stops_, optional defaultValue_ = {}) : property(std::move(property_)), stops(std::move(stops_)), defaultValue(std::move(defaultValue_)) { } std::tuple, Range> coveringRanges(float zoom) const { return stops.match( [&] (const auto& s) { assert(!s.stops.empty()); auto minIt = s.stops.lower_bound(zoom); auto maxIt = s.stops.upper_bound(zoom); // lower_bound yields first element >= zoom, but we want the *last* // element <= zoom, so if we found a stop > zoom, back up by one. if (minIt != s.stops.begin() && minIt != s.stops.end() && minIt->first > zoom) { minIt--; } return std::make_tuple( Range { minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first, maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first }, Range { s.innerStops(minIt == s.stops.end() ? s.stops.rbegin()->second : minIt->second), s.innerStops(maxIt == s.stops.end() ? s.stops.rbegin()->second : maxIt->second) } ); } ); } template Range evaluate(Range coveringStops, const Feature& feature, T finalDefaultValue) const { optional v = feature.getValue(property); if (!v) { return { defaultValue.value_or(finalDefaultValue), defaultValue.value_or(finalDefaultValue) }; } auto eval = [&] (const auto& s) { return s.evaluate(*v).value_or(defaultValue.value_or(finalDefaultValue)); }; return Range { coveringStops.min.match(eval), coveringStops.max.match(eval) }; } T evaluate(float zoom, const GeometryTileFeature& feature, T finalDefaultValue) const { std::tuple, Range> ranges = coveringRanges(zoom); Range resultRange = evaluate(std::get<1>(ranges), feature, finalDefaultValue); return util::interpolate( resultRange.min, resultRange.max, util::interpolationFactor(1.0f, std::get<0>(ranges), zoom)); } friend bool operator==(const CompositeFunction& lhs, const CompositeFunction& rhs) { return std::tie(lhs.property, lhs.stops, lhs.defaultValue) == std::tie(rhs.property, rhs.stops, rhs.defaultValue); } std::string property; Stops stops; optional defaultValue; }; } // namespace style } // namespace mbgl