summaryrefslogtreecommitdiff
path: root/platform/default/mbgl/storage/offline.cpp
blob: 931e079771f7e5135c88e14124462a5463aca0f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <mbgl/storage/offline.hpp>
#include <mbgl/util/tile_cover.hpp>
#include <mbgl/source/source_info.hpp>

#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>

#include <cmath>

namespace mbgl {

OfflineTilePyramidRegionDefinition::OfflineTilePyramidRegionDefinition(
    const std::string& styleURL_, const LatLngBounds& bounds_, double minZoom_, double maxZoom_, float pixelRatio_)
    : styleURL(styleURL_),
      bounds(bounds_),
      minZoom(minZoom_),
      maxZoom(maxZoom_),
      pixelRatio(pixelRatio_) {
    if (minZoom < 0 || maxZoom < 0 || maxZoom < minZoom || pixelRatio < 0 ||
        !std::isfinite(minZoom) || std::isnan(maxZoom) || !std::isfinite(pixelRatio)) {
        throw std::invalid_argument("Invalid offline region definition");
    }
}

std::vector<TileID> OfflineTilePyramidRegionDefinition::tileCover(SourceType type, uint16_t tileSize, const SourceInfo& info) const {
    double minZ = std::max<double>(coveringZoomLevel(minZoom, type, tileSize), info.minZoom);
    double maxZ = std::min<double>(coveringZoomLevel(maxZoom, type, tileSize), info.maxZoom);

    assert(minZ >= 0);
    assert(maxZ >= 0);
    assert(minZ < std::numeric_limits<uint8_t>::max());
    assert(maxZ < std::numeric_limits<uint8_t>::max());

    std::vector<TileID> result;

    for (uint8_t z = minZ; z <= maxZ; z++) {
        for (const auto& tile : mbgl::tileCover(bounds, z, z)) {
            result.push_back(tile.normalized());
        }
    }

    return result;
}

OfflineRegionDefinition decodeOfflineRegionDefinition(const std::string& region) {
    rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> doc;
    doc.Parse<0>(region.c_str());

    if (doc.HasParseError() ||
        !doc.HasMember("style_url") || !doc["style_url"].IsString() ||
        !doc.HasMember("bounds") || !doc["bounds"].IsArray() || doc["bounds"].Size() != 4 ||
          !doc["bounds"][0].IsDouble() || !doc["bounds"][1].IsDouble() ||
          !doc["bounds"][2].IsDouble() || !doc["bounds"][3].IsDouble() ||
        !doc.HasMember("min_zoom") || !doc["min_zoom"].IsDouble() ||
        (doc.HasMember("max_zoom") && !doc["max_zoom"].IsDouble()) ||
        !doc.HasMember("pixel_ratio") || !doc["pixel_ratio"].IsDouble()) {
        throw std::runtime_error("Malformed offline region definition");
    }

    std::string styleURL { doc["style_url"].GetString(), doc["style_url"].GetStringLength() };
    LatLngBounds bounds = LatLngBounds::hull(
        LatLng(doc["bounds"][0].GetDouble(), doc["bounds"][1].GetDouble()),
        LatLng(doc["bounds"][2].GetDouble(), doc["bounds"][3].GetDouble()));
    double minZoom = doc["min_zoom"].GetDouble();
    double maxZoom = doc.HasMember("max_zoom") ? doc["max_zoom"].GetDouble() : INFINITY;
    float pixelRatio = doc["pixel_ratio"].GetDouble();

    return { styleURL, bounds, minZoom, maxZoom, pixelRatio };
}

std::string encodeOfflineRegionDefinition(const OfflineRegionDefinition& region) {
    rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> doc;
    doc.SetObject();

    doc.AddMember("style_url", rapidjson::StringRef(region.styleURL.data(), region.styleURL.length()), doc.GetAllocator());

    rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator> bounds(rapidjson::kArrayType);
    bounds.PushBack(region.bounds.south(), doc.GetAllocator());
    bounds.PushBack(region.bounds.west(), doc.GetAllocator());
    bounds.PushBack(region.bounds.north(), doc.GetAllocator());
    bounds.PushBack(region.bounds.east(), doc.GetAllocator());
    doc.AddMember("bounds", bounds, doc.GetAllocator());

    doc.AddMember("min_zoom", region.minZoom, doc.GetAllocator());
    if (std::isfinite(region.maxZoom)) {
        doc.AddMember("max_zoom", region.maxZoom, doc.GetAllocator());
    }

    doc.AddMember("pixel_ratio", region.pixelRatio, doc.GetAllocator());

    rapidjson::StringBuffer buffer;
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
    doc.Accept(writer);

    return buffer.GetString();
}

OfflineRegion::OfflineRegion(int64_t id_,
                             const OfflineRegionDefinition& definition_,
                             const OfflineRegionMetadata& metadata_)
    : id(id_),
      definition(definition_),
      metadata(metadata_) {
}

OfflineRegion::OfflineRegion(OfflineRegion&&) = default;
OfflineRegion::~OfflineRegion() = default;

const OfflineRegionDefinition& OfflineRegion::getDefinition() const {
    return definition;
}

const OfflineRegionMetadata& OfflineRegion::getMetadata() const {
    return metadata;
}

int64_t OfflineRegion::getID() const {
    return id;
}

} // namespace mbgl