diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2017-09-26 15:44:42 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2017-09-26 15:44:42 -0700 |
commit | cd7e4c2f07aaa6a13ee54c8f89aeb52f6c6b807b (patch) | |
tree | 7f233bdbb0178f3b7d36c0447957347359d5fdd8 | |
parent | 143b7ac5d4fe151729b5579e496aa74f3c9ef68a (diff) | |
download | qtlocation-mapboxgl-cd7e4c2f07aaa6a13ee54c8f89aeb52f6c6b807b.tar.gz |
Move conversions to cpp files where possible
25 files changed, 1112 insertions, 978 deletions
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index 00b04140bd..fc1cc7b02f 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -373,16 +373,26 @@ set(MBGL_CORE_FILES include/mbgl/style/conversion/geojson_options.hpp include/mbgl/style/conversion/layer.hpp include/mbgl/style/conversion/light.hpp - include/mbgl/style/conversion/make_property_setters.hpp include/mbgl/style/conversion/position.hpp - include/mbgl/style/conversion/property_setter.hpp include/mbgl/style/conversion/property_value.hpp include/mbgl/style/conversion/source.hpp include/mbgl/style/conversion/tileset.hpp include/mbgl/style/conversion/transition_options.hpp + src/mbgl/style/conversion/constant.cpp + src/mbgl/style/conversion/coordinate.cpp + src/mbgl/style/conversion/filter.cpp src/mbgl/style/conversion/geojson.cpp + src/mbgl/style/conversion/geojson_options.cpp src/mbgl/style/conversion/json.hpp + src/mbgl/style/conversion/layer.cpp + src/mbgl/style/conversion/light.cpp + src/mbgl/style/conversion/make_property_setters.hpp + src/mbgl/style/conversion/position.cpp + src/mbgl/style/conversion/property_setter.hpp + src/mbgl/style/conversion/source.cpp src/mbgl/style/conversion/stringify.hpp + src/mbgl/style/conversion/tileset.cpp + src/mbgl/style/conversion/transition_options.cpp # style/function include/mbgl/style/function/camera_function.hpp diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp index 3a9dd3e052..50d31ab9a8 100644 --- a/include/mbgl/style/conversion/constant.hpp +++ b/include/mbgl/style/conversion/constant.hpp @@ -1,7 +1,6 @@ #pragma once #include <mbgl/style/conversion.hpp> -#include <mbgl/util/optional.hpp> #include <mbgl/util/color.hpp> #include <mbgl/util/enum.hpp> #include <mbgl/util/string.hpp> @@ -16,38 +15,17 @@ namespace conversion { template <> struct Converter<bool> { - optional<bool> operator()(const Value& value, Error& error) const { - optional<bool> converted = toBool(value); - if (!converted) { - error = { "value must be a boolean" }; - return {}; - } - return *converted; - } + optional<bool> operator()(const Value& value, Error& error) const; }; template <> struct Converter<float> { - optional<float> operator()(const Value& value, Error& error) const { - optional<float> converted = toNumber(value); - if (!converted) { - error = { "value must be a number" }; - return {}; - } - return *converted; - } + optional<float> operator()(const Value& value, Error& error) const; }; template <> struct Converter<std::string> { - optional<std::string> operator()(const Value& value, Error& error) const { - optional<std::string> converted = toString(value); - if (!converted) { - error = { "value must be a string" }; - return {}; - } - return *converted; - } + optional<std::string> operator()(const Value& value, Error& error) const; }; template <class T> @@ -71,21 +49,7 @@ struct Converter<T, typename std::enable_if_t<std::is_enum<T>::value>> { template <> struct Converter<Color> { - optional<Color> operator()(const Value& value, Error& error) const { - optional<std::string> string = toString(value); - if (!string) { - error = { "value must be a string" }; - return {}; - } - - optional<Color> color = Color::parse(*string); - if (!color) { - error = { "value must be a valid color" }; - return {}; - } - - return *color; - } + optional<Color> operator()(const Value& value, Error& error) const; }; template <size_t N> @@ -111,50 +75,12 @@ struct Converter<std::array<float, N>> { template <> struct Converter<std::vector<float>> { - optional<std::vector<float>> operator()(const Value& value, Error& error) const { - if (!isArray(value)) { - error = { "value must be an array" }; - return {}; - } - - std::vector<float> result; - result.reserve(arrayLength(value)); - - for (std::size_t i = 0; i < arrayLength(value); ++i) { - optional<float> number = toNumber(arrayMember(value, i)); - if (!number) { - error = { "value must be an array of numbers" }; - return {}; - } - result.push_back(*number); - } - - return result; - } + optional<std::vector<float>> operator()(const Value& value, Error& error) const; }; template <> struct Converter<std::vector<std::string>> { - optional<std::vector<std::string>> operator()(const Value& value, Error& error) const { - if (!isArray(value)) { - error = { "value must be an array" }; - return {}; - } - - std::vector<std::string> result; - result.reserve(arrayLength(value)); - - for (std::size_t i = 0; i < arrayLength(value); ++i) { - optional<std::string> string = toString(arrayMember(value, i)); - if (!string) { - error = { "value must be an array of strings" }; - return {}; - } - result.push_back(*string); - } - - return result; - } + optional<std::vector<std::string>> operator()(const Value& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/coordinate.hpp b/include/mbgl/style/conversion/coordinate.hpp index 2c9a49ed70..8aa39283a8 100644 --- a/include/mbgl/style/conversion/coordinate.hpp +++ b/include/mbgl/style/conversion/coordinate.hpp @@ -10,25 +10,7 @@ namespace conversion { template<> struct Converter<LatLng> { public: - optional<LatLng> operator() (const Value& value, Error& error) const { - if (!isArray(value) || arrayLength(value) < 2 ) { - error = { "coordinate array must contain numeric longitude and latitude values" }; - return {}; - } - //Style spec uses GeoJSON convention for specifying coordinates - optional<double> latitude = toDouble(arrayMember(value, 1)); - optional<double> longitude = toDouble(arrayMember(value, 0)); - - if (!latitude || !longitude) { - error = { "coordinate array must contain numeric longitude and latitude values" }; - return {}; - } - if (*latitude < -90 || *latitude > 90 ){ - error = { "coordinate latitude must be between -90 and 90" }; - return {}; - } - return LatLng(*latitude, *longitude); - } + optional<LatLng> operator() (const Value& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/filter.hpp b/include/mbgl/style/conversion/filter.hpp index 6f51cd5770..d948ad0165 100644 --- a/include/mbgl/style/conversion/filter.hpp +++ b/include/mbgl/style/conversion/filter.hpp @@ -2,7 +2,6 @@ #include <mbgl/style/filter.hpp> #include <mbgl/style/conversion.hpp> -#include <mbgl/util/geometry.hpp> namespace mbgl { namespace style { @@ -11,244 +10,7 @@ namespace conversion { template <> struct Converter<Filter> { public: - optional<Filter> operator()(const Value& value, Error& error) const { - if (!isArray(value)) { - error = { "filter expression must be an array" }; - return {}; - } - - if (arrayLength(value) < 1) { - error = { "filter expression must have at least 1 element" }; - return {}; - } - - optional<std::string> op = toString(arrayMember(value, 0)); - if (!op) { - error = { "filter operator must be a string" }; - return {}; - } - - if (*op == "==") { - return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value, error); - } else if (*op == "!=") { - return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value, error); - } else if (*op == ">") { - return convertBinaryFilter<GreaterThanFilter>(value, error); - } else if (*op == ">=") { - return convertBinaryFilter<GreaterThanEqualsFilter>(value, error); - } else if (*op == "<") { - return convertBinaryFilter<LessThanFilter>(value, error); - } else if (*op == "<=") { - return convertBinaryFilter<LessThanEqualsFilter>(value, error); - } else if (*op == "in") { - return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value, error); - } else if (*op == "!in") { - return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value, error); - } else if (*op == "all") { - return convertCompoundFilter<AllFilter>(value, error); - } else if (*op == "any") { - return convertCompoundFilter<AnyFilter>(value, error); - } else if (*op == "none") { - return convertCompoundFilter<NoneFilter>(value, error); - } else if (*op == "has") { - return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value, error); - } else if (*op == "!has") { - return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value, error); - } - - error = { R"(filter operator must be one of "==", "!=", ">", ">=", "<", "<=", "in", "!in", "all", "any", "none", "has", or "!has")" }; - return {}; - } - -private: - optional<mbgl::Value> normalizeValue(const optional<mbgl::Value>& value, Error& error) const { - if (!value) { - error = { "filter expression value must be a boolean, number, or string" }; - return {}; - } else { - return *value; - } - } - - optional<FeatureType> toFeatureType(const Value& value, Error& error) const { - optional<std::string> type = toString(value); - if (!type) { - error = { "value for $type filter must be a string" }; - return {}; - } else if (*type == "Point") { - return FeatureType::Point; - } else if (*type == "LineString") { - return FeatureType::LineString; - } else if (*type == "Polygon") { - return FeatureType::Polygon; - } else { - error = { "value for $type filter must be Point, LineString, or Polygon" }; - return {}; - } - } - - optional<FeatureIdentifier> toFeatureIdentifier(const Value& value, Error& error) const { - optional<mbgl::Value> identifier = toValue(value); - if (!identifier) { - error = { "filter expression value must be a boolean, number, or string" }; - return {}; - } else { - return (*identifier).match( - [] (uint64_t t) -> optional<FeatureIdentifier> { return { t }; }, - [] ( int64_t t) -> optional<FeatureIdentifier> { return { t }; }, - [] ( double t) -> optional<FeatureIdentifier> { return { t }; }, - [] (const std::string& t) -> optional<FeatureIdentifier> { return { t }; }, - [&] (const auto&) -> optional<FeatureIdentifier> { - error = { "filter expression value must be a boolean, number, or string" }; - return {}; - }); - } - } - - template <class FilterType, class IdentifierFilterType> - optional<Filter> convertUnaryFilter(const Value& value, Error& error) const { - if (arrayLength(value) < 2) { - error = { "filter expression must have 2 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - if (*key == "$id") { - return { IdentifierFilterType {} }; - } else { - return { FilterType { *key } }; - } - } - - template <class FilterType, class TypeFilterType, class IdentifierFilterType> - optional<Filter> convertEqualityFilter(const Value& value, Error& error) const { - if (arrayLength(value) < 3) { - error = { "filter expression must have 3 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - if (*key == "$type") { - optional<FeatureType> filterValue = toFeatureType(arrayMember(value, 2), error); - if (!filterValue) { - return {}; - } - - return { TypeFilterType { *filterValue } }; - - } else if (*key == "$id") { - optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, 2), error); - if (!filterValue) { - return {}; - } - - return { IdentifierFilterType { *filterValue } }; - - } else { - optional<mbgl::Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); - if (!filterValue) { - return {}; - } - - return { FilterType { *key, *filterValue } }; - } - } - - template <class FilterType> - optional<Filter> convertBinaryFilter(const Value& value, Error& error) const { - if (arrayLength(value) < 3) { - error = { "filter expression must have 3 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - optional<mbgl::Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); - if (!filterValue) { - return {}; - } - - return { FilterType { *key, *filterValue } }; - } - - template <class FilterType, class TypeFilterType, class IdentifierFilterType> - optional<Filter> convertSetFilter(const Value& value, Error& error) const { - if (arrayLength(value) < 2) { - error = { "filter expression must at least 2 elements" }; - return {}; - } - - optional<std::string> key = toString(arrayMember(value, 1)); - if (!key) { - error = { "filter expression key must be a string" }; - return {}; - } - - if (*key == "$type") { - std::vector<FeatureType> values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - optional<FeatureType> filterValue = toFeatureType(arrayMember(value, i), error); - if (!filterValue) { - return {}; - } - values.push_back(*filterValue); - } - - return { TypeFilterType { std::move(values) } }; - - } else if (*key == "$id") { - std::vector<FeatureIdentifier> values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, i), error); - if (!filterValue) { - return {}; - } - values.push_back(*filterValue); - } - - return { IdentifierFilterType { std::move(values) } }; - - } else { - std::vector<mbgl::Value> values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - optional<mbgl::Value> filterValue = normalizeValue(toValue(arrayMember(value, i)), error); - if (!filterValue) { - return {}; - } - values.push_back(*filterValue); - } - - return { FilterType { *key, std::move(values) } }; - } - } - - template <class FilterType> - optional<Filter> convertCompoundFilter(const Value& value, Error& error) const { - std::vector<Filter> filters; - for (std::size_t i = 1; i < arrayLength(value); ++i) { - optional<Filter> element = operator()(arrayMember(value, i), error); - if (!element) { - return {}; - } - filters.push_back(*element); - } - - return { FilterType { std::move(filters) } }; - } + optional<Filter> operator()(const Value& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/geojson_options.hpp b/include/mbgl/style/conversion/geojson_options.hpp index 809935d762..e9a147a5cb 100644 --- a/include/mbgl/style/conversion/geojson_options.hpp +++ b/include/mbgl/style/conversion/geojson_options.hpp @@ -9,72 +9,7 @@ namespace conversion { template <> struct Converter<GeoJSONOptions> { - optional<GeoJSONOptions> operator()(const Value& value, Error& error) const { - GeoJSONOptions options; - - const auto maxzoomValue = objectMember(value, "maxzoom"); - if (maxzoomValue) { - if (toNumber(*maxzoomValue)) { - options.maxzoom = static_cast<uint8_t>(*toNumber(*maxzoomValue)); - } else { - error = { "GeoJSON source maxzoom value must be a number" }; - return {}; - } - } - - const auto bufferValue = objectMember(value, "buffer"); - if (bufferValue) { - if (toNumber(*bufferValue)) { - options.buffer = static_cast<uint16_t>(*toNumber(*bufferValue)); - } else { - error = { "GeoJSON source buffer value must be a number" }; - return {}; - } - } - - const auto toleranceValue = objectMember(value, "tolerance"); - if (toleranceValue) { - if (toNumber(*toleranceValue)) { - options.tolerance = static_cast<double>(*toNumber(*toleranceValue)); - } else { - error = { "GeoJSON source tolerance value must be a number" }; - return {}; - } - } - - const auto clusterValue = objectMember(value, "cluster"); - if (clusterValue) { - if (toBool(*clusterValue)) { - options.cluster = *toBool(*clusterValue); - } else { - error = { "GeoJSON source cluster value must be a boolean" }; - return {}; - } - } - - const auto clusterMaxZoomValue = objectMember(value, "clusterMaxZoom"); - if (clusterMaxZoomValue) { - if (toNumber(*clusterMaxZoomValue)) { - options.clusterMaxZoom = static_cast<uint8_t>(*toNumber(*clusterMaxZoomValue)); - } else { - error = { "GeoJSON source clusterMaxZoom value must be a number" }; - return {}; - } - } - - const auto clusterRadiusValue = objectMember(value, "clusterRadius"); - if (clusterRadiusValue) { - if (toNumber(*clusterRadiusValue)) { - options.clusterRadius = static_cast<double>(*toNumber(*clusterRadiusValue)); - } else { - error = { "GeoJSON source clusterRadius value must be a number" }; - return {}; - } - } - - return { options }; - } - + optional<GeoJSONOptions> operator()(const Value& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/layer.hpp b/include/mbgl/style/conversion/layer.hpp index 737a80a670..33953a593a 100644 --- a/include/mbgl/style/conversion/layer.hpp +++ b/include/mbgl/style/conversion/layer.hpp @@ -1,214 +1,22 @@ #pragma once #include <mbgl/style/layer.hpp> -#include <mbgl/style/layers/background_layer.hpp> -#include <mbgl/style/layers/circle_layer.hpp> -#include <mbgl/style/layers/fill_layer.hpp> -#include <mbgl/style/layers/fill_extrusion_layer.hpp> -#include <mbgl/style/layers/line_layer.hpp> -#include <mbgl/style/layers/raster_layer.hpp> -#include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/constant.hpp> -#include <mbgl/style/conversion/filter.hpp> -#include <mbgl/style/conversion/make_property_setters.hpp> + +#include <memory> namespace mbgl { namespace style { namespace conversion { -inline optional<Error> setLayoutProperty(Layer& layer, const std::string& name, const Value& value) { - static const auto setters = makeLayoutPropertySetters(); - auto it = setters.find(name); - if (it == setters.end()) { - return Error { "property not found" }; - } - return it->second(layer, value); -} - -inline optional<Error> setPaintProperty(Layer& layer, const std::string& name, const Value& value) { - static const auto setters = makePaintPropertySetters(); - auto it = setters.find(name); - if (it == setters.end()) { - return Error { "property not found" }; - } - return it->second(layer, value); -} - -inline optional<Error> setPaintProperties(Layer& layer, const Value& value) { - auto paintValue = objectMember(value, "paint"); - if (!paintValue) { - return {}; - } - return eachMember(*paintValue, [&] (const std::string& k, const Value& v) { - return setPaintProperty(layer, k, v); - }); -} - template <> struct Converter<std::unique_ptr<Layer>> { public: - optional<std::unique_ptr<Layer>> operator()(const Value& value, Error& error) const { - if (!isObject(value)) { - error = { "layer must be an object" }; - return {}; - } - - auto idValue = objectMember(value, "id"); - if (!idValue) { - error = { "layer must have an id" }; - return {}; - } - - optional<std::string> id = toString(*idValue); - if (!id) { - error = { "layer id must be a string" }; - return {}; - } - - auto typeValue = objectMember(value, "type"); - if (!typeValue) { - error = { "layer must have a type" }; - return {}; - } - - optional<std::string> type = toString(*typeValue); - if (!type) { - error = { "layer type must be a string" }; - return {}; - } - - optional<std::unique_ptr<Layer>> converted; - - if (*type == "fill") { - converted = convertVectorLayer<FillLayer>(*id, value, error); - } else if (*type == "fill-extrusion") { - converted = convertVectorLayer<FillExtrusionLayer>(*id, value, error); - } else if (*type == "line") { - converted = convertVectorLayer<LineLayer>(*id, value, error); - } else if (*type == "circle") { - converted = convertVectorLayer<CircleLayer>(*id, value, error); - } else if (*type == "symbol") { - converted = convertVectorLayer<SymbolLayer>(*id, value, error); - } else if (*type == "raster") { - converted = convertRasterLayer(*id, value, error); - } else if (*type == "background") { - converted = convertBackgroundLayer(*id, value, error); - } else { - error = { "invalid layer type" }; - return {}; - } - - if (!converted) { - return converted; - } - - std::unique_ptr<Layer> layer = std::move(*converted); - - auto minzoomValue = objectMember(value, "minzoom"); - if (minzoomValue) { - optional<float> minzoom = toNumber(*minzoomValue); - if (!minzoom) { - error = { "minzoom must be numeric" }; - return {}; - } - layer->setMinZoom(*minzoom); - } - - auto maxzoomValue = objectMember(value, "maxzoom"); - if (maxzoomValue) { - optional<float> maxzoom = toNumber(*maxzoomValue); - if (!maxzoom) { - error = { "maxzoom must be numeric" }; - return {}; - } - layer->setMaxZoom(*maxzoom); - } - - auto layoutValue = objectMember(value, "layout"); - if (layoutValue) { - if (!isObject(*layoutValue)) { - error = { "layout must be an object" }; - return {}; - } - optional<Error> error_ = eachMember(*layoutValue, [&] (const std::string& k, const Value& v) { - return setLayoutProperty(*layer, k, v); - }); - if (error_) { - error = *error_; - return {}; - } - } - - optional<Error> error_ = setPaintProperties(*layer, value); - if (error_) { - error = *error_; - return {}; - } - - return std::move(layer); - } - -private: - template <class LayerType> - optional<std::unique_ptr<Layer>> convertVectorLayer(const std::string& id, const Value& value, Error& error) const { - auto sourceValue = objectMember(value, "source"); - if (!sourceValue) { - error = { "layer must have a source" }; - return {}; - } - - optional<std::string> source = toString(*sourceValue); - if (!source) { - error = { "layer source must be a string" }; - return {}; - } - - std::unique_ptr<LayerType> layer = std::make_unique<LayerType>(id, *source); - - auto sourceLayerValue = objectMember(value, "source-layer"); - if (sourceLayerValue) { - optional<std::string> sourceLayer = toString(*sourceLayerValue); - if (!sourceLayer) { - error = { "layer source-layer must be a string" }; - return {}; - } - layer->setSourceLayer(*sourceLayer); - } - - auto filterValue = objectMember(value, "filter"); - if (filterValue) { - optional<Filter> filter = convert<Filter>(*filterValue, error); - if (!filter) { - return {}; - } - layer->setFilter(*filter); - } - - return { std::move(layer) }; - } - - optional<std::unique_ptr<Layer>> convertRasterLayer(const std::string& id, const Value& value, Error& error) const { - auto sourceValue = objectMember(value, "source"); - if (!sourceValue) { - error = { "layer must have a source" }; - return {}; - } - - optional<std::string> source = toString(*sourceValue); - if (!source) { - error = { "layer source must be a string" }; - return {}; - } - - return { std::make_unique<RasterLayer>(id, *source) }; - } - - optional<std::unique_ptr<Layer>> convertBackgroundLayer(const std::string& id, const Value&, Error&) const { - return { std::make_unique<BackgroundLayer>(id) }; - } + optional<std::unique_ptr<Layer>> operator()(const Value& value, Error& error) const; }; +optional<Error> setPaintProperties(Layer& layer, const Value& value); + } // namespace conversion } // namespace style } // namespace mbgl diff --git a/include/mbgl/style/conversion/light.hpp b/include/mbgl/style/conversion/light.hpp index fa5851fec6..38b6991b56 100644 --- a/include/mbgl/style/conversion/light.hpp +++ b/include/mbgl/style/conversion/light.hpp @@ -2,9 +2,6 @@ #include <mbgl/style/light.hpp> #include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/position.hpp> -#include <mbgl/style/conversion/property_value.hpp> -#include <mbgl/style/conversion/transition_options.hpp> namespace mbgl { namespace style { @@ -13,107 +10,7 @@ namespace conversion { template <> struct Converter<Light> { public: - optional<Light> operator()(const Value& value, Error& error) const { - if (!isObject(value)) { - error = { "light must be an object" }; - return {}; - } - - Light light; - - const auto anchor = objectMember(value, "anchor"); - if (anchor) { - optional<PropertyValue<LightAnchorType>> convertedAnchor = - convert<PropertyValue<LightAnchorType>>(*anchor, error); - - if (convertedAnchor) { - light.setAnchor(*convertedAnchor); - } else { - return {}; - } - } - - const auto anchorTransition = objectMember(value, "anchor-transition"); - if (anchorTransition) { - optional<TransitionOptions> transition = - convert<TransitionOptions>(*anchorTransition, error); - if (transition) { - light.setAnchorTransition(*transition); - } else { - return {}; - } - } - - const auto color = objectMember(value, "color"); - if (color) { - optional<PropertyValue<Color>> convertedColor = - convert<PropertyValue<Color>>(*color, error); - - if (convertedColor) { - light.setColor(*convertedColor); - } else { - return {}; - } - } - - const auto colorTransition = objectMember(value, "color-transition"); - if (colorTransition) { - optional<TransitionOptions> transition = - convert<TransitionOptions>(*colorTransition, error); - if (transition) { - light.setColorTransition(*transition); - } else { - return {}; - } - } - - const auto position = objectMember(value, "position"); - if (position) { - optional<PropertyValue<Position>> convertedPosition = - convert<PropertyValue<Position>>(*position, error); - - if (convertedPosition) { - light.setPosition(*convertedPosition); - } else { - return {}; - } - } - - const auto positionTransition = objectMember(value, "position-transition"); - if (positionTransition) { - optional<TransitionOptions> transition = - convert<TransitionOptions>(*positionTransition, error); - if (transition) { - light.setPositionTransition(*transition); - } else { - return {}; - } - } - - const auto intensity = objectMember(value, "intensity"); - if (intensity) { - optional<PropertyValue<float>> convertedIntensity = - convert<PropertyValue<float>>(*intensity, error); - - if (convertedIntensity) { - light.setIntensity(*convertedIntensity); - } else { - return {}; - } - } - - const auto intensityTransition = objectMember(value, "intensity-transition"); - if (intensityTransition) { - optional<TransitionOptions> transition = - convert<TransitionOptions>(*intensityTransition, error); - if (transition) { - light.setIntensityTransition(*transition); - } else { - return {}; - } - } - return { std::move(light) }; - }; + optional<Light> operator()(const Value& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/position.hpp b/include/mbgl/style/conversion/position.hpp index ed1f10319c..167cd31378 100644 --- a/include/mbgl/style/conversion/position.hpp +++ b/include/mbgl/style/conversion/position.hpp @@ -2,9 +2,6 @@ #include <mbgl/style/conversion.hpp> #include <mbgl/style/position.hpp> -#include <mbgl/util/optional.hpp> - -#include <array> namespace mbgl { namespace style { @@ -12,15 +9,7 @@ namespace conversion { template <> struct Converter<Position> { - optional<Position> operator()(const Value& value, Error& error) const { - optional<std::array<float, 3>> spherical = convert<std::array<float, 3>>(value, error); - - if (!spherical) { - return {}; - } - - return Position(*spherical); - } + optional<Position> operator()(const Value& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/source.hpp b/include/mbgl/style/conversion/source.hpp index 483f0d8807..0b9a273eb5 100644 --- a/include/mbgl/style/conversion/source.hpp +++ b/include/mbgl/style/conversion/source.hpp @@ -1,16 +1,9 @@ #pragma once #include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/coordinate.hpp> -#include <mbgl/style/conversion/geojson.hpp> -#include <mbgl/style/conversion/geojson_options.hpp> -#include <mbgl/style/conversion/tileset.hpp> #include <mbgl/style/source.hpp> -#include <mbgl/style/sources/geojson_source.hpp> -#include <mbgl/style/sources/raster_source.hpp> -#include <mbgl/style/sources/vector_source.hpp> -#include <mbgl/style/sources/image_source.hpp> -#include <mbgl/util/geo.hpp> + +#include <memory> namespace mbgl { namespace style { @@ -19,163 +12,7 @@ namespace conversion { template <> struct Converter<std::unique_ptr<Source>> { public: - optional<std::unique_ptr<Source>> operator()(const Value& value, Error& error, const std::string& id) const { - if (!isObject(value)) { - error = { "source must be an object" }; - return {}; - } - - auto typeValue = objectMember(value, "type"); - if (!typeValue) { - error = { "source must have a type" }; - return {}; - } - - optional<std::string> type = toString(*typeValue); - if (!type) { - error = { "source type must be a string" }; - return {}; - } - - if (*type == "raster") { - return convertRasterSource(id, value, error); - } else if (*type == "vector") { - return convertVectorSource(id, value, error); - } else if (*type == "geojson") { - return convertGeoJSONSource(id, value, error); - } else if (*type == "image") { - return convertImageSource(id, value, error); - } else { - error = { "invalid source type" }; - return {}; - } - } - -private: - // A tile source can either specify a URL to TileJSON, or inline TileJSON. - optional<variant<std::string, Tileset>> convertURLOrTileset(const Value& value, Error& error) const { - auto urlVal = objectMember(value, "url"); - if (!urlVal) { - optional<Tileset> tileset = convert<Tileset>(value, error); - if (!tileset) { - return {}; - } - return { *tileset }; - } - - optional<std::string> url = toString(*urlVal); - if (!url) { - error = { "source url must be a string" }; - return {}; - } - - return { *url }; - } - - optional<std::unique_ptr<Source>> convertRasterSource(const std::string& id, - const Value& value, - Error& error) const { - optional<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value, error); - if (!urlOrTileset) { - return {}; - } - - uint16_t tileSize = util::tileSize; - auto tileSizeValue = objectMember(value, "tileSize"); - if (tileSizeValue) { - optional<float> size = toNumber(*tileSizeValue); - if (!size || *size < 0 || *size > std::numeric_limits<uint16_t>::max()) { - error = { "invalid tileSize" }; - return {}; - } - tileSize = *size; - } - - return { std::make_unique<RasterSource>(id, std::move(*urlOrTileset), tileSize) }; - } - - optional<std::unique_ptr<Source>> convertVectorSource(const std::string& id, - const Value& value, - Error& error) const { - optional<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value, error); - if (!urlOrTileset) { - return {}; - } - - return { std::make_unique<VectorSource>(id, std::move(*urlOrTileset)) }; - } - - optional<std::unique_ptr<Source>> convertGeoJSONSource(const std::string& id, - const Value& value, - Error& error) const { - auto dataValue = objectMember(value, "data"); - if (!dataValue) { - error = { "GeoJSON source must have a data value" }; - return {}; - } - - optional<GeoJSONOptions> options = convert<GeoJSONOptions>(value, error); - if (!options) { - return {}; - } - - auto result = std::make_unique<GeoJSONSource>(id, *options); - - if (isObject(*dataValue)) { - optional<GeoJSON> geoJSON = convert<GeoJSON>(*dataValue, error); - if (!geoJSON) { - return {}; - } - result->setGeoJSON(std::move(*geoJSON)); - } else if (toString(*dataValue)) { - result->setURL(*toString(*dataValue)); - } else { - error = { "GeoJSON data must be a URL or an object" }; - return {}; - } - - return { std::move(result) }; - } - - optional<std::unique_ptr<Source>> convertImageSource(const std::string& id, - const Value& value, - Error& error) const { - auto urlValue = objectMember(value, "url"); - if (!urlValue) { - error = { "Image source must have a url value" }; - return {}; - } - - auto urlString = toString(*urlValue); - if (!urlString) { - error = { "Image url must be a URL string" }; - return {}; - } - - auto coordinatesValue = objectMember(value, "coordinates"); - if (!coordinatesValue) { - error = { "Image source must have a coordinates values" }; - return {}; - } - - if (!isArray(*coordinatesValue) || arrayLength(*coordinatesValue) != 4) { - error = { "Image coordinates must be an array of four longitude latitude pairs" }; - return {}; - } - - std::array<LatLng, 4> coordinates; - for (std::size_t i=0; i < 4; i++) { - auto latLng = conversion::convert<LatLng>(arrayMember(*coordinatesValue,i), error); - if (!latLng) { - return {}; - } - coordinates[i] = *latLng; - } - auto result = std::make_unique<ImageSource>(id, coordinates); - result->setURL(*urlString); - - return { std::move(result) }; - } + optional<std::unique_ptr<Source>> operator()(const Value& value, Error& error, const std::string& id) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/tileset.hpp b/include/mbgl/style/conversion/tileset.hpp index 0a1ba8845b..25f4f27d81 100644 --- a/include/mbgl/style/conversion/tileset.hpp +++ b/include/mbgl/style/conversion/tileset.hpp @@ -10,69 +10,7 @@ namespace conversion { template <> struct Converter<Tileset> { public: - optional<Tileset> operator()(const Value& value, Error& error) const { - Tileset result; - - auto tiles = objectMember(value, "tiles"); - if (!tiles) { - error = { "source must have tiles" }; - return {}; - } - - if (!isArray(*tiles)) { - error = { "source tiles must be an array" }; - return {}; - } - - for (std::size_t i = 0; i < arrayLength(*tiles); i++) { - optional<std::string> urlTemplate = toString(arrayMember(*tiles, i)); - if (!urlTemplate) { - error = { "source tiles member must be a string" }; - return {}; - } - result.tiles.push_back(std::move(*urlTemplate)); - } - - auto schemeValue = objectMember(value, "scheme"); - if (schemeValue) { - optional<std::string> scheme = toString(*schemeValue); - if (scheme && *scheme == "tms") { - result.scheme = Tileset::Scheme::TMS; - } - } - - auto minzoomValue = objectMember(value, "minzoom"); - if (minzoomValue) { - optional<float> minzoom = toNumber(*minzoomValue); - if (!minzoom || *minzoom < 0 || *minzoom > std::numeric_limits<uint8_t>::max()) { - error = { "invalid minzoom" }; - return {}; - } - result.zoomRange.min = *minzoom; - } - - auto maxzoomValue = objectMember(value, "maxzoom"); - if (maxzoomValue) { - optional<float> maxzoom = toNumber(*maxzoomValue); - if (!maxzoom || *maxzoom < 0 || *maxzoom > std::numeric_limits<uint8_t>::max()) { - error = { "invalid maxzoom" }; - return {}; - } - result.zoomRange.max = *maxzoom; - } - - auto attributionValue = objectMember(value, "attribution"); - if (attributionValue) { - optional<std::string> attribution = toString(*attributionValue); - if (!attribution) { - error = { "source attribution must be a string" }; - return {}; - } - result.attribution = std::move(*attribution); - } - - return result; - } + optional<Tileset> operator()(const Value& value, Error& error) const; }; } // namespace conversion diff --git a/include/mbgl/style/conversion/transition_options.hpp b/include/mbgl/style/conversion/transition_options.hpp index ad6421f6c4..173d4a8448 100644 --- a/include/mbgl/style/conversion/transition_options.hpp +++ b/include/mbgl/style/conversion/transition_options.hpp @@ -10,36 +10,7 @@ namespace conversion { template <> struct Converter<TransitionOptions> { public: - optional<TransitionOptions> operator()(const Value& value, Error& error) const { - if (!isObject(value)) { - error = { "transition must be an object" }; - return {}; - } - - TransitionOptions result; - - auto duration = objectMember(value, "duration"); - if (duration) { - auto number = toNumber(*duration); - if (!number) { - error = { "duration must be a number" }; - return {}; - } - result.duration = { std::chrono::milliseconds(int64_t(*number)) }; - } - - auto delay = objectMember(value, "delay"); - if (delay) { - auto number = toNumber(*delay); - if (!number) { - error = { "delay must be a number" }; - return {}; - } - result.delay = { std::chrono::milliseconds(int64_t(*number)) }; - } - - return result; - } + optional<TransitionOptions> operator()(const Value& value, Error& error) const; }; } // namespace conversion diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp new file mode 100644 index 0000000000..43feb3380b --- /dev/null +++ b/src/mbgl/style/conversion/constant.cpp @@ -0,0 +1,94 @@ +#include <mbgl/style/conversion/constant.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<bool> Converter<bool>::operator()(const Value& value, Error& error) const { + optional<bool> converted = toBool(value); + if (!converted) { + error = { "value must be a boolean" }; + return {}; + } + return *converted; +} + +optional<float> Converter<float>::operator()(const Value& value, Error& error) const { + optional<float> converted = toNumber(value); + if (!converted) { + error = { "value must be a number" }; + return {}; + } + return *converted; +} + +optional<std::string> Converter<std::string>::operator()(const Value& value, Error& error) const { + optional<std::string> converted = toString(value); + if (!converted) { + error = { "value must be a string" }; + return {}; + } + return *converted; +} + +optional<Color> Converter<Color>::operator()(const Value& value, Error& error) const { + optional<std::string> string = toString(value); + if (!string) { + error = { "value must be a string" }; + return {}; + } + + optional<Color> color = Color::parse(*string); + if (!color) { + error = { "value must be a valid color" }; + return {}; + } + + return *color; +} + +optional<std::vector<float>> Converter<std::vector<float>>::operator()(const Value& value, Error& error) const { + if (!isArray(value)) { + error = { "value must be an array" }; + return {}; + } + + std::vector<float> result; + result.reserve(arrayLength(value)); + + for (std::size_t i = 0; i < arrayLength(value); ++i) { + optional<float> number = toNumber(arrayMember(value, i)); + if (!number) { + error = { "value must be an array of numbers" }; + return {}; + } + result.push_back(*number); + } + + return result; +} + +optional<std::vector<std::string>> Converter<std::vector<std::string>>::operator()(const Value& value, Error& error) const { + if (!isArray(value)) { + error = { "value must be an array" }; + return {}; + } + + std::vector<std::string> result; + result.reserve(arrayLength(value)); + + for (std::size_t i = 0; i < arrayLength(value); ++i) { + optional<std::string> string = toString(arrayMember(value, i)); + if (!string) { + error = { "value must be an array of strings" }; + return {}; + } + result.push_back(*string); + } + + return result; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/coordinate.cpp b/src/mbgl/style/conversion/coordinate.cpp new file mode 100644 index 0000000000..4f92a9a963 --- /dev/null +++ b/src/mbgl/style/conversion/coordinate.cpp @@ -0,0 +1,29 @@ +#include <mbgl/style/conversion/coordinate.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<LatLng> Converter<LatLng>::operator() (const Value& value, Error& error) const { + if (!isArray(value) || arrayLength(value) < 2 ) { + error = { "coordinate array must contain numeric longitude and latitude values" }; + return {}; + } + //Style spec uses GeoJSON convention for specifying coordinates + optional<double> latitude = toDouble(arrayMember(value, 1)); + optional<double> longitude = toDouble(arrayMember(value, 0)); + + if (!latitude || !longitude) { + error = { "coordinate array must contain numeric longitude and latitude values" }; + return {}; + } + if (*latitude < -90 || *latitude > 90 ){ + error = { "coordinate latitude must be between -90 and 90" }; + return {}; + } + return LatLng(*latitude, *longitude); +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/filter.cpp b/src/mbgl/style/conversion/filter.cpp new file mode 100644 index 0000000000..f3633d5ff7 --- /dev/null +++ b/src/mbgl/style/conversion/filter.cpp @@ -0,0 +1,248 @@ +#include <mbgl/style/conversion/filter.hpp> +#include <mbgl/util/geometry.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +static optional<mbgl::Value> normalizeValue(const optional<mbgl::Value>& value, Error& error) { + if (!value) { + error = { "filter expression value must be a boolean, number, or string" }; + return {}; + } else { + return *value; + } +} + +static optional<FeatureType> toFeatureType(const Value& value, Error& error) { + optional<std::string> type = toString(value); + if (!type) { + error = { "value for $type filter must be a string" }; + return {}; + } else if (*type == "Point") { + return FeatureType::Point; + } else if (*type == "LineString") { + return FeatureType::LineString; + } else if (*type == "Polygon") { + return FeatureType::Polygon; + } else { + error = { "value for $type filter must be Point, LineString, or Polygon" }; + return {}; + } +} + +static optional<FeatureIdentifier> toFeatureIdentifier(const Value& value, Error& error) { + optional<mbgl::Value> identifier = toValue(value); + if (!identifier) { + error = { "filter expression value must be a boolean, number, or string" }; + return {}; + } else { + return (*identifier).match( + [] (uint64_t t) -> optional<FeatureIdentifier> { return { t }; }, + [] ( int64_t t) -> optional<FeatureIdentifier> { return { t }; }, + [] ( double t) -> optional<FeatureIdentifier> { return { t }; }, + [] (const std::string& t) -> optional<FeatureIdentifier> { return { t }; }, + [&] (const auto&) -> optional<FeatureIdentifier> { + error = { "filter expression value must be a boolean, number, or string" }; + return {}; + }); + } +} + +template <class FilterType, class IdentifierFilterType> +optional<Filter> convertUnaryFilter(const Value& value, Error& error) { + if (arrayLength(value) < 2) { + error = { "filter expression must have 2 elements" }; + return {}; + } + + optional<std::string> key = toString(arrayMember(value, 1)); + if (!key) { + error = { "filter expression key must be a string" }; + return {}; + } + + if (*key == "$id") { + return { IdentifierFilterType {} }; + } else { + return { FilterType { *key } }; + } +} + +template <class FilterType, class TypeFilterType, class IdentifierFilterType> +optional<Filter> convertEqualityFilter(const Value& value, Error& error) { + if (arrayLength(value) < 3) { + error = { "filter expression must have 3 elements" }; + return {}; + } + + optional<std::string> key = toString(arrayMember(value, 1)); + if (!key) { + error = { "filter expression key must be a string" }; + return {}; + } + + if (*key == "$type") { + optional<FeatureType> filterValue = toFeatureType(arrayMember(value, 2), error); + if (!filterValue) { + return {}; + } + + return { TypeFilterType { *filterValue } }; + + } else if (*key == "$id") { + optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, 2), error); + if (!filterValue) { + return {}; + } + + return { IdentifierFilterType { *filterValue } }; + + } else { + optional<mbgl::Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); + if (!filterValue) { + return {}; + } + + return { FilterType { *key, *filterValue } }; + } +} + +template <class FilterType> +optional<Filter> convertBinaryFilter(const Value& value, Error& error) { + if (arrayLength(value) < 3) { + error = { "filter expression must have 3 elements" }; + return {}; + } + + optional<std::string> key = toString(arrayMember(value, 1)); + if (!key) { + error = { "filter expression key must be a string" }; + return {}; + } + + optional<mbgl::Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)), error); + if (!filterValue) { + return {}; + } + + return { FilterType { *key, *filterValue } }; +} + +template <class FilterType, class TypeFilterType, class IdentifierFilterType> +optional<Filter> convertSetFilter(const Value& value, Error& error) { + if (arrayLength(value) < 2) { + error = { "filter expression must at least 2 elements" }; + return {}; + } + + optional<std::string> key = toString(arrayMember(value, 1)); + if (!key) { + error = { "filter expression key must be a string" }; + return {}; + } + + if (*key == "$type") { + std::vector<FeatureType> values; + for (std::size_t i = 2; i < arrayLength(value); ++i) { + optional<FeatureType> filterValue = toFeatureType(arrayMember(value, i), error); + if (!filterValue) { + return {}; + } + values.push_back(*filterValue); + } + + return { TypeFilterType { std::move(values) } }; + + } else if (*key == "$id") { + std::vector<FeatureIdentifier> values; + for (std::size_t i = 2; i < arrayLength(value); ++i) { + optional<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, i), error); + if (!filterValue) { + return {}; + } + values.push_back(*filterValue); + } + + return { IdentifierFilterType { std::move(values) } }; + + } else { + std::vector<mbgl::Value> values; + for (std::size_t i = 2; i < arrayLength(value); ++i) { + optional<mbgl::Value> filterValue = normalizeValue(toValue(arrayMember(value, i)), error); + if (!filterValue) { + return {}; + } + values.push_back(*filterValue); + } + + return { FilterType { *key, std::move(values) } }; + } +} + +template <class FilterType> +optional<Filter> convertCompoundFilter(const Value& value, Error& error) { + std::vector<Filter> filters; + for (std::size_t i = 1; i < arrayLength(value); ++i) { + optional<Filter> element = convert<Filter>(arrayMember(value, i), error); + if (!element) { + return {}; + } + filters.push_back(*element); + } + + return { FilterType { std::move(filters) } }; +} + +optional<Filter> Converter<Filter>::operator()(const Value& value, Error& error) const { + if (!isArray(value)) { + error = { "filter expression must be an array" }; + return {}; + } + + if (arrayLength(value) < 1) { + error = { "filter expression must have at least 1 element" }; + return {}; + } + + optional<std::string> op = toString(arrayMember(value, 0)); + if (!op) { + error = { "filter operator must be a string" }; + return {}; + } + + if (*op == "==") { + return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value, error); + } else if (*op == "!=") { + return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value, error); + } else if (*op == ">") { + return convertBinaryFilter<GreaterThanFilter>(value, error); + } else if (*op == ">=") { + return convertBinaryFilter<GreaterThanEqualsFilter>(value, error); + } else if (*op == "<") { + return convertBinaryFilter<LessThanFilter>(value, error); + } else if (*op == "<=") { + return convertBinaryFilter<LessThanEqualsFilter>(value, error); + } else if (*op == "in") { + return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value, error); + } else if (*op == "!in") { + return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value, error); + } else if (*op == "all") { + return convertCompoundFilter<AllFilter>(value, error); + } else if (*op == "any") { + return convertCompoundFilter<AnyFilter>(value, error); + } else if (*op == "none") { + return convertCompoundFilter<NoneFilter>(value, error); + } else if (*op == "has") { + return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value, error); + } else if (*op == "!has") { + return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value, error); + } + + error = { R"(filter operator must be one of "==", "!=", ">", ">=", "<", "<=", "in", "!in", "all", "any", "none", "has", or "!has")" }; + return {}; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/geojson_options.cpp b/src/mbgl/style/conversion/geojson_options.cpp new file mode 100644 index 0000000000..e9750cfa8f --- /dev/null +++ b/src/mbgl/style/conversion/geojson_options.cpp @@ -0,0 +1,75 @@ +#include <mbgl/style/conversion/geojson_options.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<GeoJSONOptions> Converter<GeoJSONOptions>::operator()(const Value& value, Error& error) const { + GeoJSONOptions options; + + const auto maxzoomValue = objectMember(value, "maxzoom"); + if (maxzoomValue) { + if (toNumber(*maxzoomValue)) { + options.maxzoom = static_cast<uint8_t>(*toNumber(*maxzoomValue)); + } else { + error = { "GeoJSON source maxzoom value must be a number" }; + return {}; + } + } + + const auto bufferValue = objectMember(value, "buffer"); + if (bufferValue) { + if (toNumber(*bufferValue)) { + options.buffer = static_cast<uint16_t>(*toNumber(*bufferValue)); + } else { + error = { "GeoJSON source buffer value must be a number" }; + return {}; + } + } + + const auto toleranceValue = objectMember(value, "tolerance"); + if (toleranceValue) { + if (toNumber(*toleranceValue)) { + options.tolerance = static_cast<double>(*toNumber(*toleranceValue)); + } else { + error = { "GeoJSON source tolerance value must be a number" }; + return {}; + } + } + + const auto clusterValue = objectMember(value, "cluster"); + if (clusterValue) { + if (toBool(*clusterValue)) { + options.cluster = *toBool(*clusterValue); + } else { + error = { "GeoJSON source cluster value must be a boolean" }; + return {}; + } + } + + const auto clusterMaxZoomValue = objectMember(value, "clusterMaxZoom"); + if (clusterMaxZoomValue) { + if (toNumber(*clusterMaxZoomValue)) { + options.clusterMaxZoom = static_cast<uint8_t>(*toNumber(*clusterMaxZoomValue)); + } else { + error = { "GeoJSON source clusterMaxZoom value must be a number" }; + return {}; + } + } + + const auto clusterRadiusValue = objectMember(value, "clusterRadius"); + if (clusterRadiusValue) { + if (toNumber(*clusterRadiusValue)) { + options.clusterRadius = static_cast<double>(*toNumber(*clusterRadiusValue)); + } else { + error = { "GeoJSON source clusterRadius value must be a number" }; + return {}; + } + } + + return { options }; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/layer.cpp b/src/mbgl/style/conversion/layer.cpp new file mode 100644 index 0000000000..8535ccb36c --- /dev/null +++ b/src/mbgl/style/conversion/layer.cpp @@ -0,0 +1,206 @@ +#include <mbgl/style/conversion/layer.hpp> +#include <mbgl/style/conversion/constant.hpp> +#include <mbgl/style/conversion/filter.hpp> +#include <mbgl/style/conversion/make_property_setters.hpp> +#include <mbgl/style/layers/background_layer.hpp> +#include <mbgl/style/layers/circle_layer.hpp> +#include <mbgl/style/layers/fill_layer.hpp> +#include <mbgl/style/layers/fill_extrusion_layer.hpp> +#include <mbgl/style/layers/line_layer.hpp> +#include <mbgl/style/layers/raster_layer.hpp> +#include <mbgl/style/layers/symbol_layer.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +static optional<Error> setLayoutProperty(Layer& layer, const std::string& name, const Value& value) { + static const auto setters = makeLayoutPropertySetters(); + auto it = setters.find(name); + if (it == setters.end()) { + return Error { "property not found" }; + } + return it->second(layer, value); +} + +static optional<Error> setPaintProperty(Layer& layer, const std::string& name, const Value& value) { + static const auto setters = makePaintPropertySetters(); + auto it = setters.find(name); + if (it == setters.end()) { + return Error { "property not found" }; + } + return it->second(layer, value); +} + +optional<Error> setPaintProperties(Layer& layer, const Value& value) { + auto paintValue = objectMember(value, "paint"); + if (!paintValue) { + return {}; + } + return eachMember(*paintValue, [&] (const std::string& k, const Value& v) { + return setPaintProperty(layer, k, v); + }); +} + +template <class LayerType> +optional<std::unique_ptr<Layer>> convertVectorLayer(const std::string& id, const Value& value, Error& error) { + auto sourceValue = objectMember(value, "source"); + if (!sourceValue) { + error = { "layer must have a source" }; + return {}; + } + + optional<std::string> source = toString(*sourceValue); + if (!source) { + error = { "layer source must be a string" }; + return {}; + } + + std::unique_ptr<LayerType> layer = std::make_unique<LayerType>(id, *source); + + auto sourceLayerValue = objectMember(value, "source-layer"); + if (sourceLayerValue) { + optional<std::string> sourceLayer = toString(*sourceLayerValue); + if (!sourceLayer) { + error = { "layer source-layer must be a string" }; + return {}; + } + layer->setSourceLayer(*sourceLayer); + } + + auto filterValue = objectMember(value, "filter"); + if (filterValue) { + optional<Filter> filter = convert<Filter>(*filterValue, error); + if (!filter) { + return {}; + } + layer->setFilter(*filter); + } + + return { std::move(layer) }; +} + +static optional<std::unique_ptr<Layer>> convertRasterLayer(const std::string& id, const Value& value, Error& error) { + auto sourceValue = objectMember(value, "source"); + if (!sourceValue) { + error = { "layer must have a source" }; + return {}; + } + + optional<std::string> source = toString(*sourceValue); + if (!source) { + error = { "layer source must be a string" }; + return {}; + } + + return { std::make_unique<RasterLayer>(id, *source) }; +} + +static optional<std::unique_ptr<Layer>> convertBackgroundLayer(const std::string& id, const Value&, Error&) { + return { std::make_unique<BackgroundLayer>(id) }; +} + +optional<std::unique_ptr<Layer>> Converter<std::unique_ptr<Layer>>::operator()(const Value& value, Error& error) const { + if (!isObject(value)) { + error = { "layer must be an object" }; + return {}; + } + + auto idValue = objectMember(value, "id"); + if (!idValue) { + error = { "layer must have an id" }; + return {}; + } + + optional<std::string> id = toString(*idValue); + if (!id) { + error = { "layer id must be a string" }; + return {}; + } + + auto typeValue = objectMember(value, "type"); + if (!typeValue) { + error = { "layer must have a type" }; + return {}; + } + + optional<std::string> type = toString(*typeValue); + if (!type) { + error = { "layer type must be a string" }; + return {}; + } + + optional<std::unique_ptr<Layer>> converted; + + if (*type == "fill") { + converted = convertVectorLayer<FillLayer>(*id, value, error); + } else if (*type == "fill-extrusion") { + converted = convertVectorLayer<FillExtrusionLayer>(*id, value, error); + } else if (*type == "line") { + converted = convertVectorLayer<LineLayer>(*id, value, error); + } else if (*type == "circle") { + converted = convertVectorLayer<CircleLayer>(*id, value, error); + } else if (*type == "symbol") { + converted = convertVectorLayer<SymbolLayer>(*id, value, error); + } else if (*type == "raster") { + converted = convertRasterLayer(*id, value, error); + } else if (*type == "background") { + converted = convertBackgroundLayer(*id, value, error); + } else { + error = { "invalid layer type" }; + return {}; + } + + if (!converted) { + return converted; + } + + std::unique_ptr<Layer> layer = std::move(*converted); + + auto minzoomValue = objectMember(value, "minzoom"); + if (minzoomValue) { + optional<float> minzoom = toNumber(*minzoomValue); + if (!minzoom) { + error = { "minzoom must be numeric" }; + return {}; + } + layer->setMinZoom(*minzoom); + } + + auto maxzoomValue = objectMember(value, "maxzoom"); + if (maxzoomValue) { + optional<float> maxzoom = toNumber(*maxzoomValue); + if (!maxzoom) { + error = { "maxzoom must be numeric" }; + return {}; + } + layer->setMaxZoom(*maxzoom); + } + + auto layoutValue = objectMember(value, "layout"); + if (layoutValue) { + if (!isObject(*layoutValue)) { + error = { "layout must be an object" }; + return {}; + } + optional<Error> error_ = eachMember(*layoutValue, [&] (const std::string& k, const Value& v) { + return setLayoutProperty(*layer, k, v); + }); + if (error_) { + error = *error_; + return {}; + } + } + + optional<Error> error_ = setPaintProperties(*layer, value); + if (error_) { + error = *error_; + return {}; + } + + return std::move(layer); +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/light.cpp b/src/mbgl/style/conversion/light.cpp new file mode 100644 index 0000000000..f468bddcc1 --- /dev/null +++ b/src/mbgl/style/conversion/light.cpp @@ -0,0 +1,115 @@ +#include <mbgl/style/conversion/light.hpp> +#include <mbgl/style/conversion/position.hpp> +#include <mbgl/style/conversion/property_value.hpp> +#include <mbgl/style/conversion/transition_options.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<Light> Converter<Light>::operator()(const Value& value, Error& error) const { + if (!isObject(value)) { + error = { "light must be an object" }; + return {}; + } + + Light light; + + const auto anchor = objectMember(value, "anchor"); + if (anchor) { + optional<PropertyValue<LightAnchorType>> convertedAnchor = + convert<PropertyValue<LightAnchorType>>(*anchor, error); + + if (convertedAnchor) { + light.setAnchor(*convertedAnchor); + } else { + return {}; + } + } + + const auto anchorTransition = objectMember(value, "anchor-transition"); + if (anchorTransition) { + optional<TransitionOptions> transition = + convert<TransitionOptions>(*anchorTransition, error); + if (transition) { + light.setAnchorTransition(*transition); + } else { + return {}; + } + } + + const auto color = objectMember(value, "color"); + if (color) { + optional<PropertyValue<Color>> convertedColor = + convert<PropertyValue<Color>>(*color, error); + + if (convertedColor) { + light.setColor(*convertedColor); + } else { + return {}; + } + } + + const auto colorTransition = objectMember(value, "color-transition"); + if (colorTransition) { + optional<TransitionOptions> transition = + convert<TransitionOptions>(*colorTransition, error); + if (transition) { + light.setColorTransition(*transition); + } else { + return {}; + } + } + + const auto position = objectMember(value, "position"); + if (position) { + optional<PropertyValue<Position>> convertedPosition = + convert<PropertyValue<Position>>(*position, error); + + if (convertedPosition) { + light.setPosition(*convertedPosition); + } else { + return {}; + } + } + + const auto positionTransition = objectMember(value, "position-transition"); + if (positionTransition) { + optional<TransitionOptions> transition = + convert<TransitionOptions>(*positionTransition, error); + if (transition) { + light.setPositionTransition(*transition); + } else { + return {}; + } + } + + const auto intensity = objectMember(value, "intensity"); + if (intensity) { + optional<PropertyValue<float>> convertedIntensity = + convert<PropertyValue<float>>(*intensity, error); + + if (convertedIntensity) { + light.setIntensity(*convertedIntensity); + } else { + return {}; + } + } + + const auto intensityTransition = objectMember(value, "intensity-transition"); + if (intensityTransition) { + optional<TransitionOptions> transition = + convert<TransitionOptions>(*intensityTransition, error); + if (transition) { + light.setIntensityTransition(*transition); + } else { + return {}; + } + } + + return { std::move(light) }; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/conversion/make_property_setters.hpp b/src/mbgl/style/conversion/make_property_setters.hpp index 074d7eb730..074d7eb730 100644 --- a/include/mbgl/style/conversion/make_property_setters.hpp +++ b/src/mbgl/style/conversion/make_property_setters.hpp diff --git a/include/mbgl/style/conversion/make_property_setters.hpp.ejs b/src/mbgl/style/conversion/make_property_setters.hpp.ejs index 19c9f70538..19c9f70538 100644 --- a/include/mbgl/style/conversion/make_property_setters.hpp.ejs +++ b/src/mbgl/style/conversion/make_property_setters.hpp.ejs diff --git a/src/mbgl/style/conversion/position.cpp b/src/mbgl/style/conversion/position.cpp new file mode 100644 index 0000000000..fa6619fee3 --- /dev/null +++ b/src/mbgl/style/conversion/position.cpp @@ -0,0 +1,22 @@ +#include <mbgl/style/conversion/position.hpp> +#include <mbgl/style/conversion/constant.hpp> + +#include <array> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<Position> Converter<Position>::operator()(const Value& value, Error& error) const { + optional<std::array<float, 3>> spherical = convert<std::array<float, 3>>(value, error); + + if (!spherical) { + return {}; + } + + return Position(*spherical); +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/conversion/property_setter.hpp b/src/mbgl/style/conversion/property_setter.hpp index ef8377fc12..ef8377fc12 100644 --- a/include/mbgl/style/conversion/property_setter.hpp +++ b/src/mbgl/style/conversion/property_setter.hpp diff --git a/src/mbgl/style/conversion/source.cpp b/src/mbgl/style/conversion/source.cpp new file mode 100644 index 0000000000..f88d33fa4b --- /dev/null +++ b/src/mbgl/style/conversion/source.cpp @@ -0,0 +1,175 @@ +#include <mbgl/style/conversion/source.hpp> +#include <mbgl/style/conversion/coordinate.hpp> +#include <mbgl/style/conversion/geojson.hpp> +#include <mbgl/style/conversion/geojson_options.hpp> +#include <mbgl/style/conversion/tileset.hpp> +#include <mbgl/style/sources/geojson_source.hpp> +#include <mbgl/style/sources/raster_source.hpp> +#include <mbgl/style/sources/vector_source.hpp> +#include <mbgl/style/sources/image_source.hpp> +#include <mbgl/util/geo.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +// A tile source can either specify a URL to TileJSON, or inline TileJSON. +static optional<variant<std::string, Tileset>> convertURLOrTileset(const Value& value, Error& error) { + auto urlVal = objectMember(value, "url"); + if (!urlVal) { + optional<Tileset> tileset = convert<Tileset>(value, error); + if (!tileset) { + return {}; + } + return { *tileset }; + } + + optional<std::string> url = toString(*urlVal); + if (!url) { + error = { "source url must be a string" }; + return {}; + } + + return { *url }; +} + +static optional<std::unique_ptr<Source>> convertRasterSource(const std::string& id, + const Value& value, + Error& error) { + optional<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value, error); + if (!urlOrTileset) { + return {}; + } + + uint16_t tileSize = util::tileSize; + auto tileSizeValue = objectMember(value, "tileSize"); + if (tileSizeValue) { + optional<float> size = toNumber(*tileSizeValue); + if (!size || *size < 0 || *size > std::numeric_limits<uint16_t>::max()) { + error = { "invalid tileSize" }; + return {}; + } + tileSize = *size; + } + + return { std::make_unique<RasterSource>(id, std::move(*urlOrTileset), tileSize) }; +} + +static optional<std::unique_ptr<Source>> convertVectorSource(const std::string& id, + const Value& value, + Error& error) { + optional<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value, error); + if (!urlOrTileset) { + return {}; + } + + return { std::make_unique<VectorSource>(id, std::move(*urlOrTileset)) }; +} + +static optional<std::unique_ptr<Source>> convertGeoJSONSource(const std::string& id, + const Value& value, + Error& error) { + auto dataValue = objectMember(value, "data"); + if (!dataValue) { + error = { "GeoJSON source must have a data value" }; + return {}; + } + + optional<GeoJSONOptions> options = convert<GeoJSONOptions>(value, error); + if (!options) { + return {}; + } + + auto result = std::make_unique<GeoJSONSource>(id, *options); + + if (isObject(*dataValue)) { + optional<GeoJSON> geoJSON = convert<GeoJSON>(*dataValue, error); + if (!geoJSON) { + return {}; + } + result->setGeoJSON(std::move(*geoJSON)); + } else if (toString(*dataValue)) { + result->setURL(*toString(*dataValue)); + } else { + error = { "GeoJSON data must be a URL or an object" }; + return {}; + } + + return { std::move(result) }; +} + +static optional<std::unique_ptr<Source>> convertImageSource(const std::string& id, + const Value& value, + Error& error) { + auto urlValue = objectMember(value, "url"); + if (!urlValue) { + error = { "Image source must have a url value" }; + return {}; + } + + auto urlString = toString(*urlValue); + if (!urlString) { + error = { "Image url must be a URL string" }; + return {}; + } + + auto coordinatesValue = objectMember(value, "coordinates"); + if (!coordinatesValue) { + error = { "Image source must have a coordinates values" }; + return {}; + } + + if (!isArray(*coordinatesValue) || arrayLength(*coordinatesValue) != 4) { + error = { "Image coordinates must be an array of four longitude latitude pairs" }; + return {}; + } + + std::array<LatLng, 4> coordinates; + for (std::size_t i=0; i < 4; i++) { + auto latLng = conversion::convert<LatLng>(arrayMember(*coordinatesValue,i), error); + if (!latLng) { + return {}; + } + coordinates[i] = *latLng; + } + auto result = std::make_unique<ImageSource>(id, coordinates); + result->setURL(*urlString); + + return { std::move(result) }; +} + +optional<std::unique_ptr<Source>> Converter<std::unique_ptr<Source>>::operator()(const Value& value, Error& error, const std::string& id) const { + if (!isObject(value)) { + error = { "source must be an object" }; + return {}; + } + + auto typeValue = objectMember(value, "type"); + if (!typeValue) { + error = { "source must have a type" }; + return {}; + } + + optional<std::string> type = toString(*typeValue); + if (!type) { + error = { "source type must be a string" }; + return {}; + } + + if (*type == "raster") { + return convertRasterSource(id, value, error); + } else if (*type == "vector") { + return convertVectorSource(id, value, error); + } else if (*type == "geojson") { + return convertGeoJSONSource(id, value, error); + } else if (*type == "image") { + return convertImageSource(id, value, error); + } else { + error = { "invalid source type" }; + return {}; + } +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/tileset.cpp b/src/mbgl/style/conversion/tileset.cpp new file mode 100644 index 0000000000..54a486cb96 --- /dev/null +++ b/src/mbgl/style/conversion/tileset.cpp @@ -0,0 +1,73 @@ +#include <mbgl/style/conversion/tileset.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<Tileset> Converter<Tileset>::operator()(const Value& value, Error& error) const { + Tileset result; + + auto tiles = objectMember(value, "tiles"); + if (!tiles) { + error = { "source must have tiles" }; + return {}; + } + + if (!isArray(*tiles)) { + error = { "source tiles must be an array" }; + return {}; + } + + for (std::size_t i = 0; i < arrayLength(*tiles); i++) { + optional<std::string> urlTemplate = toString(arrayMember(*tiles, i)); + if (!urlTemplate) { + error = { "source tiles member must be a string" }; + return {}; + } + result.tiles.push_back(std::move(*urlTemplate)); + } + + auto schemeValue = objectMember(value, "scheme"); + if (schemeValue) { + optional<std::string> scheme = toString(*schemeValue); + if (scheme && *scheme == "tms") { + result.scheme = Tileset::Scheme::TMS; + } + } + + auto minzoomValue = objectMember(value, "minzoom"); + if (minzoomValue) { + optional<float> minzoom = toNumber(*minzoomValue); + if (!minzoom || *minzoom < 0 || *minzoom > std::numeric_limits<uint8_t>::max()) { + error = { "invalid minzoom" }; + return {}; + } + result.zoomRange.min = *minzoom; + } + + auto maxzoomValue = objectMember(value, "maxzoom"); + if (maxzoomValue) { + optional<float> maxzoom = toNumber(*maxzoomValue); + if (!maxzoom || *maxzoom < 0 || *maxzoom > std::numeric_limits<uint8_t>::max()) { + error = { "invalid maxzoom" }; + return {}; + } + result.zoomRange.max = *maxzoom; + } + + auto attributionValue = objectMember(value, "attribution"); + if (attributionValue) { + optional<std::string> attribution = toString(*attributionValue); + if (!attribution) { + error = { "source attribution must be a string" }; + return {}; + } + result.attribution = std::move(*attribution); + } + + return result; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/transition_options.cpp b/src/mbgl/style/conversion/transition_options.cpp new file mode 100644 index 0000000000..caabe7ec88 --- /dev/null +++ b/src/mbgl/style/conversion/transition_options.cpp @@ -0,0 +1,40 @@ +#include <mbgl/style/conversion/transition_options.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +optional<TransitionOptions> Converter<TransitionOptions>::operator()(const Value& value, Error& error) const { + if (!isObject(value)) { + error = { "transition must be an object" }; + return {}; + } + + TransitionOptions result; + + auto duration = objectMember(value, "duration"); + if (duration) { + auto number = toNumber(*duration); + if (!number) { + error = { "duration must be a number" }; + return {}; + } + result.duration = { std::chrono::milliseconds(int64_t(*number)) }; + } + + auto delay = objectMember(value, "delay"); + if (delay) { + auto number = toNumber(*delay); + if (!number) { + error = { "delay must be a number" }; + return {}; + } + result.delay = { std::chrono::milliseconds(int64_t(*number)) }; + } + + return result; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp index 4a217ee9a6..54e7e708e8 100644 --- a/src/mbgl/style/parser.cpp +++ b/src/mbgl/style/parser.cpp @@ -1,11 +1,13 @@ #include <mbgl/style/parser.hpp> #include <mbgl/style/layer_impl.hpp> +#include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/rapidjson_conversion.hpp> #include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/coordinate.hpp> #include <mbgl/style/conversion/source.hpp> #include <mbgl/style/conversion/layer.hpp> #include <mbgl/style/conversion/light.hpp> +#include <mbgl/style/conversion/transition_options.hpp> #include <mbgl/util/logging.hpp> #include <mbgl/util/string.hpp> |