Merge pull request #206 from tschaub/interim-tiles
Share common code to find loaded tiles
This commit is contained in:
@@ -129,30 +129,11 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
|
|||||||
var tilesToDrawByZ = {};
|
var tilesToDrawByZ = {};
|
||||||
tilesToDrawByZ[z] = {};
|
tilesToDrawByZ[z] = {};
|
||||||
|
|
||||||
var findInterimTiles = function(z, tileRange) {
|
function isLoaded(tile) {
|
||||||
// FIXME this could be more efficient about filling partial holes
|
return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED;
|
||||||
var fullyCovered = true;
|
}
|
||||||
var tile, tileCoord, tileCoordKey, x, y;
|
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
|
||||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
tilesToDrawByZ, isLoaded);
|
||||||
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 allTilesLoaded = true;
|
var allTilesLoaded = true;
|
||||||
var tile, tileCenter, tileCoord, tileState, x, y;
|
var tile, tileCenter, tileCoord, tileState, x, y;
|
||||||
@@ -180,7 +161,7 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
|
|||||||
}
|
}
|
||||||
|
|
||||||
allTilesLoaded = false;
|
allTilesLoaded = false;
|
||||||
tileGrid.forEachTileCoordParentTileRange(tileCoord, findInterimTiles);
|
tileGrid.forEachTileCoordParentTileRange(tileCoord, findLoadedTiles);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,30 +93,11 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
|
|||||||
var tilesToDrawByZ = {};
|
var tilesToDrawByZ = {};
|
||||||
tilesToDrawByZ[z] = {};
|
tilesToDrawByZ[z] = {};
|
||||||
|
|
||||||
var findInterimTiles = function(z, tileRange) {
|
function isLoaded(tile) {
|
||||||
// FIXME this could be more efficient about filling partial holes
|
return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED;
|
||||||
var fullyCovered = true;
|
}
|
||||||
var tile, tileCoord, tileCoordKey, x, y;
|
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
|
||||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
tilesToDrawByZ, isLoaded);
|
||||||
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 allTilesLoaded = true;
|
var allTilesLoaded = true;
|
||||||
var tile, tileCenter, tileCoord, tileState, x, y;
|
var tile, tileCenter, tileCoord, tileState, x, y;
|
||||||
@@ -144,7 +125,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
|
|||||||
}
|
}
|
||||||
|
|
||||||
allTilesLoaded = false;
|
allTilesLoaded = false;
|
||||||
tileGrid.forEachTileCoordParentTileRange(tileCoord, findInterimTiles);
|
tileGrid.forEachTileCoordParentTileRange(tileCoord, findLoadedTiles);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -365,32 +365,12 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
|
|||||||
var tilesToDrawByZ = {};
|
var tilesToDrawByZ = {};
|
||||||
tilesToDrawByZ[z] = {};
|
tilesToDrawByZ[z] = {};
|
||||||
|
|
||||||
var findInterimTiles = function(z, tileRange) {
|
function isLoaded(tile) {
|
||||||
// FIXME this could be more efficient about filling partial holes
|
return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED &&
|
||||||
var fullyCovered = true;
|
mapRenderer.isTileTextureLoaded(tile);
|
||||||
var tile, tileCoord, tileCoordKey, x, y;
|
}
|
||||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
|
||||||
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
tilesToDrawByZ, isLoaded);
|
||||||
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 tilesToLoad = new goog.structs.PriorityQueue();
|
var tilesToLoad = new goog.structs.PriorityQueue();
|
||||||
|
|
||||||
@@ -428,7 +408,7 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
|
|||||||
}
|
}
|
||||||
|
|
||||||
allTilesLoaded = false;
|
allTilesLoaded = false;
|
||||||
tileGrid.forEachTileCoordParentTileRange(tileCoord, findInterimTiles);
|
tileGrid.forEachTileCoordParentTileRange(tileCoord, findLoadedTiles);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,46 @@ ol.source.TileSource.prototype.canExpireCache = goog.functions.FALSE;
|
|||||||
ol.source.TileSource.prototype.expireCache = goog.abstractMethod;
|
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 {function(ol.Tile): boolean} isLoaded A function to determine if a
|
||||||
|
* tile 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.
|
||||||
|
*/
|
||||||
|
ol.source.TileSource.prototype.findLoadedTiles = function(loadedTilesByZ,
|
||||||
|
isLoaded, 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]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tile = this.getTile(tileCoord);
|
||||||
|
if (isLoaded(tile)) {
|
||||||
|
if (!loadedTilesByZ[z]) {
|
||||||
|
loadedTilesByZ[z] = {};
|
||||||
|
}
|
||||||
|
loadedTilesByZ[z][tileCoordKey] = tile;
|
||||||
|
} else {
|
||||||
|
fullyCovered = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fullyCovered;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,238 @@
|
|||||||
|
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() {
|
||||||
|
|
||||||
|
function isLoaded(tile) {
|
||||||
|
return !goog.isNull(tile) && tile.getState() === ol.TileState.LOADED;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, isLoaded, 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/0': true,
|
||||||
|
'1/0/0': true
|
||||||
|
});
|
||||||
|
|
||||||
|
var loadedTilesByZ = {};
|
||||||
|
var grid = source.getTileGrid();
|
||||||
|
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 0);
|
||||||
|
source.findLoadedTiles(loadedTilesByZ, isLoaded, 0, range);
|
||||||
|
var keys = goog.object.getKeys(loadedTilesByZ);
|
||||||
|
expect(keys.length).toBe(1);
|
||||||
|
var tile = loadedTilesByZ['0']['0/0/0'];
|
||||||
|
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/0': true,
|
||||||
|
'1/0/0': true
|
||||||
|
});
|
||||||
|
|
||||||
|
var loadedTilesByZ = {};
|
||||||
|
var grid = source.getTileGrid();
|
||||||
|
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1);
|
||||||
|
source.findLoadedTiles(loadedTilesByZ, isLoaded, 1, range);
|
||||||
|
var keys = goog.object.getKeys(loadedTilesByZ);
|
||||||
|
expect(keys.length).toBe(1);
|
||||||
|
var tile = loadedTilesByZ['1']['1/0/0'];
|
||||||
|
expect(tile).toBeA(ol.Tile);
|
||||||
|
expect(tile.state).toBe(ol.TileState.LOADED);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true when all tiles are already loaded', function() {
|
||||||
|
// a source with no loaded tiles
|
||||||
|
var source = new ol.test.source.MockTileSource({
|
||||||
|
'1/0/0': true,
|
||||||
|
'1/0/1': true,
|
||||||
|
'1/1/0': true,
|
||||||
|
'1/1/1': true
|
||||||
|
});
|
||||||
|
|
||||||
|
var loadedTilesByZ = {};
|
||||||
|
var grid = source.getTileGrid();
|
||||||
|
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1);
|
||||||
|
var loaded = source.findLoadedTiles(loadedTilesByZ, isLoaded, 1, range);
|
||||||
|
expect(loaded).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns true when all tiles are already loaded (part 2)', function() {
|
||||||
|
// a source with no loaded tiles
|
||||||
|
var source = new ol.test.source.MockTileSource({});
|
||||||
|
|
||||||
|
var loadedTilesByZ = {
|
||||||
|
'1': {
|
||||||
|
'1/0/0': true,
|
||||||
|
'1/0/1': true,
|
||||||
|
'1/1/0': true,
|
||||||
|
'1/1/1': true,
|
||||||
|
'1/1/2': true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var grid = source.getTileGrid();
|
||||||
|
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1);
|
||||||
|
var loaded = source.findLoadedTiles(loadedTilesByZ, isLoaded, 1, range);
|
||||||
|
expect(loaded).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false when all tiles are already loaded', function() {
|
||||||
|
// a source with no loaded tiles
|
||||||
|
var source = new ol.test.source.MockTileSource({
|
||||||
|
'1/0/0': true,
|
||||||
|
'1/0/1': true,
|
||||||
|
'1/1/0': true,
|
||||||
|
'1/1/1': false
|
||||||
|
});
|
||||||
|
|
||||||
|
var loadedTilesByZ = {};
|
||||||
|
var grid = source.getTileGrid();
|
||||||
|
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1);
|
||||||
|
var loaded = source.findLoadedTiles(loadedTilesByZ, isLoaded, 1, range);
|
||||||
|
expect(loaded).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false when all tiles are already loaded (part 2)', function() {
|
||||||
|
// a source with no loaded tiles
|
||||||
|
var source = new ol.test.source.MockTileSource({});
|
||||||
|
|
||||||
|
var loadedTilesByZ = {
|
||||||
|
'1': {
|
||||||
|
'1/0/0': true,
|
||||||
|
'1/0/1': true,
|
||||||
|
'1/1/0': true,
|
||||||
|
'1/1/1': false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var grid = source.getTileGrid();
|
||||||
|
var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1);
|
||||||
|
var loaded = source.findLoadedTiles(loadedTilesByZ, isLoaded, 1, range);
|
||||||
|
expect(loaded).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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/0': 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, -1));
|
||||||
|
expect(tile).toBeA(ol.Tile);
|
||||||
|
expect(tile.state).toBe(ol.TileState.IDLE);
|
||||||
|
|
||||||
|
// check another loaded tile
|
||||||
|
tile = source.getTile(new ol.TileCoord(1, 0, 0));
|
||||||
|
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');
|
||||||
Reference in New Issue
Block a user