Replace getTile with getTileZXY

This massively reduces the number of temporary ol.TileCoord objects.

Previously an ol.TileCoord object was generated for every potentially
visible tile at the current zoom level and lower, every frame.  This
commit eliminates all of those.  Now new ol.TileCoord objects are only
allocated when a new tile is created.
This commit is contained in:
Tom Payne
2013-03-24 14:51:54 +01:00
parent 247fc8f031
commit dfb631a08f
9 changed files with 87 additions and 75 deletions

View File

@@ -155,22 +155,21 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
tilesToDrawByZ, getTileIfLoaded);
var allTilesLoaded = true;
var tile, tileCoord, tileState, x, y;
var tile, tileState, x, y;
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tileCoord = new ol.TileCoord(z, x, y);
tile = tileSource.getTile(tileCoord, tileGrid, projection);
tile = tileSource.getTileZXY(z, x, y, tileGrid, projection);
tileState = tile.getState();
if (tileState == ol.TileState.LOADED || tileState == ol.TileState.EMPTY) {
tilesToDrawByZ[z][tileCoord.toString()] = tile;
tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
continue;
} else if (tileState == ol.TileState.ERROR) {
continue;
}
allTilesLoaded = false;
tileGrid.forEachTileCoordParentTileRange(tileCoord, findLoadedTiles);
tileGrid.forEachTileCoordParentTileRange(tile.tileCoord, findLoadedTiles);
}
}
@@ -191,9 +190,8 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
if (currentZ == z) {
for (tileCoordKey in tilesToDraw) {
tile = tilesToDraw[tileCoordKey];
tileCoord = tile.tileCoord;
index = (tileCoord.y - tileRange.minY) * tileRangeWidth +
(tileCoord.x - tileRange.minX);
index = (tile.tileCoord.y - tileRange.minY) * tileRangeWidth +
(tile.tileCoord.x - tileRange.minX);
if (this.renderedTiles_[index] != tile) {
x = tileSize.width * (tile.tileCoord.x - tileRange.minX);
y = tileSize.height * (tileRange.maxY - tile.tileCoord.y);

View File

@@ -112,15 +112,14 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
tilesToDrawByZ, getTileIfLoaded);
var allTilesLoaded = true;
var tile, tileCoord, tileState, x, y;
var tile, tileState, x, y;
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tileCoord = new ol.TileCoord(z, x, y);
tile = tileSource.getTile(tileCoord, tileGrid, projection);
tile = tileSource.getTileZXY(z, x, y, tileGrid, projection);
tileState = tile.getState();
if (tileState == ol.TileState.LOADED) {
tilesToDrawByZ[z][tileCoord.toString()] = tile;
tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
continue;
} else if (tileState == ol.TileState.ERROR ||
tileState == ol.TileState.EMPTY) {
@@ -128,7 +127,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
}
allTilesLoaded = false;
tileGrid.forEachTileCoordParentTileRange(tileCoord, findLoadedTiles);
tileGrid.forEachTileCoordParentTileRange(tile.tileCoord, findLoadedTiles);
}

View File

@@ -9,7 +9,6 @@ goog.require('ol.Image');
goog.require('ol.ImageState');
goog.require('ol.Object');
goog.require('ol.Tile');
goog.require('ol.TileCoord');
goog.require('ol.TileRange');
goog.require('ol.TileState');
goog.require('ol.layer.Layer');
@@ -258,12 +257,13 @@ ol.renderer.Layer.prototype.updateUsedTiles =
* @param {ol.source.TileSource} tileSource Tile source.
* @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
* @param {ol.Projection} projection Projection.
* @return {function(ol.TileCoord): ol.Tile} Returns a tile if it is loaded.
* @return {function(number, number, number): ol.Tile} Returns a tile if it is
* loaded.
*/
ol.renderer.Layer.prototype.createGetTileIfLoadedFunction =
function(isLoadedFunction, tileSource, tileGrid, projection) {
return function(tileCoord) {
var tile = tileSource.getTile(tileCoord, tileGrid, projection);
return function(z, x, y) {
var tile = tileSource.getTileZXY(z, x, y, tileGrid, projection);
return isLoadedFunction(tile) ? tile : null;
};
};
@@ -307,7 +307,7 @@ ol.renderer.Layer.prototype.manageTilePyramid =
}
var wantedTiles = frameState.wantedTiles[tileSourceKey];
var tileQueue = frameState.tileQueue;
var tile, tileCenter, tileCoord, tileRange, tileResolution, x, y, z;
var tile, tileCenter, tileRange, tileResolution, x, y, z;
// FIXME this should loop up to tileGrid's minZ when implemented
for (z = currentZ; z >= 0; --z) {
tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);
@@ -315,15 +315,14 @@ ol.renderer.Layer.prototype.manageTilePyramid =
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
if (ol.PREEMPTIVELY_LOAD_LOW_RESOLUTION_TILES || z == currentZ) {
tileCoord = new ol.TileCoord(z, x, y);
tile = tileSource.getTile(tileCoord, tileGrid, projection);
tile = tileSource.getTileZXY(z, x, y, tileGrid, projection);
if (tile.getState() == ol.TileState.IDLE) {
tileCenter = tileGrid.getTileCoordCenter(tileCoord);
wantedTiles[tileCoord.toString()] = true;
tileCenter = tileGrid.getTileCoordCenter(tile.tileCoord);
wantedTiles[tile.tileCoord.toString()] = true;
tileQueue.enqueue(tile, tileSourceKey, tileCenter, tileResolution);
}
} else {
tileSource.useTile(z + '/' + x + '/' + y);
tileSource.useTileZXY(z, x, y);
}
}
}

View File

@@ -13,7 +13,6 @@ goog.require('goog.webgl');
goog.require('ol.Extent');
goog.require('ol.Size');
goog.require('ol.Tile');
goog.require('ol.TileCoord');
goog.require('ol.TileRange');
goog.require('ol.TileState');
goog.require('ol.layer.TileLayer');
@@ -264,19 +263,18 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
var tilesToLoad = new goog.structs.PriorityQueue();
var allTilesLoaded = true;
var deltaX, deltaY, priority, tile, tileCenter, tileCoord, tileState, x, y;
var deltaX, deltaY, priority, tile, tileCenter, tileState, x, y;
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tileCoord = new ol.TileCoord(z, x, y);
tile = tileSource.getTile(tileCoord, tileGrid, projection);
tile = tileSource.getTileZXY(z, x, y, tileGrid, projection);
tileState = tile.getState();
if (tileState == ol.TileState.LOADED) {
if (mapRenderer.isTileTextureLoaded(tile)) {
tilesToDrawByZ[z][tileCoord.toString()] = tile;
tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
continue;
} else {
tileCenter = tileGrid.getTileCoordCenter(tileCoord);
tileCenter = tileGrid.getTileCoordCenter(tile.tileCoord);
deltaX = tileCenter.x - center.x;
deltaY = tileCenter.y - center.y;
priority = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
@@ -288,7 +286,8 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
}
allTilesLoaded = false;
tileGrid.forEachTileCoordParentTileRange(tileCoord, findLoadedTiles);
tileGrid.forEachTileCoordParentTileRange(
tile.tileCoord, findLoadedTiles);
}

View File

@@ -122,13 +122,13 @@ ol.source.DebugTileSource.prototype.expireCache = function(usedTiles) {
/**
* @inheritDoc
*/
ol.source.DebugTileSource.prototype.getTile = function(tileCoord) {
var key = tileCoord.toString();
if (this.tileCache_.containsKey(key)) {
return /** @type {!ol.DebugTile_} */ (this.tileCache_.get(key));
ol.source.DebugTileSource.prototype.getTileZXY = function(z, x, y) {
var tileCoordKey = ol.TileCoord.getKeyZXY(z, x, y);
if (this.tileCache_.containsKey(tileCoordKey)) {
return /** @type {!ol.DebugTile_} */ (this.tileCache_.get(tileCoordKey));
} else {
var tile = new ol.DebugTile_(tileCoord, this.tileGrid);
this.tileCache_.set(key, tile);
var tile = new ol.DebugTile_(new ol.TileCoord(z, x, y), this.tileGrid);
this.tileCache_.set(tileCoordKey, tile);
return tile;
}
};

View File

@@ -7,6 +7,7 @@ goog.require('ol.ImageTile');
goog.require('ol.Projection');
goog.require('ol.Tile');
goog.require('ol.TileCache');
goog.require('ol.TileCoord');
goog.require('ol.TileState');
goog.require('ol.TileUrlFunction');
goog.require('ol.TileUrlFunctionType');
@@ -86,21 +87,22 @@ ol.source.ImageTileSource.prototype.expireCache = function(usedTiles) {
/**
* @inheritDoc
*/
ol.source.ImageTileSource.prototype.getTile =
function(tileCoord, tileGrid, projection) {
var key = tileCoord.toString();
if (this.tileCache_.containsKey(key)) {
return /** @type {!ol.Tile} */ (this.tileCache_.get(key));
ol.source.ImageTileSource.prototype.getTileZXY =
function(z, x, y, tileGrid, projection) {
var tileCoordKey = ol.TileCoord.getKeyZXY(z, x, y);
if (this.tileCache_.containsKey(tileCoordKey)) {
return /** @type {!ol.Tile} */ (this.tileCache_.get(tileCoordKey));
} else {
goog.asserts.assert(tileGrid);
goog.asserts.assert(projection);
var tileCoord = new ol.TileCoord(z, x, y);
var tileUrl = this.tileUrlFunction(tileCoord, tileGrid, projection);
var tile = new ol.ImageTile(
tileCoord,
goog.isDef(tileUrl) ? ol.TileState.IDLE : ol.TileState.EMPTY,
goog.isDef(tileUrl) ? tileUrl : '',
this.crossOrigin_);
this.tileCache_.set(key, tile);
this.tileCache_.set(tileCoordKey, tile);
return tile;
}
};
@@ -109,7 +111,8 @@ ol.source.ImageTileSource.prototype.getTile =
/**
* @inheritDoc
*/
ol.source.ImageTileSource.prototype.useTile = function(tileCoordKey) {
ol.source.ImageTileSource.prototype.useTileZXY = function(z, x, y) {
var tileCoordKey = ol.TileCoord.getKeyZXY(z, x, y);
if (this.tileCache_.containsKey(tileCoordKey)) {
this.tileCache_.get(tileCoordKey);
}

View File

@@ -72,8 +72,8 @@ ol.source.TileSource.prototype.expireCache = goog.abstractMethod;
*
* @param {Object.<number, Object.<string, ol.Tile>>} loadedTilesByZ A lookup of
* loaded tiles by zoom level.
* @param {function(ol.TileCoord): ol.Tile} getTileIfLoaded A function that
* returns the tile only if it is fully loaded.
* @param {function(number, number, number): ol.Tile} getTileIfLoaded A function
* that returns the tile only if it is fully loaded.
* @param {number} z Zoom level.
* @param {ol.TileRange} tileRange Tile range.
* @return {boolean} The tile range is fully covered with loaded tiles.
@@ -82,15 +82,14 @@ ol.source.TileSource.prototype.findLoadedTiles = function(loadedTilesByZ,
getTileIfLoaded, z, tileRange) {
// FIXME this could be more efficient about filling partial holes
var fullyCovered = true;
var tile, tileCoord, tileCoordKey, x, y;
var tile, tileCoordKey, x, y;
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tileCoord = new ol.TileCoord(z, x, y);
tileCoordKey = tileCoord.toString();
tileCoordKey = ol.TileCoord.getKeyZXY(z, x, y);
if (loadedTilesByZ[z] && loadedTilesByZ[z][tileCoordKey]) {
continue;
}
tile = getTileIfLoaded(tileCoord);
tile = getTileIfLoaded(z, x, y);
if (!goog.isNull(tile)) {
if (!loadedTilesByZ[z]) {
loadedTilesByZ[z] = {};
@@ -122,12 +121,14 @@ ol.source.TileSource.prototype.getResolutions = function() {
/**
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {number} z Tile coordinate z.
* @param {number} x Tile coordinate x.
* @param {number} y Tile coordinate y.
* @param {ol.tilegrid.TileGrid=} opt_tileGrid Tile grid.
* @param {ol.Projection=} opt_projection Projection.
* @return {!ol.Tile} Tile.
*/
ol.source.TileSource.prototype.getTile = goog.abstractMethod;
ol.source.TileSource.prototype.getTileZXY = goog.abstractMethod;
/**
@@ -140,6 +141,8 @@ ol.source.TileSource.prototype.getTileGrid = function() {
/**
* Marks a tile coord as being used, without triggering a load.
* @param {string} tileCoordKey Tile coordinate key.
* @param {number} z Tile coordinate z.
* @param {number} x Tile coordinate x.
* @param {number} y Tile coordinate y.
*/
ol.source.TileSource.prototype.useTile = goog.nullFunction;
ol.source.TileSource.prototype.useTileZXY = goog.nullFunction;

View File

@@ -78,6 +78,17 @@ ol.TileCoord.createFromString = function(str) {
};
/**
* @param {number} z Z.
* @param {number} x X.
* @param {number} y Y.
* @return {string} Key.
*/
ol.TileCoord.getKeyZXY = function(z, x, y) {
return [z, x, y].join('/');
};
/**
* @return {number} Hash.
*/
@@ -112,5 +123,5 @@ ol.TileCoord.prototype.quadKey = function() {
* @return {string} String.
*/
ol.TileCoord.prototype.toString = function() {
return [this.z, this.x, this.y].join('/');
return ol.TileCoord.getKeyZXY(this.z, this.x, this.y);
};

View File

@@ -22,8 +22,8 @@ describe('ol.source.TileSource', function() {
var grid = source.getTileGrid();
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 3);
function getTileIfLoaded(tileCoord) {
var tile = source.getTile(tileCoord, null, null);
function getTileIfLoaded(z, x, y) {
var tile = source.getTileZXY(z, x, y, null, null);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
@@ -44,8 +44,8 @@ describe('ol.source.TileSource', function() {
var grid = source.getTileGrid();
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 0);
function getTileIfLoaded(tileCoord) {
var tile = source.getTile(tileCoord, null, null);
function getTileIfLoaded(z, x, y) {
var tile = source.getTileZXY(z, x, y, null, null);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
@@ -68,8 +68,8 @@ describe('ol.source.TileSource', function() {
var grid = source.getTileGrid();
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1);
function getTileIfLoaded(tileCoord) {
var tile = source.getTile(tileCoord, null, null);
function getTileIfLoaded(z, x, y) {
var tile = source.getTileZXY(z, x, y, null, null);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
@@ -93,8 +93,8 @@ describe('ol.source.TileSource', function() {
var loadedTilesByZ = {};
var grid = source.getTileGrid();
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1);
function getTileIfLoaded(tileCoord) {
var tile = source.getTile(tileCoord, null, null);
function getTileIfLoaded(z, x, y) {
var tile = source.getTileZXY(z, x, y, null, null);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
@@ -119,8 +119,8 @@ describe('ol.source.TileSource', function() {
var grid = source.getTileGrid();
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1);
function getTileIfLoaded(tileCoord) {
var tile = source.getTile(tileCoord, null, null);
function getTileIfLoaded(z, x, y) {
var tile = source.getTileZXY(z, x, y, null, null);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
@@ -142,8 +142,8 @@ describe('ol.source.TileSource', function() {
var grid = source.getTileGrid();
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1);
function getTileIfLoaded(tileCoord) {
var tile = source.getTile(tileCoord, null, null);
function getTileIfLoaded(z, x, y) {
var tile = source.getTileZXY(z, x, y, null, null);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
@@ -167,8 +167,8 @@ describe('ol.source.TileSource', function() {
var grid = source.getTileGrid();
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1);
function getTileIfLoaded(tileCoord) {
var tile = source.getTile(tileCoord, null, null);
function getTileIfLoaded(z, x, y) {
var tile = source.getTileZXY(z, x, y, null, null);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
@@ -219,10 +219,10 @@ goog.inherits(ol.test.source.MockTileSource, ol.source.TileSource);
/**
* @inheritDoc
*/
ol.test.source.MockTileSource.prototype.getTile = function(tileCoord) {
var key = tileCoord.toString();
ol.test.source.MockTileSource.prototype.getTileZXY = function(z, x, y) {
var key = ol.TileCoord.getKeyZXY(z, x, y);
var tileState = this.loaded_[key] ? ol.TileState.LOADED : ol.TileState.IDLE;
return new ol.Tile(tileCoord, tileState);
return new ol.Tile(new ol.TileCoord(z, x, y), tileState);
};
@@ -236,7 +236,7 @@ describe('ol.test.source.MockTileSource', function() {
});
});
describe('#getTile()', function() {
describe('#getTileZXY()', function() {
it('returns a tile with state based on constructor arg', function() {
var source = new ol.test.source.MockTileSource({
'0/0/0': true,
@@ -245,17 +245,17 @@ describe('ol.test.source.MockTileSource', function() {
var tile;
// check a loaded tile
tile = source.getTile(new ol.TileCoord(0, 0, 0));
tile = source.getTileZXY(0, 0, 0);
expect(tile).to.be.a(ol.Tile);
expect(tile.state).to.be(ol.TileState.LOADED);
// check a tile that is not loaded
tile = source.getTile(new ol.TileCoord(1, 0, -1));
tile = source.getTileZXY(1, 0, -1);
expect(tile).to.be.a(ol.Tile);
expect(tile.state).to.be(ol.TileState.IDLE);
// check another loaded tile
tile = source.getTile(new ol.TileCoord(1, 0, 0));
tile = source.getTileZXY(1, 0, 0);
expect(tile).to.be.a(ol.Tile);
expect(tile.state).to.be(ol.TileState.LOADED);