From 987c7591676527cc4285734f1634ad07bed737c0 Mon Sep 17 00:00:00 2001 From: ilan-gold Date: Tue, 8 Jun 2021 10:23:32 -0400 Subject: [PATCH 1/5] Add back `tileSize` to `utils` functions. --- .../geo-layers/src/tile-layer/tileset-2d.js | 3 +- modules/geo-layers/src/tile-layer/utils.js | 31 ++++++++++++------- .../geo-layers/tile-layer/utils.spec.js | 14 ++++++++- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/modules/geo-layers/src/tile-layer/tileset-2d.js b/modules/geo-layers/src/tile-layer/tileset-2d.js index 37e03808b19..83d4fd34245 100644 --- a/modules/geo-layers/src/tile-layer/tileset-2d.js +++ b/modules/geo-layers/src/tile-layer/tileset-2d.js @@ -174,7 +174,8 @@ export default class Tileset2D { // Add custom metadata to tiles getTileMetadata({x, y, z}) { - return {bbox: tileToBoundingBox(this._viewport, x, y, z)}; + const {tileSize} = this.opts; + return {bbox: tileToBoundingBox(this._viewport, x, y, z, tileSize)}; } // Returns {x, y, z} of the parent tile diff --git a/modules/geo-layers/src/tile-layer/utils.js b/modules/geo-layers/src/tile-layer/utils.js index e145921c2a5..a100fb3abdf 100644 --- a/modules/geo-layers/src/tile-layer/utils.js +++ b/modules/geo-layers/src/tile-layer/utils.js @@ -117,8 +117,8 @@ function getIndexingCoords(bbox, scale, modelMatrixInverse) { return bbox.map(i => (i * scale) / TILE_SIZE); } -function getScale(z) { - return Math.pow(2, z); +function getScale(z, tileSize = TILE_SIZE) { + return (Math.pow(2, z) * TILE_SIZE) / tileSize; } // https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Lon..2Flat._to_tile_numbers_2 @@ -130,25 +130,24 @@ export function osmTile2lngLat(x, y, z) { return [lng, lat]; } -function tile2XY(x, y, z) { - const scale = getScale(z); +function tile2XY(x, y, z, tileSize) { + const scale = getScale(z, tileSize); return [(x / scale) * TILE_SIZE, (y / scale) * TILE_SIZE]; } - -export function tileToBoundingBox(viewport, x, y, z) { +export function tileToBoundingBox(viewport, x, y, z, tileSize = TILE_SIZE) { if (viewport.isGeospatial) { const [west, north] = osmTile2lngLat(x, y, z); const [east, south] = osmTile2lngLat(x + 1, y + 1, z); return {west, north, east, south}; } - const [left, top] = tile2XY(x, y, z); - const [right, bottom] = tile2XY(x + 1, y + 1, z); + const [left, top] = tile2XY(x, y, z, tileSize); + const [right, bottom] = tile2XY(x + 1, y + 1, z, tileSize); return {left, top, right, bottom}; } -function getIdentityTileIndices(viewport, z, extent, modelMatrixInverse) { +function getIdentityTileIndices(viewport, z, tileSize, extent, modelMatrixInverse) { const bbox = getBoundingBox(viewport, null, extent); - const scale = getScale(z); + const scale = getScale(z, tileSize); const [minX, minY, maxX, maxY] = getIndexingCoords(bbox, scale, modelMatrixInverse); const indices = []; @@ -180,7 +179,9 @@ export function getTileIndices({ modelMatrix, modelMatrixInverse }) { - let z = Math.round(viewport.zoom + Math.log2(TILE_SIZE / tileSize)); + let z = viewport.isGeospatial + ? Math.round(viewport.zoom + Math.log2(TILE_SIZE / tileSize)) + : Math.ceil(viewport.zoom); if (Number.isFinite(minZoom) && z < minZoom) { if (!extent) { return []; @@ -196,7 +197,13 @@ export function getTileIndices({ } return viewport.isGeospatial ? getOSMTileIndices(viewport, z, zRange, extent || DEFAULT_EXTENT) - : getIdentityTileIndices(viewport, z, transformedExtent || DEFAULT_EXTENT, modelMatrixInverse); + : getIdentityTileIndices( + viewport, + z, + tileSize, + transformedExtent || DEFAULT_EXTENT, + modelMatrixInverse + ); } /** diff --git a/test/modules/geo-layers/tile-layer/utils.spec.js b/test/modules/geo-layers/tile-layer/utils.spec.js index f06fc1064c5..4d7e4cb3452 100644 --- a/test/modules/geo-layers/tile-layer/utils.spec.js +++ b/test/modules/geo-layers/tile-layer/utils.spec.js @@ -142,7 +142,7 @@ const TEST_CASES = [ } }), tileSize: 256, - output: ['1,2,4', '1,3,4', '2,2,4', '2,3,4', '3,2,4', '3,3,4', '4,2,4', '4,3,4'] + output: ['1,2,3', '1,3,3', '2,2,3', '2,3,3', '3,2,3', '3,3,3', '4,2,3', '4,3,3'] }, { title: 'non-geospatial modelMatrix identity', @@ -396,6 +396,12 @@ test('tileToBoundingBox#Infovis', t => { '0,0,1 Should match the results.' ); + t.deepEqual( + tileToBoundingBox(viewport, 0, 0, 0, 256), + {left: 0, top: 0, right: 256, bottom: 256}, + '0,0,0 with custom tileSize Should match the results.' + ); + t.deepEqual( tileToBoundingBox(viewport, 4, -1, 2), {left: 512, top: -128, right: 640, bottom: 0}, @@ -408,6 +414,12 @@ test('tileToBoundingBox#Infovis', t => { '4,-1,3 Should match the results.' ); + t.deepEqual( + tileToBoundingBox(viewport, 4, -1, 2, 256), + {left: 256, top: -64, right: 320, bottom: 0}, + '4,-1,2 with custom tileSize Should match the results.' + ); + t.end(); }); From befd681b84cc5cbf1c522724ffb98fc280db651c Mon Sep 17 00:00:00 2001 From: ilan-gold Date: Mon, 21 Jun 2021 11:14:24 -0400 Subject: [PATCH 2/5] Add `tileOffset` prop for info-vis --- docs/api-reference/geo-layers/tile-layer.md | 11 +++++++++-- modules/geo-layers/src/tile-layer/tile-layer.js | 9 ++++++--- modules/geo-layers/src/tile-layer/tileset-2d.js | 5 +++-- modules/geo-layers/src/tile-layer/utils.js | 5 +++-- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/docs/api-reference/geo-layers/tile-layer.md b/docs/api-reference/geo-layers/tile-layer.md index 44de0077a03..270ee2d1090 100644 --- a/docs/api-reference/geo-layers/tile-layer.md +++ b/docs/api-reference/geo-layers/tile-layer.md @@ -82,7 +82,7 @@ At each integer zoom level (`z`), the XY plane in the view space is divided into When the `TileLayer` is used with a geospatial view such as the [MapView](/docs/api-reference/core/map-view.md), x, y, and z are determined from [the OSM tile index](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames). -When the `TileLayer` is used used with a non-geospatial view such as the [OrthographicView](/docs/api-reference/core/orthographic-view.md) or the [OrbitView](/docs/api-reference/core/orbit-view.md), `x` and `y` increment from the world origin, and each tile's width and height match that defined by the `tileSize` prop. For example, the tile `x: 0, y: 0` occupies the square between `[0, 0]` and `[tileSize, tileSize]`. +When the `TileLayer` is used used with a non-geospatial view such as the [OrthographicView](/docs/api-reference/core/orthographic-view.md) or the [OrbitView](/docs/api-reference/core/orbit-view.md), `x` and `y` increment from the world origin, and each tile's width and height match that defined by the `tileSize` prop. For example, the tile `x: 0, y: 0` occupies the square between `[0, 0]` and `[tileSize, tileSize]`. If you need to offset the `z` level at which the tiles are fetched, there is a `tileOffset` prop. ## Properties @@ -138,10 +138,17 @@ if (signal.aborted) { The pixel dimension of the tiles, usually a power of 2. -The tile size represents the target pixel width and height of each tile when rendered. Smaller tile sizes display the content at higher resolution, while the layer needs to load more tiles to fill the same viewport. +For geospatial viewports, tile size represents the target pixel width and height of each tile when rendered. Smaller tile sizes display the content at higher resolution, while the layer needs to load more tiles to fill the same viewport. + +For non-geospatial viewports, the tile size should correspond to the true pixel size of the tiles. - Default: `512` +##### `tileOffset` (Number, optional) + +For non-geospatial viewports, this offset changes the zoom level at which the tiles are fetched. + +- Default: `0` ##### `maxZoom` (Number|Null, optional) diff --git a/modules/geo-layers/src/tile-layer/tile-layer.js b/modules/geo-layers/src/tile-layer/tile-layer.js index 1da423ff904..9d6fee7b488 100644 --- a/modules/geo-layers/src/tile-layer/tile-layer.js +++ b/modules/geo-layers/src/tile-layer/tile-layer.js @@ -23,7 +23,8 @@ const defaultProps = { maxCacheByteSize: null, refinementStrategy: STRATEGY_DEFAULT, zRange: null, - maxRequests: 6 + maxRequests: 6, + tileOffset: 0 }; export default class TileLayer extends CompositeLayer { @@ -89,7 +90,8 @@ export default class TileLayer extends CompositeLayer { maxCacheByteSize, refinementStrategy, extent, - maxRequests + maxRequests, + tileOffset } = props; return { @@ -100,7 +102,8 @@ export default class TileLayer extends CompositeLayer { tileSize, refinementStrategy, extent, - maxRequests + maxRequests, + tileOffset }; } diff --git a/modules/geo-layers/src/tile-layer/tileset-2d.js b/modules/geo-layers/src/tile-layer/tileset-2d.js index 83d4fd34245..5591d0d57d2 100644 --- a/modules/geo-layers/src/tile-layer/tileset-2d.js +++ b/modules/geo-layers/src/tile-layer/tileset-2d.js @@ -159,7 +159,7 @@ export default class Tileset2D { // Returns array of {x, y, z} getTileIndices({viewport, maxZoom, minZoom, zRange, modelMatrix, modelMatrixInverse}) { - const {tileSize, extent} = this.opts; + const {tileSize, extent, tileOffset} = this.opts; return getTileIndices({ viewport, maxZoom, @@ -168,7 +168,8 @@ export default class Tileset2D { tileSize, extent, modelMatrix, - modelMatrixInverse + modelMatrixInverse, + tileOffset }); } diff --git a/modules/geo-layers/src/tile-layer/utils.js b/modules/geo-layers/src/tile-layer/utils.js index a100fb3abdf..4916be55574 100644 --- a/modules/geo-layers/src/tile-layer/utils.js +++ b/modules/geo-layers/src/tile-layer/utils.js @@ -177,11 +177,12 @@ export function getTileIndices({ extent, tileSize = TILE_SIZE, modelMatrix, - modelMatrixInverse + modelMatrixInverse, + tileOffset = 0 }) { let z = viewport.isGeospatial ? Math.round(viewport.zoom + Math.log2(TILE_SIZE / tileSize)) - : Math.ceil(viewport.zoom); + : Math.ceil(viewport.zoom) + tileOffset; if (Number.isFinite(minZoom) && z < minZoom) { if (!extent) { return []; From 6c0fdec57d881de8cc23756f0b834416e2adeb0f Mon Sep 17 00:00:00 2001 From: ilan-gold Date: Mon, 21 Jun 2021 15:25:50 -0400 Subject: [PATCH 3/5] Switch to `zoomOffset` --- docs/api-reference/geo-layers/tile-layer.md | 4 ++-- modules/geo-layers/src/tile-layer/tile-layer.js | 6 +++--- modules/geo-layers/src/tile-layer/tileset-2d.js | 4 ++-- modules/geo-layers/src/tile-layer/utils.js | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/api-reference/geo-layers/tile-layer.md b/docs/api-reference/geo-layers/tile-layer.md index 270ee2d1090..d5fe7f3ee26 100644 --- a/docs/api-reference/geo-layers/tile-layer.md +++ b/docs/api-reference/geo-layers/tile-layer.md @@ -82,7 +82,7 @@ At each integer zoom level (`z`), the XY plane in the view space is divided into When the `TileLayer` is used with a geospatial view such as the [MapView](/docs/api-reference/core/map-view.md), x, y, and z are determined from [the OSM tile index](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames). -When the `TileLayer` is used used with a non-geospatial view such as the [OrthographicView](/docs/api-reference/core/orthographic-view.md) or the [OrbitView](/docs/api-reference/core/orbit-view.md), `x` and `y` increment from the world origin, and each tile's width and height match that defined by the `tileSize` prop. For example, the tile `x: 0, y: 0` occupies the square between `[0, 0]` and `[tileSize, tileSize]`. If you need to offset the `z` level at which the tiles are fetched, there is a `tileOffset` prop. +When the `TileLayer` is used used with a non-geospatial view such as the [OrthographicView](/docs/api-reference/core/orthographic-view.md) or the [OrbitView](/docs/api-reference/core/orbit-view.md), `x` and `y` increment from the world origin, and each tile's width and height match that defined by the `tileSize` prop. For example, the tile `x: 0, y: 0` occupies the square between `[0, 0]` and `[tileSize, tileSize]`. If you need to offset the `z` level at which the tiles are fetched, there is a `zoomOffset` prop. ## Properties @@ -144,7 +144,7 @@ For non-geospatial viewports, the tile size should correspond to the true pixel - Default: `512` -##### `tileOffset` (Number, optional) +##### `zoomOffset` (Number, optional) For non-geospatial viewports, this offset changes the zoom level at which the tiles are fetched. diff --git a/modules/geo-layers/src/tile-layer/tile-layer.js b/modules/geo-layers/src/tile-layer/tile-layer.js index 9d6fee7b488..b3512e1e48c 100644 --- a/modules/geo-layers/src/tile-layer/tile-layer.js +++ b/modules/geo-layers/src/tile-layer/tile-layer.js @@ -24,7 +24,7 @@ const defaultProps = { refinementStrategy: STRATEGY_DEFAULT, zRange: null, maxRequests: 6, - tileOffset: 0 + zoomOffset: 0 }; export default class TileLayer extends CompositeLayer { @@ -91,7 +91,7 @@ export default class TileLayer extends CompositeLayer { refinementStrategy, extent, maxRequests, - tileOffset + zoomOffset } = props; return { @@ -103,7 +103,7 @@ export default class TileLayer extends CompositeLayer { refinementStrategy, extent, maxRequests, - tileOffset + zoomOffset }; } diff --git a/modules/geo-layers/src/tile-layer/tileset-2d.js b/modules/geo-layers/src/tile-layer/tileset-2d.js index 5591d0d57d2..bd4fc352b46 100644 --- a/modules/geo-layers/src/tile-layer/tileset-2d.js +++ b/modules/geo-layers/src/tile-layer/tileset-2d.js @@ -159,7 +159,7 @@ export default class Tileset2D { // Returns array of {x, y, z} getTileIndices({viewport, maxZoom, minZoom, zRange, modelMatrix, modelMatrixInverse}) { - const {tileSize, extent, tileOffset} = this.opts; + const {tileSize, extent, zoomOffset} = this.opts; return getTileIndices({ viewport, maxZoom, @@ -169,7 +169,7 @@ export default class Tileset2D { extent, modelMatrix, modelMatrixInverse, - tileOffset + zoomOffset }); } diff --git a/modules/geo-layers/src/tile-layer/utils.js b/modules/geo-layers/src/tile-layer/utils.js index 4916be55574..60f44f5b949 100644 --- a/modules/geo-layers/src/tile-layer/utils.js +++ b/modules/geo-layers/src/tile-layer/utils.js @@ -178,11 +178,11 @@ export function getTileIndices({ tileSize = TILE_SIZE, modelMatrix, modelMatrixInverse, - tileOffset = 0 + zoomOffset = 0 }) { let z = viewport.isGeospatial ? Math.round(viewport.zoom + Math.log2(TILE_SIZE / tileSize)) - : Math.ceil(viewport.zoom) + tileOffset; + : Math.ceil(viewport.zoom) + zoomOffset; if (Number.isFinite(minZoom) && z < minZoom) { if (!extent) { return []; From 53f8e4e40c26eb32017ef0501af01cf0dc9b7b16 Mon Sep 17 00:00:00 2001 From: ilan-gold Date: Mon, 21 Jun 2021 15:35:49 -0400 Subject: [PATCH 4/5] Add test. --- .../geo-layers/tile-layer/utils.spec.js | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/test/modules/geo-layers/tile-layer/utils.spec.js b/test/modules/geo-layers/tile-layer/utils.spec.js index 4d7e4cb3452..e516b4e28c6 100644 --- a/test/modules/geo-layers/tile-layer/utils.spec.js +++ b/test/modules/geo-layers/tile-layer/utils.spec.js @@ -131,6 +131,32 @@ const TEST_CASES = [ }), output: ['2,2,4', '2,3,4', '3,2,4', '3,3,4'] }, + { + title: 'non-geospatial with zoom offset', + viewport: new OrthographicView().makeViewport({ + width: 800, + height: 400, + viewState: { + target: [100, 100], + zoom: 4 + } + }), + zoomOffset: 1, + output: [ + '4,5,5', + '4,6,5', + '4,7,5', + '5,5,5', + '5,6,5', + '5,7,5', + '6,5,5', + '6,6,5', + '6,7,5', + '7,5,5', + '7,6,5', + '7,7,5' + ] + }, { title: 'non-geospatial with tile size', viewport: new OrthographicView().makeViewport({ @@ -295,7 +321,8 @@ test('getTileIndices', t => { tileSize, modelMatrix, extent, - modelMatrixInverse + modelMatrixInverse, + zoomOffset } = testCase; const result = getTileIndices({ viewport, @@ -305,7 +332,8 @@ test('getTileIndices', t => { tileSize, modelMatrix, modelMatrixInverse, - extent + extent, + zoomOffset }); t.deepEqual(getTileIds(result), testCase.output, testCase.title); } From f8045cd8d1b483861bce7466bca31c6bbe108bd6 Mon Sep 17 00:00:00 2001 From: ilan-gold Date: Wed, 23 Jun 2021 14:54:27 -0400 Subject: [PATCH 5/5] Address comments. --- docs/api-reference/geo-layers/tile-layer.md | 6 ++++-- docs/upgrade-guide.md | 1 + examples/website/map-tile/app.js | 4 ++-- modules/geo-layers/src/tile-layer/utils.js | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/api-reference/geo-layers/tile-layer.md b/docs/api-reference/geo-layers/tile-layer.md index d5fe7f3ee26..6734ddabc96 100644 --- a/docs/api-reference/geo-layers/tile-layer.md +++ b/docs/api-reference/geo-layers/tile-layer.md @@ -82,7 +82,9 @@ At each integer zoom level (`z`), the XY plane in the view space is divided into When the `TileLayer` is used with a geospatial view such as the [MapView](/docs/api-reference/core/map-view.md), x, y, and z are determined from [the OSM tile index](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames). -When the `TileLayer` is used used with a non-geospatial view such as the [OrthographicView](/docs/api-reference/core/orthographic-view.md) or the [OrbitView](/docs/api-reference/core/orbit-view.md), `x` and `y` increment from the world origin, and each tile's width and height match that defined by the `tileSize` prop. For example, the tile `x: 0, y: 0` occupies the square between `[0, 0]` and `[tileSize, tileSize]`. If you need to offset the `z` level at which the tiles are fetched, there is a `zoomOffset` prop. +When the `TileLayer` is used used with a non-geospatial view such as the [OrthographicView](/docs/api-reference/core/orthographic-view.md) or the [OrbitView](/docs/api-reference/core/orbit-view.md), `x` and `y` increment from the world origin, and each tile's width and height match that defined by the `tileSize` prop. For example, the tile `x: 0, y: 0` occupies the square between `[0, 0]` and `[tileSize, tileSize]`. + +If you need to offset the `z` level at which the tiles are fetched in order to fetch tiles at a higher resolution in order to produce a "crisper" picture, there is a `zoomOffset` prop. ## Properties @@ -146,7 +148,7 @@ For non-geospatial viewports, the tile size should correspond to the true pixel ##### `zoomOffset` (Number, optional) -For non-geospatial viewports, this offset changes the zoom level at which the tiles are fetched. +This offset changes the zoom level at which the tiles are fetched. Needs to be an integer. - Default: `0` diff --git a/docs/upgrade-guide.md b/docs/upgrade-guide.md index da9b08a7d5e..387a956bb28 100644 --- a/docs/upgrade-guide.md +++ b/docs/upgrade-guide.md @@ -24,6 +24,7 @@ The module entry point is now only lightly transpiled for the most commonly used - `CartoBQTilerLayer` will be deprecated in 8.6. Use `CartoLayer` instead with `type` to `MAP_TYPES.TILESET`. - `CartoSQLLayer` will be deprecated in 8.6. Use `CartoLayer` instead with `type` to `MAP_TYPES.QUERY`. - `GeoJsonLayer`'s `getRadius` props is deprecated, replaced by `getPointRadius`. +- It is recommended to use `zoomOffset` in the `TileLayer` when trying to affect the `zoom` resolution at which tiles are fetched. ### onError Callback diff --git a/examples/website/map-tile/app.js b/examples/website/map-tile/app.js index 4a7b69b3fc6..a0493d74e44 100644 --- a/examples/website/map-tile/app.js +++ b/examples/website/map-tile/app.js @@ -42,8 +42,8 @@ export default function App({showBorder = false, onTilesLoad = null}) { // https://wiki.openstreetmap.org/wiki/Zoom_levels minZoom: 0, maxZoom: 19, - tileSize: 512 / devicePixelRatio, - + tileSize: 256, + zoomOffset: devicePixelRatio === 1 ? -1 : 0, renderSubLayers: props => { const { bbox: {west, south, east, north} diff --git a/modules/geo-layers/src/tile-layer/utils.js b/modules/geo-layers/src/tile-layer/utils.js index 60f44f5b949..398b318e247 100644 --- a/modules/geo-layers/src/tile-layer/utils.js +++ b/modules/geo-layers/src/tile-layer/utils.js @@ -181,7 +181,7 @@ export function getTileIndices({ zoomOffset = 0 }) { let z = viewport.isGeospatial - ? Math.round(viewport.zoom + Math.log2(TILE_SIZE / tileSize)) + ? Math.round(viewport.zoom + Math.log2(TILE_SIZE / tileSize)) + zoomOffset : Math.ceil(viewport.zoom) + zoomOffset; if (Number.isFinite(minZoom) && z < minZoom) { if (!extent) {