From fae099933b23a36176dcc8c4a91c37816fa9b7fe Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Fri, 23 Mar 2018 15:44:21 +0200 Subject: [PATCH] [core] offline region definition - add support for arbitrary geometries --- include/mbgl/storage/offline.hpp | 34 ++++- platform/default/mbgl/storage/offline.cpp | 133 ++++++++++-------- .../default/mbgl/storage/offline_download.cpp | 85 +++++++++-- test/storage/offline.test.cpp | 70 +++------ test/storage/offline_database.test.cpp | 96 ++++++++----- test/storage/offline_download.test.cpp | 2 +- 6 files changed, 255 insertions(+), 165 deletions(-) diff --git a/include/mbgl/storage/offline.hpp b/include/mbgl/storage/offline.hpp index 62353446f..b4e40cb5f 100644 --- a/include/mbgl/storage/offline.hpp +++ b/include/mbgl/storage/offline.hpp @@ -1,8 +1,10 @@ #pragma once #include +#include #include #include +#include #include #include @@ -30,22 +32,40 @@ public: OfflineTilePyramidRegionDefinition(std::string, LatLngBounds, double, double, float); /* Private */ - std::vector tileCover(style::SourceType, uint16_t tileSize, const Range& zoomRange) const; - uint64_t tileCount(style::SourceType, uint16_t tileSize, const Range& zoomRange) const; const std::string styleURL; const LatLngBounds bounds; const double minZoom; const double maxZoom; const float pixelRatio; -private: - Range coveringZoomRange(style::SourceType, uint16_t tileSize, const Range& zoomRange) const; }; /* - * For the present, a tile pyramid is the only type of offline region. In the future, - * other definition types will be available and this will be a variant type. + * An offline region defined by a style URL, geometry, zoom range, and + * device pixel ratio. + * + * Both minZoom and maxZoom must be ≥ 0, and maxZoom must be ≥ minZoom. + * + * maxZoom may be ∞, in which case for each tile source, the region will include + * tiles from minZoom up to the maximum zoom level provided by that source. + * + * pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0. */ -using OfflineRegionDefinition = OfflineTilePyramidRegionDefinition; +class OfflineGeometryRegionDefinition { +public: + OfflineGeometryRegionDefinition(std::string styleURL, Geometry, double minZoom, double maxZoom, float pixelRatio); + + /* Private */ + const std::string styleURL; + const Geometry geometry; + const double minZoom; + const double maxZoom; + const float pixelRatio; +}; + +/* + * The offline region definition types supported + */ +using OfflineRegionDefinition = variant; /* * The encoded format is private. diff --git a/platform/default/mbgl/storage/offline.cpp b/platform/default/mbgl/storage/offline.cpp index 598a0b182..e1ec0acb3 100644 --- a/platform/default/mbgl/storage/offline.cpp +++ b/platform/default/mbgl/storage/offline.cpp @@ -1,8 +1,10 @@ #include -#include #include #include +#include +#include + #include #include #include @@ -11,6 +13,8 @@ namespace mbgl { +// OfflineTilePyramidRegionDefinition + OfflineTilePyramidRegionDefinition::OfflineTilePyramidRegionDefinition( std::string styleURL_, LatLngBounds bounds_, double minZoom_, double maxZoom_, float pixelRatio_) : styleURL(std::move(styleURL_)), @@ -24,87 +28,100 @@ OfflineTilePyramidRegionDefinition::OfflineTilePyramidRegionDefinition( } } -std::vector OfflineTilePyramidRegionDefinition::tileCover(style::SourceType type, uint16_t tileSize, const Range& zoomRange) const { - const Range clampedZoomRange = coveringZoomRange(type, tileSize, zoomRange); - std::vector result; +// OfflineGeometryRegionDefinition - for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) { - for (const auto& tile : util::tileCover(bounds, z)) { - result.emplace_back(tile.canonical); - } +OfflineGeometryRegionDefinition::OfflineGeometryRegionDefinition(std::string styleURL_, Geometry geometry_, double minZoom_, double maxZoom_, float pixelRatio_) + : styleURL(styleURL_) + , geometry(std::move(geometry_)) + , 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"); } - - return result; -} - -uint64_t OfflineTilePyramidRegionDefinition::tileCount(style::SourceType type, uint16_t tileSize, const Range& zoomRange) const { - - const Range clampedZoomRange = coveringZoomRange(type, tileSize, zoomRange); - unsigned long result = 0;; - for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) { - result += util::tileCount(bounds, z); - } - - return result; -} - -Range OfflineTilePyramidRegionDefinition::coveringZoomRange(style::SourceType type, uint16_t tileSize, const Range& zoomRange) const { - double minZ = std::max(util::coveringZoomLevel(minZoom, type, tileSize), zoomRange.min); - double maxZ = std::min(util::coveringZoomLevel(maxZoom, type, tileSize), zoomRange.max); - - assert(minZ >= 0); - assert(maxZ >= 0); - assert(minZ < std::numeric_limits::max()); - assert(maxZ < std::numeric_limits::max()); - return { static_cast(minZ), static_cast(maxZ) }; } OfflineRegionDefinition decodeOfflineRegionDefinition(const std::string& region) { rapidjson::GenericDocument, 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()) { + // validation + + auto hasValidBounds = [&] { + return 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(); + }; + + auto hasValidGeometry = [&] { + return doc.HasMember("geometry") && doc["geometry"].IsObject(); + }; + + if (doc.HasParseError() + || !doc.HasMember("style_url") || !doc["style_url"].IsString() + || !(hasValidBounds() || hasValidGeometry()) + || !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"); } + // Common properties + 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(); + + if (doc.HasMember("bounds")) { + return OfflineTilePyramidRegionDefinition{ + styleURL, + LatLngBounds::hull( + LatLng(doc["bounds"][0].GetDouble(), doc["bounds"][1].GetDouble()), + LatLng(doc["bounds"][2].GetDouble(), doc["bounds"][3].GetDouble())), + minZoom, maxZoom, pixelRatio }; + } else { + return OfflineGeometryRegionDefinition{ + styleURL, + mapbox::geojson::convert>(doc["geometry"].GetObject()), + minZoom, maxZoom, pixelRatio }; + }; - return { styleURL, bounds, minZoom, maxZoom, pixelRatio }; } std::string encodeOfflineRegionDefinition(const OfflineRegionDefinition& region) { rapidjson::GenericDocument, rapidjson::CrtAllocator> doc; doc.SetObject(); - doc.AddMember("style_url", rapidjson::StringRef(region.styleURL.data(), region.styleURL.length()), doc.GetAllocator()); + // Encode common properties + region.match([&](auto& _region) { + doc.AddMember("style_url", rapidjson::StringRef(_region.styleURL.data(), _region.styleURL.length()), doc.GetAllocator()); + doc.AddMember("min_zoom", _region.minZoom, doc.GetAllocator()); + if (std::isfinite(_region.maxZoom)) { + doc.AddMember("max_zoom", _region.maxZoom, doc.GetAllocator()); + } - rapidjson::GenericValue, 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("pixel_ratio", _region.pixelRatio, doc.GetAllocator()); + }); - doc.AddMember("min_zoom", region.minZoom, doc.GetAllocator()); - if (std::isfinite(region.maxZoom)) { - doc.AddMember("max_zoom", region.maxZoom, doc.GetAllocator()); - } + // Encode specific properties + region.match( + [&] (const OfflineTilePyramidRegionDefinition& _region) { + rapidjson::GenericValue, 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("pixel_ratio", region.pixelRatio, doc.GetAllocator()); + }, + [&] (const OfflineGeometryRegionDefinition& _region) { + doc.AddMember("geometry", mapbox::geojson::convert(_region.geometry, doc.GetAllocator()), doc.GetAllocator()); + + } + ); rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); @@ -113,6 +130,9 @@ std::string encodeOfflineRegionDefinition(const OfflineRegionDefinition& region) return buffer.GetString(); } + +// OfflineRegion + OfflineRegion::OfflineRegion(int64_t id_, OfflineRegionDefinition definition_, OfflineRegionMetadata metadata_) @@ -135,5 +155,4 @@ const OfflineRegionMetadata& OfflineRegion::getMetadata() const { int64_t OfflineRegion::getID() const { return id; } - } // namespace mbgl diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp index 179d2d5f5..118f3aad8 100644 --- a/platform/default/mbgl/storage/offline_download.cpp +++ b/platform/default/mbgl/storage/offline_download.cpp @@ -24,6 +24,63 @@ namespace mbgl { using namespace style; +// Generic functions + +template +Range coveringZoomRange(const RegionDefinition& definition, + style::SourceType type, uint16_t tileSize, const Range& zoomRange) { + double minZ = std::max(util::coveringZoomLevel(definition.minZoom, type, tileSize), zoomRange.min); + double maxZ = std::min(util::coveringZoomLevel(definition.maxZoom, type, tileSize), zoomRange.max); + + assert(minZ >= 0); + assert(maxZ >= 0); + assert(minZ < std::numeric_limits::max()); + assert(maxZ < std::numeric_limits::max()); + return { static_cast(minZ), static_cast(maxZ) }; +} + +template +void tileCover(const Geometry& geometry, uint8_t z, Fn&& fn) { + util::TileCover cover(geometry, z); + while (cover.hasNext()) { + fn(cover.next()->canonical); + } +} + + +template +void tileCover(const OfflineRegionDefinition& definition, style::SourceType type, + uint16_t tileSize, const Range& zoomRange, Fn&& fn) { + const Range clampedZoomRange = + definition.match([&](auto& reg) { return coveringZoomRange(reg, type, tileSize, zoomRange); }); + + for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) { + definition.match( + [&](const OfflineTilePyramidRegionDefinition& reg){ tileCover(reg.bounds, z, fn); }, + [&](const OfflineGeometryRegionDefinition& reg){ tileCover(reg.geometry, z, fn); } + ); + } +} + +uint64_t tileCount(const OfflineRegionDefinition& definition, style::SourceType type, + uint16_t tileSize, const Range& zoomRange) { + + const Range clampedZoomRange = + definition.match([&](auto& reg) { return coveringZoomRange(reg, type, tileSize, zoomRange); }); + + unsigned long result = 0;; + for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) { + result += definition.match( + [&](const OfflineTilePyramidRegionDefinition& reg){ return util::tileCount(reg.bounds, z); }, + [&](const OfflineGeometryRegionDefinition& reg){ return util::tileCount(reg.geometry, z); } + ); + } + + return result; +} + +// OfflineDownload + OfflineDownload::OfflineDownload(int64_t id_, OfflineRegionDefinition&& definition_, OfflineDatabase& offlineDatabase_, @@ -70,7 +127,8 @@ OfflineRegionStatus OfflineDownload::getStatus() const { } result->requiredResourceCount++; - optional styleResponse = offlineDatabase.get(Resource::style(definition.styleURL)); + optional styleResponse = + offlineDatabase.get(Resource::style(definition.match([](auto& reg){ return reg.styleURL; }))); if (!styleResponse) { return *result; } @@ -86,7 +144,7 @@ OfflineRegionStatus OfflineDownload::getStatus() const { auto handleTiledSource = [&] (const variant& urlOrTileset, const uint16_t tileSize) { if (urlOrTileset.is()) { result->requiredResourceCount += - definition.tileCount(type, tileSize, urlOrTileset.get().zoomRange); + tileCount(definition, type, tileSize, urlOrTileset.get().zoomRange); } else { result->requiredResourceCount += 1; const auto& url = urlOrTileset.get(); @@ -96,7 +154,7 @@ OfflineRegionStatus OfflineDownload::getStatus() const { optional tileset = style::conversion::convertJSON(*sourceResponse->data, error); if (tileset) { result->requiredResourceCount += - definition.tileCount(type, tileSize, (*tileset).zoomRange); + tileCount(definition, type, tileSize, (*tileset).zoomRange); } } else { result->requiredResourceCountIsPrecise = false; @@ -116,7 +174,7 @@ OfflineRegionStatus OfflineDownload::getStatus() const { handleTiledSource(rasterSource.getURLOrTileset(), rasterSource.getTileSize()); break; } - + case SourceType::RasterDEM: { const auto& rasterDEMSource = *source->as(); handleTiledSource(rasterDEMSource.getURLOrTileset(), rasterDEMSource.getTileSize()); @@ -161,7 +219,8 @@ void OfflineDownload::activateDownload() { status = OfflineRegionStatus(); status.downloadState = OfflineRegionDownloadState::Active; status.requiredResourceCount++; - ensureResource(Resource::style(definition.styleURL), [&](Response styleResponse) { + ensureResource(Resource::style(definition.match([](auto& reg){ return reg.styleURL; })), + [&](Response styleResponse) { status.requiredResourceCountIsPrecise = true; style::Parser parser; @@ -207,7 +266,7 @@ void OfflineDownload::activateDownload() { handleTiledSource(rasterSource.getURLOrTileset(), rasterSource.getTileSize()); break; } - + case SourceType::RasterDEM: { const auto& rasterDEMSource = *source->as(); handleTiledSource(rasterDEMSource.getURLOrTileset(), rasterDEMSource.getTileSize()); @@ -247,8 +306,9 @@ void OfflineDownload::activateDownload() { } if (!parser.spriteURL.empty()) { - queueResource(Resource::spriteImage(parser.spriteURL, definition.pixelRatio)); - queueResource(Resource::spriteJSON(parser.spriteURL, definition.pixelRatio)); + auto pixelRatio = definition.match([](auto& reg){ return reg.pixelRatio; }); + queueResource(Resource::spriteImage(parser.spriteURL, pixelRatio)); + queueResource(Resource::spriteJSON(parser.spriteURL, pixelRatio)); } continueDownload(); @@ -296,11 +356,12 @@ void OfflineDownload::queueResource(Resource resource) { } void OfflineDownload::queueTiles(SourceType type, uint16_t tileSize, const Tileset& tileset) { - for (const auto& tile : definition.tileCover(type, tileSize, tileset.zoomRange)) { + tileCover(definition, type, tileSize, tileset.zoomRange, [&](const auto& tile) { status.requiredResourceCount++; - resourcesRemaining.push_back( - Resource::tile(tileset.tiles[0], definition.pixelRatio, tile.x, tile.y, tile.z, tileset.scheme)); - } + resourcesRemaining.push_back(Resource::tile( + tileset.tiles[0], definition.match([](auto& def) { return def.pixelRatio; }), tile.x, + tile.y, tile.z, tileset.scheme)); + }); } void OfflineDownload::ensureResource(const Resource& resource, diff --git a/test/storage/offline.test.cpp b/test/storage/offline.test.cpp index 59aebebab..90f957032 100644 --- a/test/storage/offline.test.cpp +++ b/test/storage/offline.test.cpp @@ -6,58 +6,30 @@ using namespace mbgl; using SourceType = mbgl::style::SourceType; -static const LatLngBounds sanFrancisco = - LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 }); -static const LatLngBounds sanFranciscoWrapped = - LatLngBounds::hull({ 37.6609, 238.5744 }, { 37.8271, 238.3204 }); +TEST(OfflineTilePyramidRegionDefinition, EncodeDecode) { + OfflineTilePyramidRegionDefinition region("mapbox://style", LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 }), 0, 20, 1.0); -TEST(OfflineTilePyramidRegionDefinition, TileCoverEmpty) { - OfflineTilePyramidRegionDefinition region("", LatLngBounds::empty(), 0, 20, 1.0); - - EXPECT_EQ((std::vector{}), region.tileCover(SourceType::Vector, 512, { 0, 22 })); + auto encoded = encodeOfflineRegionDefinition(region); + auto decoded = decodeOfflineRegionDefinition(encoded).get(); + + EXPECT_EQ(decoded.styleURL, region.styleURL); + EXPECT_EQ(decoded.minZoom, region.minZoom); + EXPECT_EQ(decoded.maxZoom, region.maxZoom); + EXPECT_EQ(decoded.pixelRatio, region.pixelRatio); + EXPECT_EQ(decoded.bounds.southwest(), region.bounds.southwest()); + EXPECT_EQ(decoded.bounds.northeast(), region.bounds.northeast()); } -TEST(OfflineTilePyramidRegionDefinition, TileCoverZoomIntersection) { - OfflineTilePyramidRegionDefinition region("", sanFrancisco, 2, 2, 1.0); +TEST(OfflineGeometryRegionDefinition, EncodeDecode) { + OfflineGeometryRegionDefinition region("mapbox://style", Point(-122.5744, 37.6609), 0, 2, 1.0); - EXPECT_EQ((std::vector{ { 2, 0, 1 } }), - region.tileCover(SourceType::Vector, 512, { 0, 22 })); - - EXPECT_EQ((std::vector{}), region.tileCover(SourceType::Vector, 512, { 3, 22 })); -} - -TEST(OfflineTilePyramidRegionDefinition, TileCoverTileSize) { - OfflineTilePyramidRegionDefinition region("", LatLngBounds::world(), 0, 0, 1.0); - - EXPECT_EQ((std::vector{ { 0, 0, 0 } }), - region.tileCover(SourceType::Vector, 512, { 0, 22 })); - - EXPECT_EQ((std::vector{ { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 } }), - region.tileCover(SourceType::Vector, 256, { 0, 22 })); -} - -TEST(OfflineTilePyramidRegionDefinition, TileCoverZoomRounding) { - OfflineTilePyramidRegionDefinition region("", sanFrancisco, 0.6, 0.7, 1.0); - - EXPECT_EQ((std::vector{ { 0, 0, 0 } }), - region.tileCover(SourceType::Vector, 512, { 0, 22 })); - - EXPECT_EQ((std::vector{ { 1, 0, 0 } }), - region.tileCover(SourceType::Raster, 512, { 0, 22 })); -} - -TEST(OfflineTilePyramidRegionDefinition, TileCoverWrapped) { - OfflineTilePyramidRegionDefinition region("", sanFranciscoWrapped, 0, 0, 1.0); - - EXPECT_EQ((std::vector{ { 0, 0, 0 } }), - region.tileCover(SourceType::Vector, 512, { 0, 22 })); -} - -TEST(OfflineTilePyramidRegionDefinition, TileCount) { - OfflineTilePyramidRegionDefinition region("", sanFranciscoWrapped, 0, 22, 1.0); - - //These numbers match the count from tileCover().size(). - EXPECT_EQ(38424u, region.tileCount(SourceType::Vector, 512, { 10, 18 })); - EXPECT_EQ(9675240u, region.tileCount(SourceType::Vector, 512, { 3, 22 })); + auto encoded = encodeOfflineRegionDefinition(region); + auto decoded = decodeOfflineRegionDefinition(encoded).get(); + + EXPECT_EQ(decoded.styleURL, region.styleURL); + EXPECT_EQ(decoded.minZoom, region.minZoom); + EXPECT_EQ(decoded.maxZoom, region.maxZoom); + EXPECT_EQ(decoded.pixelRatio, region.pixelRatio); + EXPECT_EQ(decoded.geometry, region.geometry); } diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp index 346cd6da8..2ed72e0d8 100644 --- a/test/storage/offline_database.test.cpp +++ b/test/storage/offline_database.test.cpp @@ -411,25 +411,31 @@ TEST(OfflineDatabase, PutTileNotFound) { TEST(OfflineDatabase, CreateRegion) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; auto region = db.createRegion(definition, metadata); ASSERT_TRUE(region); - EXPECT_EQ(definition.styleURL, region->getDefinition().styleURL); - EXPECT_EQ(definition.bounds, region->getDefinition().bounds); - EXPECT_EQ(definition.minZoom, region->getDefinition().minZoom); - EXPECT_EQ(definition.maxZoom, region->getDefinition().maxZoom); - EXPECT_EQ(definition.pixelRatio, region->getDefinition().pixelRatio); - EXPECT_EQ(metadata, region->getMetadata()); - EXPECT_EQ(0u, log.uncheckedCount()); + + region->getDefinition().match( + [&](OfflineTilePyramidRegionDefinition& def) { + EXPECT_EQ(definition.styleURL, def.styleURL); + EXPECT_EQ(definition.bounds, def.bounds); + EXPECT_EQ(definition.minZoom, def.minZoom); + EXPECT_EQ(definition.maxZoom, def.maxZoom); + EXPECT_EQ(definition.pixelRatio, def.pixelRatio); + }, [](auto&) { + EXPECT_FALSE(false); + } + ); + EXPECT_EQ(metadata, region->getMetadata()); } TEST(OfflineDatabase, UpdateMetadata) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; auto region = db.createRegion(definition, metadata); ASSERT_TRUE(region); @@ -445,7 +451,7 @@ TEST(OfflineDatabase, UpdateMetadata) { TEST(OfflineDatabase, ListRegions) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; auto region = db.createRegion(definition, metadata); @@ -453,12 +459,19 @@ TEST(OfflineDatabase, ListRegions) { auto regions = db.listRegions().value(); ASSERT_EQ(1u, regions.size()); + EXPECT_EQ(region->getID(), regions.at(0).getID()); - EXPECT_EQ(definition.styleURL, regions.at(0).getDefinition().styleURL); - EXPECT_EQ(definition.bounds, regions.at(0).getDefinition().bounds); - EXPECT_EQ(definition.minZoom, regions.at(0).getDefinition().minZoom); - EXPECT_EQ(definition.maxZoom, regions.at(0).getDefinition().maxZoom); - EXPECT_EQ(definition.pixelRatio, regions.at(0).getDefinition().pixelRatio); + regions.at(0).getDefinition().match( + [&](OfflineTilePyramidRegionDefinition& def) { + EXPECT_EQ(definition.styleURL, def.styleURL); + EXPECT_EQ(definition.bounds, def.bounds); + EXPECT_EQ(definition.minZoom, def.minZoom); + EXPECT_EQ(definition.maxZoom, def.maxZoom); + EXPECT_EQ(definition.pixelRatio, def.pixelRatio); + }, + [&](auto&) { + EXPECT_FALSE(false); + }); EXPECT_EQ(metadata, regions.at(0).getMetadata()); EXPECT_EQ(0u, log.uncheckedCount()); @@ -467,27 +480,30 @@ TEST(OfflineDatabase, ListRegions) { TEST(OfflineDatabase, GetRegionDefinition) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; - auto region = db.createRegion(definition, metadata); - ASSERT_TRUE(region); - auto result = db.getRegionDefinition(region->getID()); - ASSERT_TRUE(result); - - EXPECT_EQ(definition.styleURL, result->styleURL); - EXPECT_EQ(definition.bounds, result->bounds); - EXPECT_EQ(definition.minZoom, result->minZoom); - EXPECT_EQ(definition.maxZoom, result->maxZoom); - EXPECT_EQ(definition.pixelRatio, result->pixelRatio); - EXPECT_EQ(0u, log.uncheckedCount()); + + auto region = db.createRegion(definition, metadata); + db.getRegionDefinition(region->getID())->match( + [&](OfflineTilePyramidRegionDefinition& result) { + EXPECT_EQ(definition.styleURL, result.styleURL); + EXPECT_EQ(definition.bounds, result.bounds); + EXPECT_EQ(definition.minZoom, result.minZoom); + EXPECT_EQ(definition.maxZoom, result.maxZoom); + EXPECT_EQ(definition.pixelRatio, result.pixelRatio); + }, + [&](auto&) { + EXPECT_FALSE(false); + } + ); } TEST(OfflineDatabase, DeleteRegion) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; auto region = db.createRegion(definition, metadata); ASSERT_TRUE(region); @@ -509,15 +525,17 @@ TEST(OfflineDatabase, DeleteRegion) { TEST(OfflineDatabase, CreateRegionInfiniteMaxZoom) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; OfflineRegionMetadata metadata; auto region = db.createRegion(definition, metadata); ASSERT_TRUE(region); - EXPECT_EQ(0, region->getDefinition().minZoom); - EXPECT_EQ(INFINITY, region->getDefinition().maxZoom); - EXPECT_EQ(0u, log.uncheckedCount()); + + region->getDefinition().match([&](auto& def) { + EXPECT_EQ(0, def.minZoom); + EXPECT_EQ(INFINITY, def.maxZoom); + }); } TEST(OfflineDatabase, TEST_REQUIRES_WRITE(ConcurrentUse)) { @@ -600,7 +618,7 @@ TEST(OfflineDatabase, PutEvictsLeastRecentlyUsedResources) { TEST(OfflineDatabase, PutRegionResourceDoesNotEvict) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); - OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; auto region = db.createRegion(definition, OfflineRegionMetadata()); ASSERT_TRUE(region); @@ -637,7 +655,7 @@ TEST(OfflineDatabase, PutFailsWhenEvictionInsuffices) { TEST(OfflineDatabase, GetRegionCompletedStatus) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata; auto region = db.createRegion(definition, metadata); ASSERT_TRUE(region); @@ -676,7 +694,7 @@ TEST(OfflineDatabase, GetRegionCompletedStatus) { TEST(OfflineDatabase, HasRegionResource) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); - OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; auto region = db.createRegion(definition, OfflineRegionMetadata()); ASSERT_TRUE(region); @@ -700,7 +718,7 @@ TEST(OfflineDatabase, HasRegionResource) { TEST(OfflineDatabase, HasRegionResourceTile) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); - OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; auto region = db.createRegion(definition, OfflineRegionMetadata()); ASSERT_TRUE(region); @@ -734,7 +752,7 @@ TEST(OfflineDatabase, HasRegionResourceTile) { TEST(OfflineDatabase, OfflineMapboxTileCount) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata; auto region1 = db.createRegion(definition, metadata); @@ -795,7 +813,7 @@ TEST(OfflineDatabase, OfflineMapboxTileCount) { TEST(OfflineDatabase, BatchInsertion) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); - OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; auto region = db.createRegion(definition, OfflineRegionMetadata()); ASSERT_TRUE(region); @@ -821,7 +839,7 @@ TEST(OfflineDatabase, BatchInsertionMapboxTileCountExceeded) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); db.setOfflineMapboxTileCountLimit(1); - OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; auto region = db.createRegion(definition, OfflineRegionMetadata()); ASSERT_TRUE(region); diff --git a/test/storage/offline_download.test.cpp b/test/storage/offline_download.test.cpp index 93b4dd623..492e68e86 100644 --- a/test/storage/offline_download.test.cpp +++ b/test/storage/offline_download.test.cpp @@ -66,7 +66,7 @@ public: std::size_t size = 0; auto createRegion() { - OfflineRegionDefinition definition { "", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 1.0 }; OfflineRegionMetadata metadata; return db.createRegion(definition, metadata); }