diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2017-06-16 10:16:11 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2017-06-19 09:15:08 -0700 |
commit | 1de8aeed31226f167c528bfdcfae97d12c5d67ca (patch) | |
tree | 9104590c9c13d32878685ca4433780e0da96f259 /include/mbgl/style | |
parent | 8699bcdbf07550107dee77e2fddf3aa982b9fbfd (diff) | |
download | qtlocation-mapboxgl-1de8aeed31226f167c528bfdcfae97d12c5d67ca.tar.gz |
[core] Fix composite function approximation for non-integer stops
Diffstat (limited to 'include/mbgl/style')
-rw-r--r-- | include/mbgl/style/function/composite_function.hpp | 75 |
1 files changed, 53 insertions, 22 deletions
diff --git a/include/mbgl/style/function/composite_function.hpp b/include/mbgl/style/function/composite_function.hpp index 9275ccdf8f..b82e63bc37 100644 --- a/include/mbgl/style/function/composite_function.hpp +++ b/include/mbgl/style/function/composite_function.hpp @@ -49,8 +49,16 @@ public: defaultValue(std::move(defaultValue_)) { } - std::tuple<Range<float>, Range<InnerStops>> - coveringRanges(float zoom) const { + struct CoveringRanges { + float zoom; + Range<float> coveringZoomRange; + Range<InnerStops> coveringStopsRange; + }; + + // Return the relevant stop zoom values and inner stops that bracket a given zoom level. This + // is the first step toward evaluating the function, and is used for in the course of both partial + // evaluation of data-driven paint properties, and full evaluation of data-driven layout properties. + CoveringRanges coveringRanges(float zoom) const { return stops.match( [&] (const auto& s) { assert(!s.stops.empty()); @@ -63,7 +71,8 @@ public: minIt--; } - return std::make_tuple( + return CoveringRanges { + zoom, Range<float> { minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first, maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first @@ -72,38 +81,49 @@ public: s.innerStops(minIt == s.stops.end() ? s.stops.rbegin()->second : minIt->second), s.innerStops(maxIt == s.stops.end() ? s.stops.rbegin()->second : maxIt->second) } - ); + }; } ); } + // Given a range of zoom values (typically two adjacent integer zoom levels, e.g. 5.0 and 6.0), + // return the covering ranges for both. This is used in the course of partial evaluation for + // data-driven paint properties. + Range<CoveringRanges> rangeOfCoveringRanges(Range<float> zoomRange) { + return Range<CoveringRanges> { + coveringRanges(zoomRange.min), + coveringRanges(zoomRange.max) + }; + } + + // Given the covering ranges for range of zoom values (typically two adjacent integer zoom levels, + // e.g. 5.0 and 6.0), and a feature, return the results of fully evaluating the function for that + // feature at each of the two zoom levels. These two results are what go into the paint vertex buffers + // for vertices associated with this feature. The shader will interpolate between them at render time. template <class Feature> - Range<T> evaluate(Range<InnerStops> coveringStops, - const Feature& feature, - T finalDefaultValue) const { - optional<Value> v = feature.getValue(property); - if (!v) { - return { + Range<T> evaluate(const Range<CoveringRanges>& ranges, const Feature& feature, T finalDefaultValue) { + optional<Value> value = feature.getValue(property); + if (!value) { + return Range<T> { 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<T> { - coveringStops.min.match(eval), - coveringStops.max.match(eval) + evaluateFinal(ranges.min, *value, finalDefaultValue), + evaluateFinal(ranges.max, *value, finalDefaultValue) }; } - T evaluate(float zoom, const GeometryTileFeature& feature, T finalDefaultValue) const { - std::tuple<Range<float>, Range<InnerStops>> ranges = coveringRanges(zoom); - Range<T> resultRange = evaluate(std::get<1>(ranges), feature, finalDefaultValue); - return util::interpolate( - resultRange.min, - resultRange.max, - util::interpolationFactor(1.0f, std::get<0>(ranges), zoom)); + // Fully evaluate the function for a zoom value and feature. This is used when evaluating data-driven + // layout properties. + template <class Feature> + T evaluate(float zoom, const Feature& feature, T finalDefaultValue) const { + optional<Value> value = feature.getValue(property); + if (!value) { + return defaultValue.value_or(finalDefaultValue); + } + return evaluateFinal(coveringRanges(zoom), *value, finalDefaultValue); } friend bool operator==(const CompositeFunction& lhs, @@ -115,6 +135,17 @@ public: std::string property; Stops stops; optional<T> defaultValue; + +private: + T evaluateFinal(const CoveringRanges& ranges, const Value& value, T finalDefaultValue) const { + auto eval = [&] (const auto& s) { + return s.evaluate(value).value_or(defaultValue.value_or(finalDefaultValue)); + }; + return util::interpolate( + ranges.coveringStopsRange.min.match(eval), + ranges.coveringStopsRange.max.match(eval), + util::interpolationFactor(1.0f, ranges.coveringZoomRange, ranges.zoom)); + } }; } // namespace style |