[general] moving ios and android project under ./platform folder

This commit is contained in:
Petr Pokorny
2020-12-20 12:38:56 +01:00
parent 8e759a51e4
commit 41f0be34e7
9877 changed files with 141 additions and 2889 deletions

42
bin/CMakeLists.txt Normal file
View 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
View 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
View 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
View 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
View 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;
}