From ddf993f0c902b922675f8c17d225b78c7a4bea16 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Mon, 18 Feb 2013 14:18:08 -0700 Subject: [PATCH 1/5] 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. --- .../canvas/canvastilelayerrenderer.js | 28 +-- src/ol/renderer/dom/domtilelayerrenderer.js | 28 +-- .../renderer/webgl/webgltilelayerrenderer.js | 30 +--- src/ol/source/tilesource.js | 39 +++++ test/spec/ol/source/tilesource.test.js | 163 ++++++++++++++++++ 5 files changed, 211 insertions(+), 77 deletions(-) create mode 100644 test/spec/ol/source/tilesource.test.js diff --git a/src/ol/renderer/canvas/canvastilelayerrenderer.js b/src/ol/renderer/canvas/canvastilelayerrenderer.js index 02e5e904ff..3917e7f3e0 100644 --- a/src/ol/renderer/canvas/canvastilelayerrenderer.js +++ b/src/ol/renderer/canvas/canvastilelayerrenderer.js @@ -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); } } diff --git a/src/ol/renderer/dom/domtilelayerrenderer.js b/src/ol/renderer/dom/domtilelayerrenderer.js index 094d6a3009..d6521d9386 100644 --- a/src/ol/renderer/dom/domtilelayerrenderer.js +++ b/src/ol/renderer/dom/domtilelayerrenderer.js @@ -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); } diff --git a/src/ol/renderer/webgl/webgltilelayerrenderer.js b/src/ol/renderer/webgl/webgltilelayerrenderer.js index 360f8f8d82..fe29c6cf00 100644 --- a/src/ol/renderer/webgl/webgltilelayerrenderer.js +++ b/src/ol/renderer/webgl/webgltilelayerrenderer.js @@ -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); } diff --git a/src/ol/source/tilesource.js b/src/ol/source/tilesource.js index 93e083eef8..bb7d3b0d96 100644 --- a/src/ol/source/tilesource.js +++ b/src/ol/source/tilesource.js @@ -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.>} 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 */ diff --git a/test/spec/ol/source/tilesource.test.js b/test/spec/ol/source/tilesource.test.js new file mode 100644 index 0000000000..9d51c59b04 --- /dev/null +++ b/test/spec/ol/source/tilesource.test.js @@ -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.} 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.} + * @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'); From 6aa4e99fe536e50c4c2f3ed47cf930f4233bc3dd Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Mon, 18 Feb 2013 14:51:39 -0700 Subject: [PATCH 2/5] Fix return from findLoadedTiles Previously, the findInterimTiles method was returning undefined if the min x/y coord for a tile range was already in the lookup. The return says it indicates whether all tiles for the given z are loaded. This change corrects the return. This change also reveals a misunderstanding of the tile range returned by `getTileRangeForExtentAndZ`. The previous findInterimTiles method was treating max values as inclusive. This is intuitive. It looks like the method returns a range where max values are exclusive. --- src/ol/source/tilesource.js | 3 +- test/spec/ol/source/tilesource.test.js | 107 ++++++++++++++++++++++--- 2 files changed, 100 insertions(+), 10 deletions(-) diff --git a/src/ol/source/tilesource.js b/src/ol/source/tilesource.js index bb7d3b0d96..98e6720dc8 100644 --- a/src/ol/source/tilesource.js +++ b/src/ol/source/tilesource.js @@ -75,12 +75,13 @@ ol.source.TileSource.prototype.findLoadedTiles = function(loadedTilesByZ, z, // FIXME this could be more efficient about filling partial holes var fullyCovered = true; var tile, tileCoord, tileCoordKey, x, y; + // TODO: tile range is misunderstood (inclusive or not?) 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 + continue; } tile = this.getTile(tileCoord); if (!goog.isNull(tile) && tile.getState() == ol.TileState.LOADED) { diff --git a/test/spec/ol/source/tilesource.test.js b/test/spec/ol/source/tilesource.test.js index 9d51c59b04..f6639eaa69 100644 --- a/test/spec/ol/source/tilesource.test.js +++ b/test/spec/ol/source/tilesource.test.js @@ -30,8 +30,8 @@ describe('ol.source.TileSource', function() { 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 + '0/0/0': true, + '1/0/0': true }); var loadedTilesByZ = {}; @@ -40,7 +40,7 @@ describe('ol.source.TileSource', function() { source.findLoadedTiles(loadedTilesByZ, 0, range); var keys = goog.object.getKeys(loadedTilesByZ); expect(keys.length).toBe(1); - var tile = loadedTilesByZ['0']['0/0/-1']; + var tile = loadedTilesByZ['0']['0/0/0']; expect(tile).toBeA(ol.Tile); expect(tile.state).toBe(ol.TileState.LOADED); }); @@ -48,8 +48,8 @@ describe('ol.source.TileSource', function() { 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 + '0/0/0': true, + '1/0/0': true }); var loadedTilesByZ = {}; @@ -58,11 +58,100 @@ describe('ol.source.TileSource', function() { source.findLoadedTiles(loadedTilesByZ, 1, range); var keys = goog.object.getKeys(loadedTilesByZ); expect(keys.length).toBe(1); - var tile = loadedTilesByZ['1']['1/0/-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({ + // TODO: tile range is misunderstood + '1/0/0': true, + '1/0/1': true, + '1/0/2': true, + '1/1/0': true, + '1/1/1': true, + '1/1/2': true, + '1/2/0': true, + '1/2/1': true, + '1/2/2': true, + }); + + var loadedTilesByZ = {}; + var grid = source.getTileGrid(); + var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1); + var allLoaded = source.findLoadedTiles(loadedTilesByZ, 1, range); + expect(allLoaded).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/0/2': true, + '1/1/0': true, + '1/1/1': true, + '1/1/2': true, + '1/2/0': true, + '1/2/1': true, + '1/2/2': true, + } + }; + var grid = source.getTileGrid(); + var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1); + var allLoaded = source.findLoadedTiles(loadedTilesByZ, 1, range); + expect(allLoaded).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/0/2': true, + '1/1/0': true, + '1/1/1': false, + '1/1/2': true, + '1/2/0': true, + '1/2/1': true, + '1/2/2': true, + }); + + var loadedTilesByZ = {}; + var grid = source.getTileGrid(); + var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1); + var allLoaded = source.findLoadedTiles(loadedTilesByZ, 1, range); + expect(allLoaded).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/0/2': true, + '1/1/0': true, + '1/1/1': false, + '1/1/2': true, + '1/2/0': true, + '1/2/1': true, + '1/2/2': true, + } + }; + var grid = source.getTileGrid(); + var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1); + var allLoaded = source.findLoadedTiles(loadedTilesByZ, 1, range); + expect(allLoaded).toBe(false); + }); + }); }); @@ -80,7 +169,7 @@ ol.test.source.MockTileSource = function(loaded) { var tileGrid = new ol.tilegrid.TileGrid({ resolutions: [360 / 256, 180 / 256, 90 / 256, 45 / 256], extent: extent, - origin: new ol.Coordinate(-180, 180), + origin: new ol.Coordinate(-180, -180), tileSize: new ol.Size(256, 256) }); @@ -127,7 +216,7 @@ describe('ol.test.source.MockTileSource', 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 + '1/0/0': true }); var tile; @@ -142,7 +231,7 @@ describe('ol.test.source.MockTileSource', function() { expect(tile.state).toBe(ol.TileState.IDLE); // check another loaded tile - tile = source.getTile(new ol.TileCoord(1, 0, -1)); + tile = source.getTile(new ol.TileCoord(1, 0, 0)); expect(tile).toBeA(ol.Tile); expect(tile.state).toBe(ol.TileState.LOADED); From e8c50c729009a4329caeaceef6dab9e3cbc9c610 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Mon, 18 Feb 2013 15:11:53 -0700 Subject: [PATCH 3/5] Passing tests --- test/spec/ol/source/tilesource.test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/spec/ol/source/tilesource.test.js b/test/spec/ol/source/tilesource.test.js index f6639eaa69..5cb401d51f 100644 --- a/test/spec/ol/source/tilesource.test.js +++ b/test/spec/ol/source/tilesource.test.js @@ -75,7 +75,7 @@ describe('ol.source.TileSource', function() { '1/1/2': true, '1/2/0': true, '1/2/1': true, - '1/2/2': true, + '1/2/2': true }); var loadedTilesByZ = {}; @@ -99,7 +99,7 @@ describe('ol.source.TileSource', function() { '1/1/2': true, '1/2/0': true, '1/2/1': true, - '1/2/2': true, + '1/2/2': true } }; var grid = source.getTileGrid(); @@ -119,7 +119,7 @@ describe('ol.source.TileSource', function() { '1/1/2': true, '1/2/0': true, '1/2/1': true, - '1/2/2': true, + '1/2/2': true }); var loadedTilesByZ = {}; @@ -143,7 +143,7 @@ describe('ol.source.TileSource', function() { '1/1/2': true, '1/2/0': true, '1/2/1': true, - '1/2/2': true, + '1/2/2': true } }; var grid = source.getTileGrid(); @@ -226,7 +226,7 @@ describe('ol.test.source.MockTileSource', function() { expect(tile.state).toBe(ol.TileState.LOADED); // check a tile that is not loaded - tile = source.getTile(new ol.TileCoord(1, 0, 0)); + tile = source.getTile(new ol.TileCoord(1, 0, -1)); expect(tile).toBeA(ol.Tile); expect(tile.state).toBe(ol.TileState.IDLE); From 1b984ac06c9d97893c400d03f66a260d1aa64a7a Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Tue, 19 Feb 2013 09:54:41 -0700 Subject: [PATCH 4/5] Fewer tiles to be considered fully loaded With 797dba2cdbabd8fa0a78c32a7b3bfcdbff29eea8 we no longer have to load excess tiles to consider an extent fully loaded. --- test/spec/ol/source/tilesource.test.js | 30 ++++++-------------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/test/spec/ol/source/tilesource.test.js b/test/spec/ol/source/tilesource.test.js index 5cb401d51f..a02603a9ae 100644 --- a/test/spec/ol/source/tilesource.test.js +++ b/test/spec/ol/source/tilesource.test.js @@ -66,16 +66,10 @@ describe('ol.source.TileSource', function() { it('returns true when all tiles are already loaded', function() { // a source with no loaded tiles var source = new ol.test.source.MockTileSource({ - // TODO: tile range is misunderstood '1/0/0': true, '1/0/1': true, - '1/0/2': true, '1/1/0': true, - '1/1/1': true, - '1/1/2': true, - '1/2/0': true, - '1/2/1': true, - '1/2/2': true + '1/1/1': true }); var loadedTilesByZ = {}; @@ -93,13 +87,9 @@ describe('ol.source.TileSource', function() { '1': { '1/0/0': true, '1/0/1': true, - '1/0/2': true, '1/1/0': true, '1/1/1': true, - '1/1/2': true, - '1/2/0': true, - '1/2/1': true, - '1/2/2': true + '1/1/2': true } }; var grid = source.getTileGrid(); @@ -113,13 +103,8 @@ describe('ol.source.TileSource', function() { var source = new ol.test.source.MockTileSource({ '1/0/0': true, '1/0/1': true, - '1/0/2': true, '1/1/0': true, - '1/1/1': false, - '1/1/2': true, - '1/2/0': true, - '1/2/1': true, - '1/2/2': true + '1/1/1': false }); var loadedTilesByZ = {}; @@ -137,13 +122,8 @@ describe('ol.source.TileSource', function() { '1': { '1/0/0': true, '1/0/1': true, - '1/0/2': true, '1/1/0': true, - '1/1/1': false, - '1/1/2': true, - '1/2/0': true, - '1/2/1': true, - '1/2/2': true + '1/1/1': false } }; var grid = source.getTileGrid(); @@ -156,6 +136,8 @@ describe('ol.source.TileSource', function() { }); + + /** * Tile source for tests that uses a EPSG:4326 based grid with 4 resolutions and * 256x256 tiles. From 80dc7b5bf7980ca211b617cf9e84cd1a913baf9a Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Tue, 19 Feb 2013 12:13:58 -0700 Subject: [PATCH 5/5] Accept custom isLoaded method in findLoadedTiles method --- .../canvas/canvastilelayerrenderer.js | 5 +++- src/ol/renderer/dom/domtilelayerrenderer.js | 5 +++- .../renderer/webgl/webgltilelayerrenderer.js | 6 ++++- src/ol/source/tilesource.js | 10 +++---- test/spec/ol/source/tilesource.test.js | 26 +++++++++++-------- 5 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/ol/renderer/canvas/canvastilelayerrenderer.js b/src/ol/renderer/canvas/canvastilelayerrenderer.js index 3917e7f3e0..e7c48f044c 100644 --- a/src/ol/renderer/canvas/canvastilelayerrenderer.js +++ b/src/ol/renderer/canvas/canvastilelayerrenderer.js @@ -129,8 +129,11 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame = var tilesToDrawByZ = {}; tilesToDrawByZ[z] = {}; + function isLoaded(tile) { + return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED; + } var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource, - tilesToDrawByZ); + tilesToDrawByZ, isLoaded); var allTilesLoaded = true; var tile, tileCenter, tileCoord, tileState, x, y; diff --git a/src/ol/renderer/dom/domtilelayerrenderer.js b/src/ol/renderer/dom/domtilelayerrenderer.js index d6521d9386..faeb67d47d 100644 --- a/src/ol/renderer/dom/domtilelayerrenderer.js +++ b/src/ol/renderer/dom/domtilelayerrenderer.js @@ -93,8 +93,11 @@ ol.renderer.dom.TileLayer.prototype.renderFrame = var tilesToDrawByZ = {}; tilesToDrawByZ[z] = {}; + function isLoaded(tile) { + return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED; + } var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource, - tilesToDrawByZ); + tilesToDrawByZ, isLoaded); var allTilesLoaded = true; var tile, tileCenter, tileCoord, tileState, x, y; diff --git a/src/ol/renderer/webgl/webgltilelayerrenderer.js b/src/ol/renderer/webgl/webgltilelayerrenderer.js index fe29c6cf00..53405ca10a 100644 --- a/src/ol/renderer/webgl/webgltilelayerrenderer.js +++ b/src/ol/renderer/webgl/webgltilelayerrenderer.js @@ -365,8 +365,12 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame = var tilesToDrawByZ = {}; tilesToDrawByZ[z] = {}; + function isLoaded(tile) { + return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED && + mapRenderer.isTileTextureLoaded(tile); + } var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource, - tilesToDrawByZ); + tilesToDrawByZ, isLoaded); var tilesToLoad = new goog.structs.PriorityQueue(); diff --git a/src/ol/source/tilesource.js b/src/ol/source/tilesource.js index 98e6720dc8..e9666dada6 100644 --- a/src/ol/source/tilesource.js +++ b/src/ol/source/tilesource.js @@ -8,7 +8,6 @@ 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'); @@ -66,16 +65,17 @@ ol.source.TileSource.prototype.expireCache = goog.abstractMethod; * * @param {Object.>} 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, z, - tileRange) { +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; - // TODO: tile range is misunderstood (inclusive or not?) for (x = tileRange.minX; x <= tileRange.maxX; ++x) { for (y = tileRange.minY; y <= tileRange.maxY; ++y) { tileCoord = new ol.TileCoord(z, x, y); @@ -84,7 +84,7 @@ ol.source.TileSource.prototype.findLoadedTiles = function(loadedTilesByZ, z, continue; } tile = this.getTile(tileCoord); - if (!goog.isNull(tile) && tile.getState() == ol.TileState.LOADED) { + if (isLoaded(tile)) { if (!loadedTilesByZ[z]) { loadedTilesByZ[z] = {}; } diff --git a/test/spec/ol/source/tilesource.test.js b/test/spec/ol/source/tilesource.test.js index a02603a9ae..3ee01e99a6 100644 --- a/test/spec/ol/source/tilesource.test.js +++ b/test/spec/ol/source/tilesource.test.js @@ -14,6 +14,10 @@ describe('ol.source.TileSource', function() { 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({}); @@ -21,7 +25,7 @@ describe('ol.source.TileSource', function() { var loadedTilesByZ = {}; var grid = source.getTileGrid(); var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 3); - source.findLoadedTiles(loadedTilesByZ, 3, range); + source.findLoadedTiles(loadedTilesByZ, isLoaded, 3, range); var keys = goog.object.getKeys(loadedTilesByZ); expect(keys.length).toBe(0); @@ -37,7 +41,7 @@ describe('ol.source.TileSource', function() { var loadedTilesByZ = {}; var grid = source.getTileGrid(); var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 0); - source.findLoadedTiles(loadedTilesByZ, 0, range); + source.findLoadedTiles(loadedTilesByZ, isLoaded, 0, range); var keys = goog.object.getKeys(loadedTilesByZ); expect(keys.length).toBe(1); var tile = loadedTilesByZ['0']['0/0/0']; @@ -55,7 +59,7 @@ describe('ol.source.TileSource', function() { var loadedTilesByZ = {}; var grid = source.getTileGrid(); var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1); - source.findLoadedTiles(loadedTilesByZ, 1, range); + source.findLoadedTiles(loadedTilesByZ, isLoaded, 1, range); var keys = goog.object.getKeys(loadedTilesByZ); expect(keys.length).toBe(1); var tile = loadedTilesByZ['1']['1/0/0']; @@ -75,8 +79,8 @@ describe('ol.source.TileSource', function() { var loadedTilesByZ = {}; var grid = source.getTileGrid(); var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1); - var allLoaded = source.findLoadedTiles(loadedTilesByZ, 1, range); - expect(allLoaded).toBe(true); + var loaded = source.findLoadedTiles(loadedTilesByZ, isLoaded, 1, range); + expect(loaded).toBe(true); }); it('returns true when all tiles are already loaded (part 2)', function() { @@ -94,8 +98,8 @@ describe('ol.source.TileSource', function() { }; var grid = source.getTileGrid(); var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1); - var allLoaded = source.findLoadedTiles(loadedTilesByZ, 1, range); - expect(allLoaded).toBe(true); + var loaded = source.findLoadedTiles(loadedTilesByZ, isLoaded, 1, range); + expect(loaded).toBe(true); }); it('returns false when all tiles are already loaded', function() { @@ -110,8 +114,8 @@ describe('ol.source.TileSource', function() { var loadedTilesByZ = {}; var grid = source.getTileGrid(); var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1); - var allLoaded = source.findLoadedTiles(loadedTilesByZ, 1, range); - expect(allLoaded).toBe(false); + var loaded = source.findLoadedTiles(loadedTilesByZ, isLoaded, 1, range); + expect(loaded).toBe(false); }); it('returns false when all tiles are already loaded (part 2)', function() { @@ -128,8 +132,8 @@ describe('ol.source.TileSource', function() { }; var grid = source.getTileGrid(); var range = grid.getTileRangeForExtentAndZ(source.getExtent(), 1); - var allLoaded = source.findLoadedTiles(loadedTilesByZ, 1, range); - expect(allLoaded).toBe(false); + var loaded = source.findLoadedTiles(loadedTilesByZ, isLoaded, 1, range); + expect(loaded).toBe(false); }); });