diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2016-10-28 16:39:50 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2017-02-02 09:44:42 -0800 |
commit | 141e995806576364d185626176c1b993fc519291 (patch) | |
tree | ecdc41fc7699f2a1a9e9456157348451ebe99597 /include/mbgl/style/function | |
parent | 6a6bddb4537004cc1bfc506e76772de74d33f3f7 (diff) | |
download | qtlocation-mapboxgl-141e995806576364d185626176c1b993fc519291.tar.gz |
[core] Add support for data-driven styling
Diffstat (limited to 'include/mbgl/style/function')
-rw-r--r-- | include/mbgl/style/function/camera_function.hpp | 41 | ||||
-rw-r--r-- | include/mbgl/style/function/categorical_stops.hpp | 42 | ||||
-rw-r--r-- | include/mbgl/style/function/composite_function.hpp | 109 | ||||
-rw-r--r-- | include/mbgl/style/function/exponential_stops.hpp | 54 | ||||
-rw-r--r-- | include/mbgl/style/function/identity_stops.hpp | 20 | ||||
-rw-r--r-- | include/mbgl/style/function/interval_stops.hpp | 49 | ||||
-rw-r--r-- | include/mbgl/style/function/source_function.hpp | 56 |
7 files changed, 371 insertions, 0 deletions
diff --git a/include/mbgl/style/function/camera_function.hpp b/include/mbgl/style/function/camera_function.hpp new file mode 100644 index 0000000000..a96978939d --- /dev/null +++ b/include/mbgl/style/function/camera_function.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include <mbgl/style/function/exponential_stops.hpp> +#include <mbgl/style/function/interval_stops.hpp> +#include <mbgl/util/interpolate.hpp> +#include <mbgl/util/variant.hpp> + +namespace mbgl { +namespace style { + +template <class T> +class CameraFunction { +public: + using Stops = std::conditional_t< + util::Interpolatable<T>, + variant< + ExponentialStops<T>, + IntervalStops<T>>, + variant< + IntervalStops<T>>>; + + CameraFunction(Stops stops_) + : stops(std::move(stops_)) { + } + + T evaluate(float zoom) const { + return stops.match([&] (const auto& s) { + return s.evaluate(Value(double(zoom))); + }); + } + + friend bool operator==(const CameraFunction& lhs, + const CameraFunction& rhs) { + return lhs.stops == rhs.stops; + } + + Stops stops; +}; + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/function/categorical_stops.hpp b/include/mbgl/style/function/categorical_stops.hpp new file mode 100644 index 0000000000..11ec2a0e5a --- /dev/null +++ b/include/mbgl/style/function/categorical_stops.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include <mbgl/util/feature.hpp> +#include <mbgl/util/variant.hpp> + +#include <cassert> +#include <utility> +#include <map> + +namespace mbgl { +namespace style { + +class CategoricalValue : public variant<bool, int64_t, std::string> { +public: + using variant<bool, int64_t, std::string>::variant; +}; + +template <class T> +class CategoricalStops { +public: + using Stops = std::map<CategoricalValue, T>; + + Stops stops; + T defaultValue; + + CategoricalStops() = default; + CategoricalStops(Stops stops_, T defaultValue_ = T()) + : stops(std::move(stops_)), + defaultValue(std::move(defaultValue_)) { + assert(stops.size() > 0); + } + + T evaluate(const Value&) const; + + friend bool operator==(const CategoricalStops& lhs, + const CategoricalStops& rhs) { + return lhs.stops == rhs.stops && lhs.defaultValue == rhs.defaultValue; + } +}; + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/function/composite_function.hpp b/include/mbgl/style/function/composite_function.hpp new file mode 100644 index 0000000000..169a455435 --- /dev/null +++ b/include/mbgl/style/function/composite_function.hpp @@ -0,0 +1,109 @@ +#pragma once + +#include <mbgl/style/function/exponential_stops.hpp> +#include <mbgl/style/function/interval_stops.hpp> +#include <mbgl/style/function/categorical_stops.hpp> +#include <mbgl/util/interpolate.hpp> +#include <mbgl/util/range.hpp> +#include <mbgl/util/variant.hpp> + +#include <string> +#include <tuple> + +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 T> +class CompositeFunction { +public: + using InnerStops = std::conditional_t< + util::Interpolatable<T>, + variant< + ExponentialStops<T>, + IntervalStops<T>, + CategoricalStops<T>>, + variant< + IntervalStops<T>, + CategoricalStops<T>>>; + + using Stops = std::conditional_t< + util::Interpolatable<T>, + variant< + std::map<float, ExponentialStops<T>>, + std::map<float, IntervalStops<T>>, + std::map<float, CategoricalStops<T>>>, + variant< + std::map<float, IntervalStops<T>>, + std::map<float, CategoricalStops<T>>>>; + + CompositeFunction(std::string property_, Stops stops_) + : property(std::move(property_)), + stops(std::move(stops_)) { + } + + std::tuple<Range<float>, Range<InnerStops>> + coveringRanges(float zoom) const { + return stops.match( + [&] (const auto& s) { + assert(!s.empty()); + auto minIt = s.lower_bound(zoom); + auto maxIt = s.upper_bound(zoom); + if (minIt != s.begin()) { + minIt--; + } + return std::make_tuple( + Range<float> { + minIt == s.end() ? s.rbegin()->first : minIt->first, + maxIt == s.end() ? s.rbegin()->first : maxIt->first + }, + Range<InnerStops> { + minIt == s.end() ? s.rbegin()->second : minIt->second, + maxIt == s.end() ? s.rbegin()->second : maxIt->second + } + ); + } + ); + } + + Range<T> evaluate(Range<InnerStops> coveringStops, + const GeometryTileFeature& feature) const { + optional<Value> v = feature.getValue(property); + if (!v) { + return { T(), T() }; + } + auto eval = [&] (const auto& s) { + return s.evaluate(*v); + }; + return Range<T> { + coveringStops.min.match(eval), + coveringStops.max.match(eval) + }; + } + + T evaluate(float zoom, const GeometryTileFeature& feature) const { + std::tuple<Range<float>, Range<InnerStops>> ranges = coveringRanges(zoom); + Range<T> resultRange = evaluate(std::get<1>(ranges), feature); + 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 lhs.property == rhs.property && lhs.stops == rhs.stops; + } + + std::string property; + Stops stops; +}; + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/function/exponential_stops.hpp b/include/mbgl/style/function/exponential_stops.hpp new file mode 100644 index 0000000000..7bd8783614 --- /dev/null +++ b/include/mbgl/style/function/exponential_stops.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include <mbgl/util/feature.hpp> +#include <mbgl/util/interpolate.hpp> + +#include <map> + +namespace mbgl { +namespace style { + +template <class T> +class ExponentialStops { +public: + using Stops = std::map<float, T>; + + Stops stops; + float base = 1.0f; + + ExponentialStops() = default; + ExponentialStops(Stops stops_, float base_ = 1.0f) + : stops(std::move(stops_)), + base(base_) { + } + + T evaluate(const Value& value) const { + if (stops.empty()) { + assert(false); + return T(); + } + + optional<float> z = numericValue<float>(value); + if (!z) { + return T(); + } + + auto it = stops.upper_bound(*z); + if (it == stops.end()) { + return stops.rbegin()->second; + } else if (it == stops.begin()) { + return stops.begin()->second; + } else { + return util::interpolate(std::prev(it)->second, it->second, + util::interpolationFactor(base, { std::prev(it)->first, it->first }, *z)); + } + } + + friend bool operator==(const ExponentialStops& lhs, + const ExponentialStops& rhs) { + return lhs.stops == rhs.stops && lhs.base == rhs.base; + } +}; + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/function/identity_stops.hpp b/include/mbgl/style/function/identity_stops.hpp new file mode 100644 index 0000000000..4e199f2e15 --- /dev/null +++ b/include/mbgl/style/function/identity_stops.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include <mbgl/util/feature.hpp> + +namespace mbgl { +namespace style { + +template <class T> +class IdentityStops { +public: + T evaluate(const Value&) const; + + friend bool operator==(const IdentityStops&, + const IdentityStops&) { + return true; + } +}; + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/function/interval_stops.hpp b/include/mbgl/style/function/interval_stops.hpp new file mode 100644 index 0000000000..cf879d730b --- /dev/null +++ b/include/mbgl/style/function/interval_stops.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include <mbgl/util/feature.hpp> + +#include <map> + +namespace mbgl { +namespace style { + +template <class T> +class IntervalStops { +public: + using Stops = std::map<float, T>; + Stops stops; + + IntervalStops() = default; + IntervalStops(Stops stops_) + : stops(std::move(stops_)) { + } + + T evaluate(const Value& value) const { + if (stops.empty()) { + assert(false); + return T(); + } + + optional<float> z = numericValue<float>(value); + if (!z) { + return T(); + } + + auto it = stops.upper_bound(*z); + if (it == stops.end()) { + return stops.rbegin()->second; + } else if (it == stops.begin()) { + return stops.begin()->second; + } else { + return std::prev(it)->second; + } + } + + friend bool operator==(const IntervalStops& lhs, + const IntervalStops& rhs) { + return lhs.stops == rhs.stops; + } +}; + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/function/source_function.hpp b/include/mbgl/style/function/source_function.hpp new file mode 100644 index 0000000000..e998be082a --- /dev/null +++ b/include/mbgl/style/function/source_function.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include <mbgl/style/function/exponential_stops.hpp> +#include <mbgl/style/function/interval_stops.hpp> +#include <mbgl/style/function/categorical_stops.hpp> +#include <mbgl/style/function/identity_stops.hpp> +#include <mbgl/tile/geometry_tile_data.hpp> +#include <mbgl/util/interpolate.hpp> +#include <mbgl/util/variant.hpp> + +#include <string> + +namespace mbgl { +namespace style { + +template <class T> +class SourceFunction { +public: + using Stops = std::conditional_t< + util::Interpolatable<T>, + variant< + ExponentialStops<T>, + IntervalStops<T>, + CategoricalStops<T>, + IdentityStops<T>>, + variant< + IntervalStops<T>, + CategoricalStops<T>, + IdentityStops<T>>>; + + SourceFunction(std::string property_, Stops stops_) + : property(std::move(property_)), + stops(std::move(stops_)) { + } + + T evaluate(const GeometryTileFeature& feature) const { + optional<Value> v = feature.getValue(property); + if (!v) { + return T(); + } + return stops.match([&] (const auto& s) { + return s.evaluate(*v); + }); + } + + friend bool operator==(const SourceFunction& lhs, + const SourceFunction& rhs) { + return lhs.property == rhs.property && lhs.stops == rhs.stops; + } + + std::string property; + Stops stops; +}; + +} // namespace style +} // namespace mbgl |