diff --git a/src/ol/tilegrid/TileGrid.js b/src/ol/tilegrid/TileGrid.js index 9758aa780a..d5be04961e 100644 --- a/src/ol/tilegrid/TileGrid.js +++ b/src/ol/tilegrid/TileGrid.js @@ -180,6 +180,12 @@ class TileGrid { */ this.tmpSize_ = [0, 0]; + /** + * @private + * @type {import("../extent.js").Extent} + */ + this.tmpExtent_ = [0, 0, 0, 0]; + if (options.sizes !== undefined) { this.fullTileRanges_ = options.sizes.map(function (size, z) { const tileRange = new TileRange( @@ -340,7 +346,10 @@ class TileGrid { opt_tileRange ); } - const tileCoordExtent = this.getTileCoordExtent(tileCoord, opt_extent); + const tileCoordExtent = this.getTileCoordExtent( + tileCoord, + opt_extent || this.tmpExtent_ + ); return this.getTileRangeForExtentAndZ( tileCoordExtent, tileCoord[0] + 1, @@ -350,6 +359,48 @@ class TileGrid { return null; } + /** + * @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate. + * @param {number} z Integer zoom level. + * @param {import("../TileRange.js").default=} opt_tileRange Temporary import("../TileRange.js").default object. + * @return {import("../TileRange.js").default} Tile range. + */ + getTileRangeForTileCoordAndZ(tileCoord, z, opt_tileRange) { + if (z > this.maxZoom || z < this.minZoom) { + return null; + } + + const tileCoordZ = tileCoord[0]; + const tileCoordX = tileCoord[1]; + const tileCoordY = tileCoord[2]; + + if (z === tileCoordZ) { + return createOrUpdateTileRange( + tileCoordX, + tileCoordY, + tileCoordX, + tileCoordY, + opt_tileRange + ); + } + + if (this.zoomFactor_) { + const factor = Math.pow(this.zoomFactor_, z - tileCoordZ); + const minX = Math.floor(tileCoordX * factor); + const minY = Math.floor(tileCoordY * factor); + if (z < tileCoordZ) { + return createOrUpdateTileRange(minX, minX, minY, minY, opt_tileRange); + } + + const maxX = Math.floor(factor * (tileCoordX + 1)) - 1; + const maxY = Math.floor(factor * (tileCoordY + 1)) - 1; + return createOrUpdateTileRange(minX, maxX, minY, maxY, opt_tileRange); + } + + const tileCoordExtent = this.getTileCoordExtent(tileCoord, this.tmpExtent_); + return this.getTileRangeForExtentAndZ(tileCoordExtent, z, opt_tileRange); + } + /** * Get the extent for a tile range. * @param {number} z Integer zoom level. diff --git a/test/spec/ol/tilegrid/tilegrid.test.js b/test/spec/ol/tilegrid/tilegrid.test.js index ad2048cbc9..8ca76b44ba 100644 --- a/test/spec/ol/tilegrid/tilegrid.test.js +++ b/test/spec/ol/tilegrid/tilegrid.test.js @@ -1179,4 +1179,57 @@ describe('ol.tilegrid.TileGrid', function () { expect(tileGrid.getZForResolution(50, -1)).to.eql(3); }); }); + + describe('getTileRangeForTileCoordAndZ()', function () { + const tileGrid = createForExtent( + getProjection('EPSG:3857').getExtent(), + 22 + ); + + it('can be used to get the child tile range', function () { + const range = tileGrid.getTileRangeForTileCoordAndZ([0, 0, 0], 1); + expect(range.minX).to.be(0); + expect(range.maxX).to.be(1); + expect(range.minY).to.be(0); + expect(range.maxY).to.be(1); + }); + + it('can be used to get the range of a deeper level', function () { + const range = tileGrid.getTileRangeForTileCoordAndZ([0, 0, 0], 3); + expect(range.minX).to.be(0); + expect(range.maxX).to.be(7); + expect(range.minY).to.be(0); + expect(range.maxY).to.be(7); + }); + + it('can be used to get the parent tile range', function () { + const range = tileGrid.getTileRangeForTileCoordAndZ([1, 1, 0], 0); + expect(range.minX).to.be(0); + expect(range.maxX).to.be(0); + expect(range.minY).to.be(0); + expect(range.maxY).to.be(0); + }); + + it('can be used to get the range of a shallower level', function () { + const range = tileGrid.getTileRangeForTileCoordAndZ([3, 1, 6], 0); + expect(range.minX).to.be(0); + expect(range.maxX).to.be(0); + expect(range.minY).to.be(0); + expect(range.maxY).to.be(0); + }); + + const tileCoord = [15, 6239, 11751]; + tileGrid.forEachTileCoordParentTileRange(tileCoord, function ( + z, + tileRange + ) { + it(`works for level ${z}`, function () { + const range = tileGrid.getTileRangeForTileCoordAndZ(tileCoord, z); + expect(range.minX).to.be(tileRange.minX); + expect(range.maxX).to.be(tileRange.maxX); + expect(range.minY).to.be(tileRange.minY); + expect(range.maxY).to.be(tileRange.maxY); + }); + }); + }); });