Factor out common code and test

The findInterimTiles method was used in three renderers.  This change makes it available on the tile source and adds some basic tests.
This commit is contained in:
Tim Schaub
2013-02-18 14:18:08 -07:00
parent 4c2463dd91
commit ddf993f0c9
5 changed files with 211 additions and 77 deletions

View File

@@ -129,30 +129,8 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {};
var findInterimTiles = function(z, tileRange) {
// FIXME this could be more efficient about filling partial holes
var fullyCovered = true;
var tile, tileCoord, 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();
if (tilesToDrawByZ[z] && tilesToDrawByZ[z][tileCoordKey]) {
return;
}
tile = tileSource.getTile(tileCoord);
if (!goog.isNull(tile) && tile.getState() == ol.TileState.LOADED) {
if (!tilesToDrawByZ[z]) {
tilesToDrawByZ[z] = {};
}
tilesToDrawByZ[z][tileCoordKey] = tile;
} else {
fullyCovered = false;
}
}
}
return fullyCovered;
};
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
tilesToDrawByZ);
var allTilesLoaded = true;
var tile, tileCenter, tileCoord, tileState, x, y;
@@ -180,7 +158,7 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
}
allTilesLoaded = false;
tileGrid.forEachTileCoordParentTileRange(tileCoord, findInterimTiles);
tileGrid.forEachTileCoordParentTileRange(tileCoord, findLoadedTiles);
}
}

View File

@@ -93,30 +93,8 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {};
var findInterimTiles = function(z, tileRange) {
// FIXME this could be more efficient about filling partial holes
var fullyCovered = true;
var tile, tileCoord, 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();
if (tilesToDrawByZ[z] && tilesToDrawByZ[z][tileCoordKey]) {
return;
}
tile = tileSource.getTile(tileCoord);
if (!goog.isNull(tile) && tile.getState() == ol.TileState.LOADED) {
if (!tilesToDrawByZ[z]) {
tilesToDrawByZ[z] = {};
}
tilesToDrawByZ[z][tileCoordKey] = tile;
} else {
fullyCovered = false;
}
}
}
return fullyCovered;
};
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
tilesToDrawByZ);
var allTilesLoaded = true;
var tile, tileCenter, tileCoord, tileState, x, y;
@@ -144,7 +122,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
}
allTilesLoaded = false;
tileGrid.forEachTileCoordParentTileRange(tileCoord, findInterimTiles);
tileGrid.forEachTileCoordParentTileRange(tileCoord, findLoadedTiles);
}

View File

@@ -365,32 +365,8 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {};
var findInterimTiles = function(z, tileRange) {
// FIXME this could be more efficient about filling partial holes
var fullyCovered = true;
var tile, tileCoord, 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();
if (tilesToDrawByZ[z] && tilesToDrawByZ[z][tileCoordKey]) {
return;
}
tile = tileSource.getTile(tileCoord);
if (!goog.isNull(tile) &&
tile.getState() == ol.TileState.LOADED &&
mapRenderer.isTileTextureLoaded(tile)) {
if (!tilesToDrawByZ[z]) {
tilesToDrawByZ[z] = {};
}
tilesToDrawByZ[z][tileCoordKey] = tile;
} else {
fullyCovered = false;
}
}
}
return fullyCovered;
};
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
tilesToDrawByZ);
var tilesToLoad = new goog.structs.PriorityQueue();
@@ -428,7 +404,7 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
}
allTilesLoaded = false;
tileGrid.forEachTileCoordParentTileRange(tileCoord, findInterimTiles);
tileGrid.forEachTileCoordParentTileRange(tileCoord, findLoadedTiles);
}

View File

@@ -8,6 +8,7 @@ goog.require('ol.Projection');
goog.require('ol.Tile');
goog.require('ol.TileCoord');
goog.require('ol.TileRange');
goog.require('ol.TileState');
goog.require('ol.source.Source');
goog.require('ol.tilegrid.TileGrid');
@@ -58,6 +59,44 @@ ol.source.TileSource.prototype.canExpireCache = goog.functions.FALSE;
ol.source.TileSource.prototype.expireCache = goog.abstractMethod;
/**
* Look for loaded tiles over a given tile range and zoom level. Adds
* properties to the provided lookup representing key/tile pairs for already
* loaded tiles.
*
* @param {Object.<number, Object.<string, ol.Tile>>} loadedTilesByZ A lookup of
* loaded tiles by zoom level.
* @param {number} z Zoom level.
* @param {ol.TileRange} tileRange Tile range.
* @return {boolean} The tile range is fully covered with loaded tiles.
*/
ol.source.TileSource.prototype.findLoadedTiles = function(loadedTilesByZ, z,
tileRange) {
// FIXME this could be more efficient about filling partial holes
var fullyCovered = true;
var tile, tileCoord, 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();
if (loadedTilesByZ[z] && loadedTilesByZ[z][tileCoordKey]) {
return false; // TODO: fix this
}
tile = this.getTile(tileCoord);
if (!goog.isNull(tile) && tile.getState() == ol.TileState.LOADED) {
if (!loadedTilesByZ[z]) {
loadedTilesByZ[z] = {};
}
loadedTilesByZ[z][tileCoordKey] = tile;
} else {
fullyCovered = false;
}
}
}
return fullyCovered;
};
/**
* @inheritDoc
*/

View File

@@ -0,0 +1,163 @@
goog.provide('ol.test.source.TileSource');
describe('ol.source.TileSource', function() {
describe('constructor', function() {
it('returns a tile source', function() {
var source = new ol.source.TileSource({
projection: ol.Projection.getFromCode('EPSG:4326')
});
expect(source).toBeA(ol.source.Source);
expect(source).toBeA(ol.source.TileSource);
});
});
describe('#findLoadedTiles()', function() {
it('adds no tiles if none are already loaded', function() {
// a source with no loaded tiles
var source = new ol.test.source.MockTileSource({});
var loadedTilesByZ = {};
var grid = source.getTileGrid();
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 3);
source.findLoadedTiles(loadedTilesByZ, 3, range);
var keys = goog.object.getKeys(loadedTilesByZ);
expect(keys.length).toBe(0);
});
it('adds loaded tiles to the lookup (z: 0)', function() {
// a source with no loaded tiles
var source = new ol.test.source.MockTileSource({
'0/0/-1': true,
'1/0/-1': true
});
var loadedTilesByZ = {};
var grid = source.getTileGrid();
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 0);
source.findLoadedTiles(loadedTilesByZ, 0, range);
var keys = goog.object.getKeys(loadedTilesByZ);
expect(keys.length).toBe(1);
var tile = loadedTilesByZ['0']['0/0/-1'];
expect(tile).toBeA(ol.Tile);
expect(tile.state).toBe(ol.TileState.LOADED);
});
it('adds loaded tiles to the lookup (z: 1)', function() {
// a source with no loaded tiles
var source = new ol.test.source.MockTileSource({
'0/0/-1': true,
'1/0/-1': true
});
var loadedTilesByZ = {};
var grid = source.getTileGrid();
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1);
source.findLoadedTiles(loadedTilesByZ, 1, range);
var keys = goog.object.getKeys(loadedTilesByZ);
expect(keys.length).toBe(1);
var tile = loadedTilesByZ['1']['1/0/-1'];
expect(tile).toBeA(ol.Tile);
expect(tile.state).toBe(ol.TileState.LOADED);
});
});
});
/**
* Tile source for tests that uses a EPSG:4326 based grid with 4 resolutions and
* 256x256 tiles.
*
* @constructor
* @extends {ol.source.TileSource}
* @param {Object.<string, boolean>} loaded Lookup of already loaded tiles.
*/
ol.test.source.MockTileSource = function(loaded) {
var extent = new ol.Extent(-180, -180, 180, 180);
var tileGrid = new ol.tilegrid.TileGrid({
resolutions: [360 / 256, 180 / 256, 90 / 256, 45 / 256],
extent: extent,
origin: new ol.Coordinate(-180, 180),
tileSize: new ol.Size(256, 256)
});
goog.base(this, {
extent: extent,
projection: ol.Projection.getFromCode('EPSG:4326'),
tileGrid: tileGrid
});
/**
* @type {Object.<string, boolean>}
* @private
*/
this.loaded_ = loaded;
};
goog.inherits(ol.test.source.MockTileSource, ol.source.TileSource);
/**
* @inheritDoc
*/
ol.test.source.MockTileSource.prototype.getTile = function(tileCoord) {
var tile = new ol.Tile(tileCoord);
var key = tileCoord.toString();
if (this.loaded_[key]) {
tile.state = ol.TileState.LOADED;
}
return tile;
};
describe('ol.test.source.MockTileSource', function() {
describe('constructor', function() {
it('creates a tile source', function() {
var source = new ol.test.source.MockTileSource({});
expect(source).toBeA(ol.source.TileSource);
expect(source).toBeA(ol.test.source.MockTileSource);
});
});
describe('#getTile()', function() {
it('returns a tile with state based on constructor arg', function() {
var source = new ol.test.source.MockTileSource({
'0/0/0': true,
'1/0/-1': true
});
var tile;
// check a loaded tile
tile = source.getTile(new ol.TileCoord(0, 0, 0));
expect(tile).toBeA(ol.Tile);
expect(tile.state).toBe(ol.TileState.LOADED);
// check a tile that is not loaded
tile = source.getTile(new ol.TileCoord(1, 0, 0));
expect(tile).toBeA(ol.Tile);
expect(tile.state).toBe(ol.TileState.IDLE);
// check another loaded tile
tile = source.getTile(new ol.TileCoord(1, 0, -1));
expect(tile).toBeA(ol.Tile);
expect(tile.state).toBe(ol.TileState.LOADED);
});
});
});
goog.require('goog.object');
goog.require('ol.Coordinate');
goog.require('ol.Extent');
goog.require('ol.Projection');
goog.require('ol.Tile');
goog.require('ol.TileCoord');
goog.require('ol.TileState');
goog.require('ol.source.TileSource');
goog.require('ol.tilegrid.TileGrid');