summaryrefslogtreecommitdiff
path: root/bin/offline.cpp
blob: c03149d2f5bdab34435b68f46ee125cbe30fa328 (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
#include <mbgl/util/default_styles.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/io.hpp>

#include <mbgl/storage/default_file_source.hpp>

#include <cstdlib>
#include <iostream>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wshadow"
#include <boost/program_options.hpp>
#pragma GCC diagnostic pop

namespace po = boost::program_options;
using namespace std::literals::chrono_literals;

int main(int argc, char *argv[]) {
    std::string style = mbgl::util::default_styles::streets.url;
    double north = 37.2, west = -122.8, south = 38.1, east = -121.7; // Bay area
    double minZoom = 0.0, maxZoom = 15.0, pixelRatio = 1.0;
    std::string output = "offline.db";

    const char* tokenEnv = getenv("MAPBOX_ACCESS_TOKEN");
    std::string token = tokenEnv ? tokenEnv : std::string();

    po::options_description desc("Allowed options");
    desc.add_options()
        ("style,s", po::value(&style)->value_name("URL"), "Map stylesheet")
        ("north", po::value(&north)->value_name("degrees")->default_value(north), "North latitude")
        ("west", po::value(&west)->value_name("degrees")->default_value(west), "West longitude")
        ("south", po::value(&south)->value_name("degrees")->default_value(south), "South latitude")
        ("east", po::value(&east)->value_name("degrees")->default_value(east), "East longitude")
        ("minZoom", po::value(&minZoom)->value_name("number")->default_value(minZoom), "Min zoom level")
        ("maxZoom", po::value(&maxZoom)->value_name("number")->default_value(maxZoom), "Max zoom level")
        ("pixelRatio", po::value(&pixelRatio)->value_name("number")->default_value(pixelRatio), "Pixel ratio")
        ("token,t", po::value(&token)->value_name("key")->default_value(token), "Mapbox access token")
        ("output,o", po::value(&output)->value_name("file")->default_value(output), "Output database file name")
    ;

    try {
        po::variables_map vm;
        po::store(po::parse_command_line(argc, argv, desc), vm);
        po::notify(vm);
    } catch(std::exception& e) {
        std::cout << "Error: " << e.what() << std::endl << desc;
        exit(1);
    }

    using namespace mbgl;

    util::RunLoop loop;

    DefaultFileSource fileSource(output, ".");
    fileSource.setAccessToken(token);

    LatLngBounds boundingBox = LatLngBounds::hull(LatLng(north, west), LatLng(south, east));
    OfflineTilePyramidRegionDefinition definition(style, boundingBox, minZoom, maxZoom, pixelRatio);
    OfflineRegionMetadata metadata;

    class Observer : public OfflineRegionObserver {
    public:
        Observer(util::RunLoop& loop_)
            : loop(loop_),
              start(SystemClock::now()) {
        }

        void statusChanged(OfflineRegionStatus status) override {
            std::string bytesPerSecond = "-";

            auto elapsedSeconds = (SystemClock::now() - start) / 1s;
            if (elapsedSeconds != 0) {
                bytesPerSecond = util::toString(status.completedResourceSize / elapsedSeconds);
            }

            std::cout << status.completedResourceCount << " / " << status.requiredResourceCount
                      << " resources"
                      << (status.requiredResourceCountIsPrecise ? "; " : " (indeterminate); ")
                      << status.completedResourceSize << " bytes downloaded"
                      << " (" << bytesPerSecond << " bytes/sec)"
                      << std::endl;

            if (status.complete()) {
                std::cout << "Finished" << std::endl;
                loop.stop();
            }
        }

        void responseError(Response::Error error) override {
            std::cerr << error.reason << " downloading resource: " << error.message << std::endl;
        }

        util::RunLoop& loop;
        SystemTimePoint start;
    };

    fileSource.createOfflineRegion(definition, metadata, [&] (std::exception_ptr error, optional<OfflineRegion> region) {
        if (error) {
            std::cerr << "Error creating region: " << util::toString(error) << std::endl;
            loop.stop();
            exit(1);
        } else {
            assert(region);
            fileSource.setOfflineRegionObserver(*region, std::make_unique<Observer>(loop));
            fileSource.setOfflineRegionDownloadState(*region, OfflineRegionDownloadState::Active);
        }
    });

    loop.run();
    return 0;
}