1#include <mbgl/storage/offline.hpp>
2#include <mbgl/util/tile_cover.hpp>
3#include <mbgl/util/tileset.hpp>
4#include <mbgl/util/projection.hpp>
5
6#include <rapidjson/document.h>
7#include <rapidjson/stringbuffer.h>
8#include <rapidjson/writer.h>
9
10#include <cmath>
11
12namespace mbgl {
13
14OfflineTilePyramidRegionDefinition::OfflineTilePyramidRegionDefinition(
15 std::string styleURL_, LatLngBounds bounds_, double minZoom_, double maxZoom_, float pixelRatio_)
16 : styleURL(std::move(styleURL_)),
17 bounds(std::move(bounds_)),
18 minZoom(minZoom_),
19 maxZoom(maxZoom_),
20 pixelRatio(pixelRatio_) {
21 if (minZoom < 0 || maxZoom < 0 || maxZoom < minZoom || pixelRatio < 0 ||
22 !std::isfinite(x: minZoom) || std::isnan(x: maxZoom) || !std::isfinite(x: pixelRatio)) {
23 throw std::invalid_argument("Invalid offline region definition");
24 }
25}
26
27std::vector<CanonicalTileID> OfflineTilePyramidRegionDefinition::tileCover(style::SourceType type, uint16_t tileSize, const Range<uint8_t>& zoomRange) const {
28 const Range<uint8_t> clampedZoomRange = coveringZoomRange(type, tileSize, zoomRange);
29
30 std::vector<CanonicalTileID> result;
31
32 for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) {
33 for (const auto& tile : util::tileCover(bounds, z)) {
34 result.emplace_back(args: tile.canonical);
35 }
36 }
37
38 return result;
39}
40
41uint64_t OfflineTilePyramidRegionDefinition::tileCount(style::SourceType type, uint16_t tileSize, const Range<uint8_t>& zoomRange) const {
42
43 const Range<uint8_t> clampedZoomRange = coveringZoomRange(type, tileSize, zoomRange);
44 unsigned long result = 0;;
45 for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) {
46 result += util::tileCount(bounds, z);
47 }
48
49 return result;
50}
51
52Range<uint8_t> OfflineTilePyramidRegionDefinition::coveringZoomRange(style::SourceType type, uint16_t tileSize, const Range<uint8_t>& zoomRange) const {
53 double minZ = std::max<double>(a: util::coveringZoomLevel(z: minZoom, type, tileSize), b: zoomRange.min);
54 double maxZ = std::min<double>(a: util::coveringZoomLevel(z: maxZoom, type, tileSize), b: zoomRange.max);
55
56 assert(minZ >= 0);
57 assert(maxZ >= 0);
58 assert(minZ < std::numeric_limits<uint8_t>::max());
59 assert(maxZ < std::numeric_limits<uint8_t>::max());
60 return { static_cast<uint8_t>(minZ), static_cast<uint8_t>(maxZ) };
61}
62
63OfflineRegionDefinition decodeOfflineRegionDefinition(const std::string& region) {
64 rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> doc;
65 doc.Parse<0>(str: region.c_str());
66
67 if (doc.HasParseError() ||
68 !doc.HasMember(name: "style_url") || !doc["style_url"].IsString() ||
69 !doc.HasMember(name: "bounds") || !doc["bounds"].IsArray() || doc["bounds"].Size() != 4 ||
70 !doc["bounds"][0].IsDouble() || !doc["bounds"][1].IsDouble() ||
71 !doc["bounds"][2].IsDouble() || !doc["bounds"][3].IsDouble() ||
72 !doc.HasMember(name: "min_zoom") || !doc["min_zoom"].IsDouble() ||
73 (doc.HasMember(name: "max_zoom") && !doc["max_zoom"].IsDouble()) ||
74 !doc.HasMember(name: "pixel_ratio") || !doc["pixel_ratio"].IsDouble()) {
75 throw std::runtime_error("Malformed offline region definition");
76 }
77
78 std::string styleURL { doc["style_url"].GetString(), doc["style_url"].GetStringLength() };
79 LatLngBounds bounds = LatLngBounds::hull(
80 a: LatLng(doc["bounds"][0].GetDouble(), doc["bounds"][1].GetDouble()),
81 b: LatLng(doc["bounds"][2].GetDouble(), doc["bounds"][3].GetDouble()));
82 double minZoom = doc["min_zoom"].GetDouble();
83 double maxZoom = doc.HasMember(name: "max_zoom") ? doc["max_zoom"].GetDouble() : INFINITY;
84 float pixelRatio = doc["pixel_ratio"].GetDouble();
85
86 return { styleURL, bounds, minZoom, maxZoom, pixelRatio };
87}
88
89std::string encodeOfflineRegionDefinition(const OfflineRegionDefinition& region) {
90 rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> doc;
91 doc.SetObject();
92
93 doc.AddMember(name: "style_url", value: rapidjson::StringRef(str: region.styleURL.data(), length: region.styleURL.length()), allocator&: doc.GetAllocator());
94
95 rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator> bounds(rapidjson::kArrayType);
96 bounds.PushBack(value: region.bounds.south(), allocator&: doc.GetAllocator());
97 bounds.PushBack(value: region.bounds.west(), allocator&: doc.GetAllocator());
98 bounds.PushBack(value: region.bounds.north(), allocator&: doc.GetAllocator());
99 bounds.PushBack(value: region.bounds.east(), allocator&: doc.GetAllocator());
100 doc.AddMember(name: "bounds", value&: bounds, allocator&: doc.GetAllocator());
101
102 doc.AddMember(name: "min_zoom", value: region.minZoom, allocator&: doc.GetAllocator());
103 if (std::isfinite(x: region.maxZoom)) {
104 doc.AddMember(name: "max_zoom", value: region.maxZoom, allocator&: doc.GetAllocator());
105 }
106
107 doc.AddMember(name: "pixel_ratio", value: region.pixelRatio, allocator&: doc.GetAllocator());
108
109 rapidjson::StringBuffer buffer;
110 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
111 doc.Accept(handler&: writer);
112
113 return buffer.GetString();
114}
115
116OfflineRegion::OfflineRegion(int64_t id_,
117 OfflineRegionDefinition definition_,
118 OfflineRegionMetadata metadata_)
119 : id(id_),
120 definition(std::move(definition_)),
121 metadata(std::move(metadata_)) {
122}
123
124OfflineRegion::OfflineRegion(OfflineRegion&&) = default;
125OfflineRegion::~OfflineRegion() = default;
126
127const OfflineRegionDefinition& OfflineRegion::getDefinition() const {
128 return definition;
129}
130
131const OfflineRegionMetadata& OfflineRegion::getMetadata() const {
132 return metadata;
133}
134
135int64_t OfflineRegion::getID() const {
136 return id;
137}
138
139} // namespace mbgl
140

source code of qtlocation/src/3rdparty/mapbox-gl-native/platform/default/mbgl/storage/offline.cpp