1 #include <mbgl/style/conversion/tileset.hpp>
2 #include <mbgl/util/geo.hpp>
3 #include <mbgl/math/clamp.hpp>
4 
5 namespace mbgl {
6 namespace style {
7 namespace conversion {
8 
operator ()(const Convertible & value,Error & error) const9 optional<Tileset> Converter<Tileset>::operator()(const Convertible& value, Error& error) const {
10     Tileset result;
11 
12     auto tiles = objectMember(value, "tiles");
13     if (!tiles) {
14         error = { "source must have tiles" };
15         return {};
16     }
17 
18     if (!isArray(*tiles)) {
19         error = { "source tiles must be an array" };
20         return {};
21     }
22 
23     for (std::size_t i = 0; i < arrayLength(*tiles); i++) {
24         optional<std::string> urlTemplate = toString(arrayMember(*tiles, i));
25         if (!urlTemplate) {
26             error = { "source tiles member must be a string" };
27             return {};
28         }
29         result.tiles.push_back(std::move(*urlTemplate));
30     }
31 
32     auto schemeValue = objectMember(value, "scheme");
33     if (schemeValue) {
34         optional<std::string> scheme = toString(*schemeValue);
35         if (scheme && *scheme == "tms") {
36             result.scheme = Tileset::Scheme::TMS;
37         }
38     }
39 
40     auto encodingValue = objectMember(value, "encoding");
41     if (encodingValue) {
42         optional<std::string> encoding = toString(*encodingValue);
43         if (encoding && *encoding == "terrarium") {
44             result.encoding = Tileset::DEMEncoding::Terrarium;
45         } else if (encoding && *encoding != "mapbox") {
46             error = { "invalid raster-dem encoding type - valid types are 'mapbox' and 'terrarium' " };
47         }
48     }
49 
50     auto minzoomValue = objectMember(value, "minzoom");
51     if (minzoomValue) {
52         optional<float> minzoom = toNumber(*minzoomValue);
53         if (!minzoom || *minzoom < 0 || *minzoom > std::numeric_limits<uint8_t>::max()) {
54             error = { "invalid minzoom" };
55             return {};
56         }
57         result.zoomRange.min = *minzoom;
58     }
59 
60     auto maxzoomValue = objectMember(value, "maxzoom");
61     if (maxzoomValue) {
62         optional<float> maxzoom = toNumber(*maxzoomValue);
63         if (!maxzoom || *maxzoom < 0 || *maxzoom > std::numeric_limits<uint8_t>::max()) {
64             error = { "invalid maxzoom" };
65             return {};
66         }
67         result.zoomRange.max = *maxzoom;
68     }
69 
70     auto attributionValue = objectMember(value, "attribution");
71     if (attributionValue) {
72         optional<std::string> attribution = toString(*attributionValue);
73         if (!attribution) {
74             error = { "source attribution must be a string" };
75             return {};
76         }
77         result.attribution = std::move(*attribution);
78     }
79 
80     auto boundsValue = objectMember(value, "bounds");
81     if (boundsValue) {
82         if (!isArray(*boundsValue) || arrayLength(*boundsValue) != 4) {
83             error = { "bounds must be an array with left, bottom, top, and right values" };
84             return {};
85         }
86         optional<double> left = toDouble(arrayMember(*boundsValue, 0));
87         optional<double> bottom = toDouble(arrayMember(*boundsValue, 1));
88         optional<double> right = toDouble(arrayMember(*boundsValue, 2));
89         optional<double> top = toDouble(arrayMember(*boundsValue, 3));
90 
91         if (!left || !right || !bottom || !top) {
92             error = { "bounds array must contain numeric longitude and latitude values" };
93             return {};
94         }
95 
96         bottom = util::clamp(*bottom, -90.0, 90.0);
97         top = util::clamp(*top, -90.0, 90.0);
98         if (top <= bottom){
99             error = { "bounds bottom latitude must be smaller than top latitude" };
100             return {};
101         }
102 
103         if(*left >= *right) {
104             error = { "bounds left longitude should be less than right longitude" };
105             return {};
106         }
107         left = util::max(-180.0, *left);
108         right = util::min(180.0, *right);
109         result.bounds = LatLngBounds::hull({ *bottom, *left }, { *top, *right });
110     }
111 
112     return result;
113 }
114 
115 } // namespace conversion
116 } // namespace style
117 } // namespace mbgl
118