summaryrefslogtreecommitdiff
path: root/include/mbgl/style/conversion/function.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/mbgl/style/conversion/function.hpp')
-rw-r--r--include/mbgl/style/conversion/function.hpp400
1 files changed, 20 insertions, 380 deletions
diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp
index 932925c53c..5ddede324b 100644
--- a/include/mbgl/style/conversion/function.hpp
+++ b/include/mbgl/style/conversion/function.hpp
@@ -3,224 +3,15 @@
#include <mbgl/style/function/camera_function.hpp>
#include <mbgl/style/function/source_function.hpp>
#include <mbgl/style/function/composite_function.hpp>
-#include <mbgl/style/function/convert.hpp>
-#include <mbgl/style/function/categorical_stops.hpp>
-#include <mbgl/style/function/exponential_stops.hpp>
-#include <mbgl/style/function/interval_stops.hpp>
-#include <mbgl/style/function/identity_stops.hpp>
-#include <mbgl/style/function/composite_exponential_stops.hpp>
-#include <mbgl/style/function/composite_interval_stops.hpp>
-#include <mbgl/style/function/composite_categorical_stops.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/constant.hpp>
-#include <mbgl/util/ignore.hpp>
-#include <mbgl/util/variant.hpp>
+#include <mbgl/style/expression/expression.hpp>
+#include <mbgl/style/expression/value.hpp>
namespace mbgl {
namespace style {
namespace conversion {
-template <class D, class R>
-optional<std::map<D, R>> convertStops(const Convertible& value, Error& error) {
- auto stopsValue = objectMember(value, "stops");
- if (!stopsValue) {
- error = { "function value must specify stops" };
- return {};
- }
-
- if (!isArray(*stopsValue)) {
- error = { "function stops must be an array" };
- return {};
- }
-
- if (arrayLength(*stopsValue) == 0) {
- error = { "function must have at least one stop" };
- return {};
- }
-
- std::map<D, R> stops;
- for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) {
- const auto& stopValue = arrayMember(*stopsValue, i);
-
- if (!isArray(stopValue)) {
- error = { "function stop must be an array" };
- return {};
- }
-
- if (arrayLength(stopValue) != 2) {
- error = { "function stop must have two elements" };
- return {};
- }
-
- optional<D> d = convert<D>(arrayMember(stopValue, 0), error);
- if (!d) {
- return {};
- }
-
- optional<R> r = convert<R>(arrayMember(stopValue, 1), error);
- if (!r) {
- return {};
- }
-
- stops.emplace(*d, *r);
- }
-
- return stops;
-}
-
-template <class T>
-struct Converter<ExponentialStops<T>> {
- static constexpr const char * type = "exponential";
-
- optional<ExponentialStops<T>> operator()(const Convertible& value, Error& error) const {
- auto stops = convertStops<float, T>(value, error);
- if (!stops) {
- return {};
- }
-
- auto baseValue = objectMember(value, "base");
- if (!baseValue) {
- return ExponentialStops<T>(*stops);
- }
-
- optional<float> base = toNumber(*baseValue);
- if (!base) {
- error = { "function base must be a number"};
- return {};
- }
-
- return ExponentialStops<T>(*stops, *base);
- }
-};
-
-template <class T>
-struct Converter<IntervalStops<T>> {
- static constexpr const char * type = "interval";
-
- optional<IntervalStops<T>> operator()(const Convertible& value, Error& error) const {
- auto stops = convertStops<float, T>(value, error);
- if (!stops) {
- return {};
- }
- return IntervalStops<T>(*stops);
- }
-};
-
-template <>
-struct Converter<CategoricalValue> {
- optional<CategoricalValue> operator()(const Convertible& value, Error& error) const {
- auto b = toBool(value);
- if (b) {
- return { *b };
- }
-
- auto n = toNumber(value);
- if (n) {
- return { int64_t(*n) };
- }
-
- auto s = toString(value);
- if (s) {
- return { *s };
- }
-
- error = { "stop domain value must be a number, string, or boolean" };
- return {};
- }
-};
-
-template <class T>
-struct Converter<CategoricalStops<T>> {
- static constexpr const char * type = "categorical";
-
- optional<CategoricalStops<T>> operator()(const Convertible& value, Error& error) const {
- auto stops = convertStops<CategoricalValue, T>(value, error);
- if (!stops) {
- return {};
- }
- return CategoricalStops<T>(
- std::map<CategoricalValue, T>((*stops).begin(), (*stops).end()));
- }
-};
-
-template <class T>
-struct Converter<IdentityStops<T>> {
- static constexpr const char * type = "identity";
-
- optional<IdentityStops<T>> operator()(const Convertible&, Error&) const {
- return IdentityStops<T>();
- }
-};
-
-template <class, class>
-struct StopsConverter;
-
-template <class T, class... Ts>
-struct StopsConverter<T, variant<Ts...>> {
-public:
- optional<variant<Ts...>> operator()(const Convertible& value, Error& error) const {
- std::string type = util::Interpolatable<T>::value ? "exponential" : "interval";
-
- auto typeValue = objectMember(value, "type");
- if (typeValue && toString(*typeValue)) {
- type = *toString(*typeValue);
- }
-
- bool matched = false;
- optional<variant<Ts...>> result;
-
- // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226
- auto tryConvert = [&] (auto* tp) {
- using Stops = std::decay_t<decltype(*tp)>;
- if (type == Converter<Stops>::type) {
- matched = true;
- optional<Stops> stops = convert<Stops>(value, error);
- if (stops) {
- result = variant<Ts...>(*stops);
- }
- }
- };
-
- util::ignore({
- (tryConvert((Ts*)nullptr), 0)...
- });
-
- if (!matched) {
- error = { "unsupported function type" };
- return {};
- }
-
- return result;
- }
-};
-
-template <class T>
-struct Converter<CameraFunction<T>> {
- optional<CameraFunction<T>> operator()(const Convertible& value, Error& error) const {
- if (!isObject(value)) {
- error = { "function must be an object" };
- return {};
- }
-
- using Stops = std::conditional_t<
- util::Interpolatable<T>::value,
- variant<
- ExponentialStops<T>,
- IntervalStops<T>>,
- variant<
- IntervalStops<T>>>;
-
- auto stops = StopsConverter<T, Stops>()(value, error);
- if (!stops) {
- return {};
- }
-
- return CameraFunction<T>((*stops).match([&] (const auto& s) {
- return expression::Convert::toExpression(s);
- }), false);
- }
-};
-
template <class T>
optional<optional<T>> convertDefaultValue(const Convertible& value, Error& error) {
auto defaultValueValue = objectMember(value, "default");
@@ -237,199 +28,48 @@ optional<optional<T>> convertDefaultValue(const Convertible& value, Error& error
return { *defaultValue };
}
-template <class T>
-struct Converter<SourceFunction<T>> {
- optional<SourceFunction<T>> operator()(const Convertible& value, Error& error) const {
- if (!isObject(value)) {
- error = { "function must be an object" };
- return {};
- }
-
- auto propertyValue = objectMember(value, "property");
- if (!propertyValue) {
- error = { "function must specify property" };
- return {};
- }
-
- auto propertyString = toString(*propertyValue);
- if (!propertyString) {
- error = { "function property must be a string" };
- return {};
- }
-
- using Stops = std::conditional_t<
- util::Interpolatable<T>::value,
- variant<
- ExponentialStops<T>,
- IntervalStops<T>,
- CategoricalStops<T>,
- IdentityStops<T>>,
- variant<
- IntervalStops<T>,
- CategoricalStops<T>,
- IdentityStops<T>>>;
-
- auto stops = StopsConverter<T, Stops>()(value, error);
- if (!stops) {
- return {};
- }
-
- auto defaultValue = convertDefaultValue<T>(value, error);
- if (!defaultValue) {
- return {};
- }
-
- return SourceFunction<T>((*stops).match([&] (const auto& s) {
- return expression::Convert::toExpression(*propertyString, s);
- }), *defaultValue);
- }
-};
-
-template <class S>
-struct CompositeValue : std::pair<float, S> {
- using std::pair<float, S>::pair;
-};
-
-template <class S>
-struct Converter<CompositeValue<S>> {
- optional<CompositeValue<S>> operator()(const Convertible& value, Error& error) const {
- if (!isObject(value)) {
- error = { "stop must be an object" };
- return {};
- }
-
- auto zoomValue = objectMember(value, "zoom");
- if (!zoomValue) {
- error = { "stop must specify zoom" };
- return {};
- }
-
- auto propertyValue = objectMember(value, "value");
- if (!propertyValue) {
- error = { "stop must specify value" };
- return {};
- }
-
- optional<float> z = convert<float>(*zoomValue, error);
- if (!z) {
- return {};
- }
-
- optional<S> s = convert<S>(*propertyValue, error);
- if (!s) {
- return {};
- }
-
- return CompositeValue<S> { *z, *s };
- }
-};
+optional<std::unique_ptr<expression::Expression>> convertCameraFunctionToExpression(expression::type::Type, const Convertible&, Error&);
+optional<std::unique_ptr<expression::Expression>> convertSourceFunctionToExpression(expression::type::Type, const Convertible&, Error&);
+optional<std::unique_ptr<expression::Expression>> convertCompositeFunctionToExpression(expression::type::Type, const Convertible&, Error&);
template <class T>
-struct Converter<CompositeExponentialStops<T>> {
- static constexpr const char * type = "exponential";
-
- optional<CompositeExponentialStops<T>> operator()(const Convertible& value, Error& error) const {
- auto stops = convertStops<CompositeValue<float>, T>(value, error);
- if (!stops) {
+struct Converter<CameraFunction<T>> {
+ optional<CameraFunction<T>> operator()(const Convertible& value, Error& error) const {
+ auto expression = convertCameraFunctionToExpression(expression::valueTypeToExpressionType<T>(), value, error);
+ if (!expression) {
return {};
}
-
- auto base = 1.0f;
- auto baseValue = objectMember(value, "base");
- if (baseValue && toNumber(*baseValue)) {
- base = *toNumber(*baseValue);
- }
-
- std::map<float, std::map<float, T>> convertedStops;
- for (const auto& stop : *stops) {
- convertedStops[stop.first.first].emplace(stop.first.second, stop.second);
- }
-
- return CompositeExponentialStops<T>(convertedStops, base);
+ return CameraFunction<T>(std::move(*expression), false);
}
};
template <class T>
-struct Converter<CompositeIntervalStops<T>> {
- static constexpr const char * type = "interval";
-
- optional<CompositeIntervalStops<T>> operator()(const Convertible& value, Error& error) const {
- auto stops = convertStops<CompositeValue<float>, T>(value, error);
- if (!stops) {
+struct Converter<SourceFunction<T>> {
+ optional<SourceFunction<T>> operator()(const Convertible& value, Error& error) const {
+ auto expression = convertSourceFunctionToExpression(expression::valueTypeToExpressionType<T>(), value, error);
+ if (!expression) {
return {};
}
-
- std::map<float, std::map<float, T>> convertedStops;
- for (const auto& stop : *stops) {
- convertedStops[stop.first.first].emplace(stop.first.second, stop.second);
- }
-
- return CompositeIntervalStops<T>(convertedStops);
- }
-};
-
-template <class T>
-struct Converter<CompositeCategoricalStops<T>> {
- static constexpr const char * type = "categorical";
-
- optional<CompositeCategoricalStops<T>> operator()(const Convertible& value, Error& error) const {
- auto stops = convertStops<CompositeValue<CategoricalValue>, T>(value, error);
- if (!stops) {
+ auto defaultValue = convertDefaultValue<T>(value, error);
+ if (!defaultValue) {
return {};
}
-
- std::map<float, std::map<CategoricalValue, T>> convertedStops;
- for (const auto& stop : *stops) {
- convertedStops[stop.first.first].emplace(stop.first.second, stop.second);
- }
-
- return CompositeCategoricalStops<T>(convertedStops);
+ return SourceFunction<T>(std::move(*expression), *defaultValue);
}
};
template <class T>
struct Converter<CompositeFunction<T>> {
optional<CompositeFunction<T>> operator()(const Convertible& value, Error& error) const {
- if (!isObject(value)) {
- error = { "function must be an object" };
+ auto expression = convertCompositeFunctionToExpression(expression::valueTypeToExpressionType<T>(), value, error);
+ if (!expression) {
return {};
}
-
- auto propertyValue = objectMember(value, "property");
- if (!propertyValue) {
- error = { "function must specify property" };
- return {};
- }
-
- auto propertyString = toString(*propertyValue);
- if (!propertyString) {
- error = { "function property must be a string" };
- return {};
- }
-
- using Stops = std::conditional_t<
- util::Interpolatable<T>::value,
- variant<
- CompositeExponentialStops<T>,
- CompositeIntervalStops<T>,
- CompositeCategoricalStops<T>>,
- variant<
- CompositeIntervalStops<T>,
- CompositeCategoricalStops<T>>>;
-
- auto stops = StopsConverter<T, Stops>()(value, error);
- if (!stops) {
- return {};
- }
-
auto defaultValue = convertDefaultValue<T>(value, error);
if (!defaultValue) {
return {};
}
-
- return CompositeFunction<T>((*stops).match([&] (const auto& s) {
- return expression::Convert::toExpression(*propertyString, s);
- }), *defaultValue);
+ return CompositeFunction<T>(std::move(*expression), *defaultValue);
}
};