diff --git a/all/modules/datasources/TileDataSource.i b/all/modules/datasources/TileDataSource.i index 7a370cc4d..57bf343b2 100644 --- a/all/modules/datasources/TileDataSource.i +++ b/all/modules/datasources/TileDataSource.i @@ -29,6 +29,7 @@ %attribute(carto::TileDataSource, int, MinZoom, getMinZoom) %attribute(carto::TileDataSource, int, MaxZoom, getMaxZoom) +%attribute(carto::TileDataSource, int, MaxOverzoomLevel, getMaxOverzoomLevel, setMaxOverzoomLevel) %attributeval(carto::TileDataSource, carto::MapBounds, DataExtent, getDataExtent) !attributestring_polymorphic(carto::TileDataSource, projections.Projection, Projection, getProjection) %ignore carto::TileDataSource::OnChangeListener; diff --git a/all/native/datasources/MBTilesTileDataSource.cpp b/all/native/datasources/MBTilesTileDataSource.cpp index 17c057dd5..519af42a6 100644 --- a/all/native/datasources/MBTilesTileDataSource.cpp +++ b/all/native/datasources/MBTilesTileDataSource.cpp @@ -126,7 +126,7 @@ namespace carto { } return *_cachedDataExtent; } - + std::shared_ptr MBTilesTileDataSource::loadTile(const MapTile& mapTile) { std::lock_guard lock(_mutex); Log::Infof("MBTilesTileDataSource::loadTile: Loading %s", mapTile.toString().c_str()); @@ -134,7 +134,13 @@ namespace carto { Log::Errorf("MBTilesTileDataSource::loadTile: Failed to load %s: Couldn't connect to the database", mapTile.toString().c_str()); return std::shared_ptr(); } - + + if (getMaxOverzoomLevel() >= 0 && mapTile.getZoom() > getMaxZoomWithOverzoom()) { + // we explicitly return an empty tile to not draw overzoom + auto tileData = std::make_shared(std::shared_ptr()); + tileData->setIsOverZoom(true); + return tileData; + } try { // Make the query and check for database error sqlite3pp::query query(*_database, "SELECT tile_data FROM tiles WHERE zoom_level=:zoom AND tile_column=:x AND tile_row=:y"); diff --git a/all/native/datasources/MBTilesTileDataSource.h b/all/native/datasources/MBTilesTileDataSource.h index c5c3beadf..a1e3e415d 100644 --- a/all/native/datasources/MBTilesTileDataSource.h +++ b/all/native/datasources/MBTilesTileDataSource.h @@ -89,7 +89,7 @@ namespace carto { virtual MapBounds getDataExtent() const; virtual std::shared_ptr loadTile(const MapTile& mapTile); - + private: static std::unique_ptr OpenDatabase(const std::string& path); diff --git a/all/native/datasources/TileDataSource.cpp b/all/native/datasources/TileDataSource.cpp index 363efa4cd..aeaf9f352 100644 --- a/all/native/datasources/TileDataSource.cpp +++ b/all/native/datasources/TileDataSource.cpp @@ -21,6 +21,28 @@ namespace carto { return _maxZoom; } + int TileDataSource::getMaxZoomWithOverzoom() const { + if (_maxOverzoomLevel >= 0) { + return getMaxZoom() + _maxOverzoomLevel; + } + return getMaxZoom(); + } + + int TileDataSource::getMaxOverzoomLevel() const { + return _maxOverzoomLevel; + } + bool TileDataSource::isMaxOverzoomLevelSet() const { + return _maxOverzoomLevel >= 0; + } + + void TileDataSource::setMaxOverzoomLevel(int overzoomLevel) { + { + std::lock_guard lock(_mutex); + _maxOverzoomLevel = overzoomLevel; + } + notifyTilesChanged(false); + } + MapBounds TileDataSource::getDataExtent() const { return _projection->getBounds(); } @@ -32,7 +54,7 @@ namespace carto { void TileDataSource::notifyTilesChanged(bool removeTiles) { std::vector > onChangeListeners; { - std::lock_guard lock(_onChangeListenersMutex); + std::lock_guard lock(_mutex); onChangeListeners = _onChangeListeners; } for (const std::shared_ptr& listener : onChangeListeners) { @@ -41,30 +63,32 @@ namespace carto { } void TileDataSource::registerOnChangeListener(const std::shared_ptr& listener) { - std::lock_guard lock(_onChangeListenersMutex); + std::lock_guard lock(_mutex); _onChangeListeners.push_back(listener); } void TileDataSource::unregisterOnChangeListener(const std::shared_ptr& listener) { - std::lock_guard lock(_onChangeListenersMutex); + std::lock_guard lock(_mutex); _onChangeListeners.erase(std::remove(_onChangeListeners.begin(), _onChangeListeners.end(), listener), _onChangeListeners.end()); } TileDataSource::TileDataSource() : _minZoom(0), _maxZoom(Const::MAX_SUPPORTED_ZOOM_LEVEL), + _maxOverzoomLevel(-1), _projection(std::make_shared()), _onChangeListeners(), - _onChangeListenersMutex() + _mutex() { } TileDataSource::TileDataSource(int minZoom, int maxZoom) : _minZoom(std::max(0, minZoom)), _maxZoom(std::min(static_cast(Const::MAX_SUPPORTED_ZOOM_LEVEL), maxZoom)), + _maxOverzoomLevel(-1), _projection(std::make_shared()), _onChangeListeners(), - _onChangeListenersMutex() + _mutex() { } diff --git a/all/native/datasources/TileDataSource.h b/all/native/datasources/TileDataSource.h index 83ad3a6ef..882b4c969 100644 --- a/all/native/datasources/TileDataSource.h +++ b/all/native/datasources/TileDataSource.h @@ -53,6 +53,30 @@ namespace carto { */ virtual int getMaxZoom() const; + + /** + * Returns the maximum zoom level supported by this data source + getMaxOverzoomLevel if >= 0. + * @return The maximum zoom level supported (exclusive). + */ + virtual int getMaxZoomWithOverzoom() const; + + /** + * Sets the maximum overzoom level for this datasource. + * If a tile for the given zoom level Z is not available, SDK will try to use tiles with zoom levels Z-1, ..., Z-MaxOverzoomLevel. + * The default is -1 (disabled). + * @param overzoomLevel The new maximum overzoom value. + */ + void setMaxOverzoomLevel(int overzoomLevel); + + /** + * Gets the current maximum overzoom level for this datasource. + * Over it the datasource will not be "drawn" + * @return The current maximum overzoom level for this datasource. + */ + int getMaxOverzoomLevel() const; + + bool isMaxOverzoomLevelSet() const; + /** * Returns the extent of the tiles in this data source. * The bounds are in coordinate system of the projection of the data source. @@ -117,11 +141,12 @@ namespace carto { std::atomic _minZoom; std::atomic _maxZoom; + std::atomic _maxOverzoomLevel; const std::shared_ptr _projection; private: std::vector > _onChangeListeners; - mutable std::mutex _onChangeListenersMutex; + mutable std::mutex _mutex; }; } diff --git a/all/native/datasources/components/TileData.cpp b/all/native/datasources/components/TileData.cpp index 8dcfef7b0..5b113767c 100644 --- a/all/native/datasources/components/TileData.cpp +++ b/all/native/datasources/components/TileData.cpp @@ -4,7 +4,7 @@ namespace carto { TileData::TileData(const std::shared_ptr& data) : - _data(data), _expirationTime(), _replaceWithParent(false), _mutex() + _data(data), _expirationTime(), _replaceWithParent(false), _overzoom(false), _mutex() { } @@ -42,6 +42,16 @@ namespace carto { _replaceWithParent = flag; } + bool TileData::isOverZoom() const { + std::lock_guard lock(_mutex); + return _overzoom; + } + + void TileData::setIsOverZoom(bool flag) { + std::lock_guard lock(_mutex); + _overzoom = flag; + } + const std::shared_ptr& TileData::getData() const { return _data; } diff --git a/all/native/datasources/components/TileData.h b/all/native/datasources/components/TileData.h index ec8d8d0fe..ed4c3d0d1 100644 --- a/all/native/datasources/components/TileData.h +++ b/all/native/datasources/components/TileData.h @@ -48,6 +48,17 @@ namespace carto { * @param flag True when the tile should be replaced with the parent, false otherwise. */ void setReplaceWithParent(bool flag); + + /** + * Returns true if the tile data source marked this as over zoom. + * @return True if the tile should not be drawn. False otherwise. + */ + bool isOverZoom() const; + /** + * Set the parent overzoom flag. + * @return True if the tile should not be drawn. False otherwise. + */ + void setIsOverZoom(bool flag); /** * Returns tile data as binary data. @@ -59,6 +70,7 @@ namespace carto { const std::shared_ptr _data; std::shared_ptr _expirationTime; bool _replaceWithParent; + bool _overzoom; mutable std::mutex _mutex; }; diff --git a/all/native/layers/RasterTileLayer.cpp b/all/native/layers/RasterTileLayer.cpp index bf58980f2..e0742c7a2 100644 --- a/all/native/layers/RasterTileLayer.cpp +++ b/all/native/layers/RasterTileLayer.cpp @@ -434,6 +434,11 @@ namespace carto { if (tileData->isReplaceWithParent()) { continue; } + if(tileData->isOverZoom()) { + // we need to invalidate cache tiles to make sure we dont draw over + layer->_preloadingCache.remove(_tileId); + layer->_visibleCache.remove(_tileId); + } if (isCanceled()) { break; diff --git a/all/native/layers/VectorTileLayer.cpp b/all/native/layers/VectorTileLayer.cpp index d4e73c534..0ef020b7d 100644 --- a/all/native/layers/VectorTileLayer.cpp +++ b/all/native/layers/VectorTileLayer.cpp @@ -608,6 +608,11 @@ namespace carto { if (tileData->isReplaceWithParent()) { continue; } + if(tileData->isOverZoom()) { + // we need to invalidate cache tiles to make sure we dont draw over + layer->_preloadingCache.remove(_tileId); + layer->_visibleCache.remove(_tileId); + } if (isCanceled()) { break;