#pragma once #include #include #include #include #include #include #include #include #include #include #include namespace mbgl { namespace style { namespace conversion { template <> struct Converter> { public: template optional> operator()(const V& 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 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. template optional> convertURLOrTileset(const V& value, Error& error) const { auto urlVal = objectMember(value, "url"); if (!urlVal) { optional tileset = convert(value, error); if (!tileset) { return {}; } return { *tileset }; } optional url = toString(*urlVal); if (!url) { error = { "source url must be a string" }; return {}; } return { *url }; } template optional> convertRasterSource(const std::string& id, const V& value, Error& error) const { optional> urlOrTileset = convertURLOrTileset(value, error); if (!urlOrTileset) { return {}; } uint16_t tileSize = util::tileSize; auto tileSizeValue = objectMember(value, "tileSize"); if (tileSizeValue) { optional size = toNumber(*tileSizeValue); if (!size || *size < 0 || *size > std::numeric_limits::max()) { error = { "invalid tileSize" }; return {}; } tileSize = *size; } return { std::make_unique(id, std::move(*urlOrTileset), tileSize) }; } template optional> convertVectorSource(const std::string& id, const V& value, Error& error) const { optional> urlOrTileset = convertURLOrTileset(value, error); if (!urlOrTileset) { return {}; } return { std::make_unique(id, std::move(*urlOrTileset)) }; } template optional> convertGeoJSONSource(const std::string& id, const V& value, Error& error) const { auto dataValue = objectMember(value, "data"); if (!dataValue) { error = { "GeoJSON source must have a data value" }; return {}; } optional options = convert(value, error); if (!options) { return {}; } auto result = std::make_unique(id, *options); if (isObject(*dataValue)) { optional geoJSON = convert(*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) }; } template optional> convertImageSource(const std::string& id, const V& 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 coordinates; for (std::size_t i=0; i < 4; i++) { auto latLng = conversion::convert(arrayMember(*coordinatesValue,i), error); if (!latLng) { return {}; } coordinates[i] = *latLng; } auto result = std::make_unique(id, coordinates); result->setURL(*urlString); return { std::move(result) }; } }; } // namespace conversion } // namespace style } // namespace mbgl