diff --git a/lib/src/layer/tile_layer/tile_image_view.dart b/lib/src/layer/tile_layer/tile_image_view.dart index 1537e6a29..5a67e07cd 100644 --- a/lib/src/layer/tile_layer/tile_image_view.dart +++ b/lib/src/layer/tile_layer/tile_image_view.dart @@ -183,7 +183,7 @@ final class TileImageView { } if (z + 1 < maxZoom) { - _retainChildren(retain, i, j, z + 1, maxZoom); + _retainChildren(retain, 2 * x + i, 2 * y + j, z + 1, maxZoom); } } } diff --git a/test/layer/tile_layer/tile_image_view_test.dart b/test/layer/tile_layer/tile_image_view_test.dart index 99801dfd6..0261ccc38 100644 --- a/test/layer/tile_layer/tile_image_view_test.dart +++ b/test/layer/tile_layer/tile_image_view_test.dart @@ -138,6 +138,37 @@ void main() { } }); + group('renderTiles', () { + test('%.retainChildren uses correct coordinates for z+2 fallback', () { + // This test verifies that _retainChildren correctly calculates + // descendant coordinates when recursing to z+2 level. + // Using large coordinates (100, 200) to catch the bug where + // i,j (0-1) was passed instead of 2*x+i, 2*y+j. + const baseZoom = 10; + final tileImages = tileImagesMappingFrom([ + // z=10 tile not ready + MockTileImage(100, 200, baseZoom, + loadFinished: false, readyToDisplay: false), + // z=11 tiles don't exist + // z=12 tile exists and is ready (this is what we want to fall back to) + MockTileImage(400, 800, baseZoom + 2), + ]); + + final tileImageView = TileImageView( + tileImages: tileImages, + positionCoordinates: Set.from(tileImages.keys), + visibleRange: discreteTileRange(100, 200, 100, 200, zoom: baseZoom), + keepRange: discreteTileRange(100, 200, 100, 200, zoom: baseZoom), + ); + + final renderTiles = tileImageView.renderTiles.toList(); + expect( + renderTiles, + contains(const TileCoordinates(400, 800, baseZoom + 2)), + ); + }); + }); + test('errorTilesNotVisible', () { const zoom = 10; final tileImages = tileImagesMappingFrom([