[general] moving ios and android project under ./platform folder
This commit is contained in:
42
bin/CMakeLists.txt
Normal file
42
bin/CMakeLists.txt
Normal file
@@ -0,0 +1,42 @@
|
||||
add_executable(
|
||||
mbgl-cache
|
||||
${PROJECT_SOURCE_DIR}/bin/cache.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
mbgl-cache
|
||||
PRIVATE
|
||||
Mapbox::Base
|
||||
Mapbox::Base::Extras::args
|
||||
mbgl-compiler-options
|
||||
mbgl-core
|
||||
)
|
||||
|
||||
add_executable(
|
||||
mbgl-offline
|
||||
${PROJECT_SOURCE_DIR}/bin/offline.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
mbgl-offline
|
||||
PRIVATE Mapbox::Base::Extras::args mbgl-compiler-options mbgl-core
|
||||
)
|
||||
|
||||
add_executable(
|
||||
mbgl-render
|
||||
${PROJECT_SOURCE_DIR}/bin/render.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
mbgl-render
|
||||
PRIVATE Mapbox::Base::Extras::args mbgl-compiler-options mbgl-core
|
||||
)
|
||||
|
||||
install(TARGETS mbgl-offline mbgl-render RUNTIME DESTINATION bin)
|
||||
|
||||
# FIXME: CI must have a valid token
|
||||
#
|
||||
# add_test(NAME mbgl-offline-tool-test COMMAND mbgl-offline -s mapbox://styles/mapbox/satellite-v9 --maxZoom=0 WORKING_DIRECTORY
|
||||
# ${PROJECT_SOURCE_DIR} )
|
||||
#
|
||||
# add_test(NAME mbgl-render-tool-test COMMAND mbgl-render WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} )
|
||||
98
bin/cache.cpp
Normal file
98
bin/cache.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
#include <mbgl/storage/file_source_manager.hpp>
|
||||
#include <mbgl/storage/resource.hpp>
|
||||
#include <mbgl/storage/resource_options.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <args.hxx>
|
||||
#include <mapbox/io/io.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
args::ArgumentParser p("Mapbox GL cache tool", "");
|
||||
args::HelpFlag helpFlag(p, "help", "Display this help menu", {'h'});
|
||||
|
||||
args::ValueFlag<std::string> urlValue(p, "URL", "Resource URL (required)", {'u'}, args::Options::Required);
|
||||
args::ValueFlag<std::string> cacheValue(
|
||||
p, "cache", "Path to the cache database (required)", {'c'}, args::Options::Required);
|
||||
args::ValueFlag<std::string> dataValue(
|
||||
p, "data", "Path to the resource data (required)", {'d'}, args::Options::Required);
|
||||
args::ValueFlag<std::string> etagValue(p, "etag", "Cache eTag, none otherwise", {'t'});
|
||||
args::ValueFlag<unsigned long> expiresValue(p, "expires", "Expires date, will use 'now' otherwise", {'e'});
|
||||
args::ValueFlag<unsigned long> modifiedValue(p, "modified", "Modified date, will use 'now' otherwise", {'m'});
|
||||
|
||||
std::unordered_map<std::string, mbgl::Resource::Kind> typeMap{{"glyphs", mbgl::Resource::Glyphs},
|
||||
{"image", mbgl::Resource::Image},
|
||||
{"source", mbgl::Resource::Source},
|
||||
{"sprite-image", mbgl::Resource::SpriteImage},
|
||||
{"sprite-json", mbgl::Resource::SpriteJSON},
|
||||
{"style", mbgl::Resource::Style},
|
||||
{"tile", mbgl::Resource::Tile}};
|
||||
|
||||
std::string typeHelp("One of the following (required):");
|
||||
for (auto key : typeMap) {
|
||||
typeHelp += " " + key.first;
|
||||
}
|
||||
|
||||
args::MapFlag<std::string, mbgl::Resource::Kind> typeFlag(
|
||||
p, "type", typeHelp, {"type"}, typeMap, args::Options::Required);
|
||||
|
||||
args::Group tileIdGroup(p, "Coordinates (required for 'tile')", args::Group::Validators::AllOrNone);
|
||||
args::ValueFlag<int32_t> xValueFlag(tileIdGroup, "x", "Tile x coordinate", {'x'});
|
||||
args::ValueFlag<int32_t> yValueFlag(tileIdGroup, "y", "Tile y coordinate", {'y'});
|
||||
args::ValueFlag<int32_t> zValueFlag(tileIdGroup, "z", "The zoom level", {'z'});
|
||||
|
||||
try {
|
||||
p.ParseCLI(argc, argv);
|
||||
} catch (const args::Help&) {
|
||||
std::cout << p;
|
||||
exit(0);
|
||||
} catch (const args::ParseError& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << p;
|
||||
exit(1);
|
||||
} catch (const args::ValidationError& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << p;
|
||||
exit(2);
|
||||
}
|
||||
|
||||
auto file = mapbox::base::io::readFile(args::get(dataValue));
|
||||
if (!file) {
|
||||
std::cerr << file.error() << std::endl;
|
||||
exit(3);
|
||||
}
|
||||
|
||||
mbgl::Response response;
|
||||
response.data = std::make_shared<std::string>(*file);
|
||||
response.etag = etagValue ? args::get(etagValue) : std::string();
|
||||
response.expires = expiresValue ? mbgl::Timestamp(mbgl::Seconds(args::get(expiresValue))) : mbgl::util::now();
|
||||
response.modified = modifiedValue ? mbgl::Timestamp(mbgl::Seconds(args::get(modifiedValue))) : mbgl::util::now();
|
||||
|
||||
mbgl::Resource resource(args::get(typeFlag), args::get(urlValue));
|
||||
|
||||
if (args::get(typeFlag) == mbgl::Resource::Tile) {
|
||||
if (!xValueFlag || !yValueFlag || !zValueFlag) {
|
||||
std::cerr << "Error: -x, -y and -z must be provided for tiles" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
resource.tileData = {{args::get(urlValue),
|
||||
1,
|
||||
args::get(xValueFlag),
|
||||
args::get(yValueFlag),
|
||||
static_cast<int8_t>(args::get(zValueFlag))}};
|
||||
}
|
||||
|
||||
mbgl::util::RunLoop loop;
|
||||
std::shared_ptr<mbgl::FileSource> dbfs = mbgl::FileSourceManager::get()->getFileSource(
|
||||
mbgl::FileSourceType::Database, mbgl::ResourceOptions().withCachePath(args::get(cacheValue)));
|
||||
dbfs->forward(resource, response, [&loop] { loop.stop(); });
|
||||
loop.run();
|
||||
return 0;
|
||||
}
|
||||
274
bin/offline.cpp
Normal file
274
bin/offline.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
#include <mbgl/util/default_styles.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/geojson.hpp>
|
||||
|
||||
#include <mbgl/storage/database_file_source.hpp>
|
||||
#include <mbgl/storage/file_source_manager.hpp>
|
||||
#include <mbgl/storage/resource_options.hpp>
|
||||
|
||||
#include <args.hxx>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <csignal>
|
||||
#include <atomic>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
std::string readFile(const std::string& fileName) {
|
||||
std::ifstream stream(fileName.c_str());
|
||||
if (!stream.good()) {
|
||||
throw std::runtime_error("Cannot read file: " + fileName);
|
||||
}
|
||||
|
||||
std::stringstream buffer;
|
||||
buffer << stream.rdbuf();
|
||||
stream.close();
|
||||
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
mapbox::geometry::geometry<double> parseGeometry(const std::string& json) {
|
||||
using namespace mapbox::geojson;
|
||||
auto geojson = parse(json);
|
||||
return geojson.match(
|
||||
[](const geometry& geom) {
|
||||
return geom;
|
||||
},
|
||||
[](const feature& feature) {
|
||||
return feature.geometry;
|
||||
},
|
||||
[](const feature_collection& featureCollection) {
|
||||
if (featureCollection.size() < 1) {
|
||||
throw std::runtime_error("No features in feature collection");
|
||||
}
|
||||
geometry_collection geometries;
|
||||
|
||||
for (auto feature : featureCollection) {
|
||||
geometries.push_back(feature.geometry);
|
||||
}
|
||||
|
||||
return geometries;
|
||||
});
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, mbgl::Response::Error::Reason r) {
|
||||
switch (r) {
|
||||
case mbgl::Response::Error::Reason::Success:
|
||||
return os << "Response::Error::Reason::Success";
|
||||
case mbgl::Response::Error::Reason::NotFound:
|
||||
return os << "Response::Error::Reason::NotFound";
|
||||
case mbgl::Response::Error::Reason::Server:
|
||||
return os << "Response::Error::Reason::Server";
|
||||
case mbgl::Response::Error::Reason::Connection:
|
||||
return os << "Response::Error::Reason::Connection";
|
||||
case mbgl::Response::Error::Reason::RateLimit:
|
||||
return os << "Response::Error::Reason::RateLimit";
|
||||
case mbgl::Response::Error::Reason::Other:
|
||||
return os << "Response::Error::Reason::Other";
|
||||
}
|
||||
|
||||
// The above switch is exhaustive, but placate GCC nonetheless:
|
||||
assert(false);
|
||||
return os;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
args::ArgumentParser argumentParser("Mapbox GL offline tool");
|
||||
args::HelpFlag helpFlag(argumentParser, "help", "Display this help menu", {'h', "help"});
|
||||
|
||||
args::ValueFlag<std::string> tokenValue(argumentParser, "key", "Mapbox access token", {'t', "token"});
|
||||
args::ValueFlag<std::string> styleValue(argumentParser, "URL", "Map stylesheet", {'s', "style"});
|
||||
args::ValueFlag<std::string> outputValue(argumentParser, "file", "Output database file name", {'o', "output"});
|
||||
args::ValueFlag<std::string> apiBaseValue(argumentParser, "URL", "API Base URL", {'a', "apiBaseURL"});
|
||||
|
||||
args::Group mergeGroup(argumentParser, "Merge databases:", args::Group::Validators::AllOrNone);
|
||||
args::ValueFlag<std::string> mergePathValue(mergeGroup, "merge", "Database to merge from", {'m', "merge"});
|
||||
args::ValueFlag<std::string> inputValue(mergeGroup, "input", "Database to merge into. Use with --merge option.", {'i', "input"});
|
||||
|
||||
// LatLngBounds
|
||||
args::Group latLngBoundsGroup(argumentParser, "LatLng bounds:", args::Group::Validators::AllOrNone);
|
||||
args::ValueFlag<double> northValue(latLngBoundsGroup, "degrees", "North latitude", {"north"});
|
||||
args::ValueFlag<double> westValue(latLngBoundsGroup, "degrees", "West longitude", {"west"});
|
||||
args::ValueFlag<double> southValue(latLngBoundsGroup, "degrees", "South latitude", {"south"});
|
||||
args::ValueFlag<double> eastValue(latLngBoundsGroup, "degrees", "East longitude", {"east"});
|
||||
|
||||
// Geometry
|
||||
args::Group geoJSONGroup(argumentParser, "GeoJson geometry:", args::Group::Validators::AllOrNone);
|
||||
args::ValueFlag<std::string> geometryValue(geoJSONGroup, "file", "GeoJSON Feature file containing the region geometry (can't be a FeatureCollection)", {"geojson"});
|
||||
|
||||
args::ValueFlag<double> minZoomValue(argumentParser, "number", "Min zoom level", {"minZoom"});
|
||||
args::ValueFlag<double> maxZoomValue(argumentParser, "number", "Max zoom level", {"maxZoom"});
|
||||
args::ValueFlag<double> pixelRatioValue(argumentParser, "number", "Pixel ratio", {"pixelRatio"});
|
||||
args::ValueFlag<bool> includeIdeographsValue(argumentParser, "boolean", "Include CJK glyphs", {"includeIdeographs"});
|
||||
|
||||
try {
|
||||
argumentParser.ParseCLI(argc, argv);
|
||||
} catch (const args::Help&) {
|
||||
std::cout << argumentParser;
|
||||
exit(0);
|
||||
} catch (const args::ParseError& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << argumentParser;
|
||||
exit(1);
|
||||
} catch (const args::ValidationError& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << argumentParser;
|
||||
exit(2);
|
||||
}
|
||||
|
||||
std::string style = styleValue ? args::get(styleValue) : mbgl::util::default_styles::streets.url;
|
||||
|
||||
mbgl::optional<std::string> mergePath = {};
|
||||
if (mergePathValue) mergePath = args::get(mergePathValue);
|
||||
mbgl::optional<std::string> inputDb = {};
|
||||
if (inputValue) inputDb = args::get(inputValue);
|
||||
|
||||
const double minZoom = minZoomValue ? args::get(minZoomValue) : 0.0;
|
||||
const double maxZoom = maxZoomValue ? args::get(maxZoomValue) : 15.0;
|
||||
const double pixelRatio = pixelRatioValue ? args::get(pixelRatioValue) : 1.0;
|
||||
const bool includeIdeographs = includeIdeographsValue ? args::get(includeIdeographsValue) : false;
|
||||
const std::string output = outputValue ? args::get(outputValue) : "offline.db";
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
OfflineRegionDefinition definition = [&]() {
|
||||
if (geometryValue) {
|
||||
try {
|
||||
std::string json = readFile(geometryValue.Get());
|
||||
auto geometry = parseGeometry(json);
|
||||
return OfflineRegionDefinition{ OfflineGeometryRegionDefinition(style, geometry, minZoom, maxZoom, pixelRatio, includeIdeographs) };
|
||||
} catch(const std::runtime_error& e) {
|
||||
std::cerr << "Could not parse geojson file " << geometryValue.Get() << ": " << e.what() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
// Bay area
|
||||
const double north = northValue ? args::get(northValue) : 37.2;
|
||||
const double west = westValue ? args::get(westValue) : -122.8;
|
||||
const double south = southValue ? args::get(southValue) : 38.1;
|
||||
const double east = eastValue ? args::get(eastValue) : -121.7;
|
||||
LatLngBounds boundingBox = LatLngBounds::hull(LatLng(north, west), LatLng(south, east));
|
||||
return OfflineRegionDefinition{ OfflineTilePyramidRegionDefinition(style, boundingBox, minZoom, maxZoom, pixelRatio, includeIdeographs) };
|
||||
}
|
||||
}();
|
||||
|
||||
const char* tokenEnv = getenv("MAPBOX_ACCESS_TOKEN");
|
||||
const std::string token = tokenValue ? args::get(tokenValue) : (tokenEnv ? tokenEnv : std::string());
|
||||
|
||||
const std::string apiBaseURL = apiBaseValue ? args::get(apiBaseValue) : mbgl::util::API_BASE_URL;
|
||||
|
||||
|
||||
util::RunLoop loop;
|
||||
std::shared_ptr<DatabaseFileSource> fileSource = std::static_pointer_cast<DatabaseFileSource>(
|
||||
std::shared_ptr<FileSource>(FileSourceManager::get()->getFileSource(
|
||||
FileSourceType::Database,
|
||||
ResourceOptions().withAccessToken(token).withBaseURL(apiBaseURL).withCachePath(output))));
|
||||
|
||||
std::unique_ptr<OfflineRegion> region;
|
||||
|
||||
if (inputDb && mergePath) {
|
||||
DatabaseFileSource inputSource(ResourceOptions().withCachePath(*inputDb));
|
||||
|
||||
int retCode = 0;
|
||||
std::cout << "Start Merge" << std::endl;
|
||||
inputSource.mergeOfflineRegions(*mergePath, [&] (mbgl::expected<std::vector<OfflineRegion>, std::exception_ptr> result) {
|
||||
|
||||
if (!result) {
|
||||
std::cerr << "Error merging database: " << util::toString(result.error()) << std::endl;
|
||||
retCode = 1;
|
||||
} else {
|
||||
std::cout << " Added " << result->size() << " Regions" << std::endl;
|
||||
std::cout << "Finished Merge" << std::endl;
|
||||
}
|
||||
loop.stop();
|
||||
});
|
||||
loop.run();
|
||||
return retCode;
|
||||
}
|
||||
|
||||
OfflineRegionMetadata metadata;
|
||||
|
||||
class Observer : public OfflineRegionObserver {
|
||||
public:
|
||||
Observer(OfflineRegion& region_,
|
||||
std::shared_ptr<DatabaseFileSource> fileSource_,
|
||||
util::RunLoop& loop_,
|
||||
mbgl::optional<std::string> mergePath_)
|
||||
: region(region_),
|
||||
fileSource(std::move(fileSource_)),
|
||||
loop(loop_),
|
||||
mergePath(std::move(mergePath_)),
|
||||
start(util::now()) {}
|
||||
|
||||
void statusChanged(OfflineRegionStatus status) override {
|
||||
if (status.downloadState == OfflineRegionDownloadState::Inactive) {
|
||||
std::cout << "stopped" << std::endl;
|
||||
loop.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
std::string bytesPerSecond = "-";
|
||||
|
||||
auto elapsedSeconds = (util::now() - start) / 1s;
|
||||
if (elapsedSeconds != 0) {
|
||||
bytesPerSecond = util::toString(status.completedResourceSize / elapsedSeconds);
|
||||
}
|
||||
|
||||
std::cout << status.completedResourceCount << " / " << status.requiredResourceCount << " resources | "
|
||||
<< status.completedTileCount << " / " << status.requiredTileCount << " tiles"
|
||||
<< (status.requiredResourceCountIsPrecise ? " | " : " (indeterminate); ")
|
||||
<< status.completedResourceSize << " bytes downloaded"
|
||||
<< " (" << bytesPerSecond << " bytes/sec)" << std::endl;
|
||||
|
||||
if (status.complete()) {
|
||||
std::cout << "Finished Download" << std::endl;
|
||||
loop.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void responseError(Response::Error error) override {
|
||||
std::cerr << error.reason << " downloading resource: " << error.message << std::endl;
|
||||
}
|
||||
|
||||
void mapboxTileCountLimitExceeded(uint64_t limit) override {
|
||||
std::cerr << "Error: reached limit of " << limit << " offline tiles" << std::endl;
|
||||
}
|
||||
|
||||
OfflineRegion& region;
|
||||
std::shared_ptr<DatabaseFileSource> fileSource;
|
||||
util::RunLoop& loop;
|
||||
mbgl::optional<std::string> mergePath;
|
||||
Timestamp start;
|
||||
};
|
||||
|
||||
static auto stop = [&] {
|
||||
if (region) {
|
||||
std::cout << "Stopping download... ";
|
||||
fileSource->setOfflineRegionDownloadState(*region, OfflineRegionDownloadState::Inactive);
|
||||
}
|
||||
};
|
||||
|
||||
std::signal(SIGINT, [] (int) { stop(); });
|
||||
|
||||
fileSource->createOfflineRegion(
|
||||
definition, metadata, [&](mbgl::expected<OfflineRegion, std::exception_ptr> region_) {
|
||||
if (!region_) {
|
||||
std::cerr << "Error creating region: " << util::toString(region_.error()) << std::endl;
|
||||
loop.stop();
|
||||
exit(1);
|
||||
} else {
|
||||
assert(region_);
|
||||
region = std::make_unique<OfflineRegion>(std::move(*region_));
|
||||
fileSource->setOfflineRegionObserver(*region,
|
||||
std::make_unique<Observer>(*region, fileSource, loop, mergePath));
|
||||
fileSource->setOfflineRegionDownloadState(*region, OfflineRegionDownloadState::Active);
|
||||
}
|
||||
});
|
||||
|
||||
loop.run();
|
||||
return 0;
|
||||
}
|
||||
18
bin/offline.sh
Executable file
18
bin/offline.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
OFFLINE=./build/macos/Release/mbgl-offline
|
||||
|
||||
# Barcelona
|
||||
$OFFLINE --north 41.4664 --west 2.0407 --south 41.2724 --east 2.2680 --output barcelona.db
|
||||
$OFFLINE --north 41.4664 --west 2.0407 --south 41.2724 --east 2.2680 --output barcelona_sat.db --style mapbox://styles/mapbox/satellite-v8
|
||||
|
||||
# Greater London within the M25 at zoom levels 0–15
|
||||
$OFFLINE --north 51.6777 --west -0.5026 --south 51.3237 --east 0.2527 --maxZoom 15 --output london.db
|
||||
$OFFLINE --north 51.6777 --west -0.5026 --south 51.3237 --east 0.2527 --maxZoom 15 --output london_sat.db --style mapbox://styles/mapbox/satellite-v8
|
||||
|
||||
# The contiguous United States at zoom levels 0–9
|
||||
$OFFLINE --north 49.6107 --west -125.5078 --south 24.2870 --east -66.3574 --maxZoom 9 --output us.db
|
||||
$OFFLINE --north 49.6107 --west -125.5078 --south 24.2870 --east -66.3574 --maxZoom 9 --output us_sat.db --style mapbox://styles/mapbox/satellite-v8
|
||||
110
bin/render.cpp
Normal file
110
bin/render.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/map/map_options.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
#include <mbgl/util/default_styles.hpp>
|
||||
|
||||
#include <mbgl/gfx/backend.hpp>
|
||||
#include <mbgl/gfx/headless_frontend.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
|
||||
#include <args.hxx>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
args::ArgumentParser argumentParser("Mapbox GL render tool");
|
||||
args::HelpFlag helpFlag(argumentParser, "help", "Display this help menu", {"help"});
|
||||
|
||||
args::ValueFlag<std::string> backendValue(argumentParser, "Backend", "Rendering backend", {"backend"});
|
||||
args::ValueFlag<std::string> tokenValue(argumentParser, "key", "Mapbox access token", {'t', "token"});
|
||||
args::ValueFlag<std::string> styleValue(argumentParser, "URL", "Map stylesheet", {'s', "style"});
|
||||
args::ValueFlag<std::string> outputValue(argumentParser, "file", "Output file name", {'o', "output"});
|
||||
args::ValueFlag<std::string> cacheValue(argumentParser, "file", "Cache database file name", {'c', "cache"});
|
||||
args::ValueFlag<std::string> assetsValue(argumentParser, "file", "Directory to which asset:// URLs will resolve", {'a', "assets"});
|
||||
|
||||
args::Flag debugFlag(argumentParser, "debug", "Debug mode", {"debug"});
|
||||
|
||||
args::ValueFlag<double> pixelRatioValue(argumentParser, "number", "Image scale factor", {'r', "ratio"});
|
||||
|
||||
args::ValueFlag<double> zoomValue(argumentParser, "number", "Zoom level", {'z', "zoom"});
|
||||
|
||||
args::ValueFlag<double> lonValue(argumentParser, "degrees", "Longitude", {'x', "lon"});
|
||||
args::ValueFlag<double> latValue(argumentParser, "degrees", "Latitude", {'y', "lat"});
|
||||
args::ValueFlag<double> bearingValue(argumentParser, "degrees", "Bearing", {'b', "bearing"});
|
||||
args::ValueFlag<double> pitchValue(argumentParser, "degrees", "Pitch", {'p', "pitch"});
|
||||
args::ValueFlag<uint32_t> widthValue(argumentParser, "pixels", "Image width", {'w', "width"});
|
||||
args::ValueFlag<uint32_t> heightValue(argumentParser, "pixels", "Image height", {'h', "height"});
|
||||
|
||||
try {
|
||||
argumentParser.ParseCLI(argc, argv);
|
||||
} catch (const args::Help&) {
|
||||
std::cout << argumentParser;
|
||||
exit(0);
|
||||
} catch (const args::ParseError& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << argumentParser;
|
||||
exit(1);
|
||||
} catch (const args::ValidationError& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << argumentParser;
|
||||
exit(2);
|
||||
}
|
||||
|
||||
std::string style = styleValue ? args::get(styleValue) : mbgl::util::default_styles::streets.url;
|
||||
const double lat = latValue ? args::get(latValue) : 0;
|
||||
const double lon = lonValue ? args::get(lonValue) : 0;
|
||||
const double zoom = zoomValue ? args::get(zoomValue) : 0;
|
||||
const double bearing = bearingValue ? args::get(bearingValue) : 0;
|
||||
const double pitch = pitchValue ? args::get(pitchValue) : 0;
|
||||
const double pixelRatio = pixelRatioValue ? args::get(pixelRatioValue) : 1;
|
||||
|
||||
const uint32_t width = widthValue ? args::get(widthValue) : 512;
|
||||
const uint32_t height = heightValue ? args::get(heightValue) : 512;
|
||||
const std::string output = outputValue ? args::get(outputValue) : "out.png";
|
||||
const std::string cache_file = cacheValue ? args::get(cacheValue) : "cache.sqlite";
|
||||
const std::string asset_root = assetsValue ? args::get(assetsValue) : ".";
|
||||
|
||||
// Try to load the token from the environment.
|
||||
const char* tokenEnv = getenv("MAPBOX_ACCESS_TOKEN");
|
||||
const std::string token = tokenValue ? args::get(tokenValue) : (tokenEnv ? tokenEnv : std::string());
|
||||
|
||||
const bool debug = debugFlag ? args::get(debugFlag) : false;
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
util::RunLoop loop;
|
||||
|
||||
HeadlessFrontend frontend({ width, height }, pixelRatio);
|
||||
Map map(frontend, MapObserver::nullObserver(),
|
||||
MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()).withPixelRatio(pixelRatio),
|
||||
ResourceOptions().withCachePath(cache_file).withAssetPath(asset_root).withAccessToken(std::string(token)));
|
||||
|
||||
if (style.find("://") == std::string::npos) {
|
||||
style = std::string("file://") + style;
|
||||
}
|
||||
|
||||
map.getStyle().loadURL(style);
|
||||
map.jumpTo(CameraOptions()
|
||||
.withCenter(LatLng { lat, lon })
|
||||
.withZoom(zoom)
|
||||
.withBearing(bearing)
|
||||
.withPitch(pitch));
|
||||
|
||||
if (debug) {
|
||||
map.setDebug(debug ? mbgl::MapDebugOptions::TileBorders | mbgl::MapDebugOptions::ParseStatus : mbgl::MapDebugOptions::NoDebug);
|
||||
}
|
||||
|
||||
try {
|
||||
std::ofstream out(output, std::ios::binary);
|
||||
out << encodePNG(frontend.render(map).image);
|
||||
out.close();
|
||||
} catch(std::exception& e) {
|
||||
std::cout << "Error: " << e.what() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user