From 318ce8616c83d99458482e7c0bd531afe2a2081c Mon Sep 17 00:00:00 2001 From: Rory Fuhrer Date: Fri, 3 Oct 2025 11:56:15 -0700 Subject: [PATCH 1/2] Fix that minzoom calcs were using round or ceil instead of floor --- modules/geo-layers/src/tileset-2d/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/geo-layers/src/tileset-2d/utils.ts b/modules/geo-layers/src/tileset-2d/utils.ts index c00e2719ac4..14dea715a4b 100644 --- a/modules/geo-layers/src/tileset-2d/utils.ts +++ b/modules/geo-layers/src/tileset-2d/utils.ts @@ -285,8 +285,8 @@ export function getTileIndices({ zoomOffset?: number; }) { let z = viewport.isGeospatial - ? Math.round(viewport.zoom + Math.log2(TILE_SIZE / tileSize)) + zoomOffset - : Math.ceil(viewport.zoom) + zoomOffset; + ? Math.floor(viewport.zoom + Math.log2(TILE_SIZE / tileSize)) + zoomOffset + : Math.floor(viewport.zoom) + zoomOffset; if (typeof minZoom === 'number' && Number.isFinite(minZoom) && z < minZoom) { if (!extent) { return []; From 079ad418fee17f8505bfaeaee6b6615f5e6d1771 Mon Sep 17 00:00:00 2001 From: Rory Fuhrer Date: Tue, 28 Oct 2025 09:13:06 -0700 Subject: [PATCH 2/2] update getTileIndices logic --- modules/geo-layers/src/tileset-2d/utils.ts | 12 +++++++++--- test/modules/geo-layers/tileset-2d/utils.spec.ts | 8 ++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/modules/geo-layers/src/tileset-2d/utils.ts b/modules/geo-layers/src/tileset-2d/utils.ts index 14dea715a4b..e188fa6333a 100644 --- a/modules/geo-layers/src/tileset-2d/utils.ts +++ b/modules/geo-layers/src/tileset-2d/utils.ts @@ -284,10 +284,16 @@ export function getTileIndices({ modelMatrixInverse?: Matrix4; zoomOffset?: number; }) { + // This round/ceil operation ensures that tiles are rendered in the same way as Google Maps, Map Libre, etc. + // eg. at viewport.zoom = 9.5, you should fetch tiles at z = 10, not z = 9. let z = viewport.isGeospatial - ? Math.floor(viewport.zoom + Math.log2(TILE_SIZE / tileSize)) + zoomOffset - : Math.floor(viewport.zoom) + zoomOffset; - if (typeof minZoom === 'number' && Number.isFinite(minZoom) && z < minZoom) { + ? Math.round(viewport.zoom + Math.log2(TILE_SIZE / tileSize) + zoomOffset) + : Math.ceil(viewport.zoom + zoomOffset); + + // This check doesn't round/ceil and doesn't use the offset. This ensures that tiles are not rendered if the + // viewport.zoom is less than minZoom. eg. at viewport.zoom = 9.5 with minZoom = 10 we should not fetch tiles + // at z = 10 until viewport.zoom is 10 or greater. + if (typeof minZoom === 'number' && Number.isFinite(minZoom) && viewport.zoom < minZoom) { if (!extent) { return []; } diff --git a/test/modules/geo-layers/tileset-2d/utils.spec.ts b/test/modules/geo-layers/tileset-2d/utils.spec.ts index b4a7ca2e1f1..6878ae37002 100644 --- a/test/modules/geo-layers/tileset-2d/utils.spec.ts +++ b/test/modules/geo-layers/tileset-2d/utils.spec.ts @@ -101,6 +101,14 @@ const TEST_CASES = [ maxZoom: undefined, output: [] }, + { + title: 'ignore round and offset on minZoom check', + viewport: new WebMercatorViewport({longitude: -90, latitude: 45, zoom: 3.5}), + zoomOffset: 1, + minZoom: 4, + maxZoom: undefined, + output: [] + }, { title: 'over zoom', viewport: new WebMercatorViewport({