Merge pull request #126 from openlayers/tilequeue
Tile queue requires optimizing
This commit is contained in:
@@ -69,7 +69,7 @@ ol.control.Attribution.prototype.handleMapPostrender = function(mapEvent) {
|
|||||||
if (goog.isNull(frameState)) {
|
if (goog.isNull(frameState)) {
|
||||||
this.updateElement_(null);
|
this.updateElement_(null);
|
||||||
} else {
|
} else {
|
||||||
this.updateElement_(frameState.tileUsage);
|
this.updateElement_(frameState.usedTiles);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,12 +94,12 @@ ol.control.Attribution.prototype.setMap = function(map) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {?Object.<string, Object.<string, ol.TileRange>>} tileUsage Tile
|
* @param {?Object.<string, Object.<string, ol.TileRange>>} usedTiles Used
|
||||||
* usage.
|
* tiles.
|
||||||
*/
|
*/
|
||||||
ol.control.Attribution.prototype.updateElement_ = function(tileUsage) {
|
ol.control.Attribution.prototype.updateElement_ = function(usedTiles) {
|
||||||
|
|
||||||
if (goog.isNull(tileUsage)) {
|
if (goog.isNull(usedTiles)) {
|
||||||
if (this.renderedVisible_) {
|
if (this.renderedVisible_) {
|
||||||
goog.style.showElement(this.element, false);
|
goog.style.showElement(this.element, false);
|
||||||
this.renderedVisible_ = false;
|
this.renderedVisible_ = false;
|
||||||
@@ -136,14 +136,14 @@ ol.control.Attribution.prototype.updateElement_ = function(tileUsage) {
|
|||||||
var attributions = {};
|
var attributions = {};
|
||||||
var i, tileRanges, tileSource, tileSourceAttribution,
|
var i, tileRanges, tileSource, tileSourceAttribution,
|
||||||
tileSourceAttributionKey, tileSourceAttributions, tileSourceKey, z;
|
tileSourceAttributionKey, tileSourceAttributions, tileSourceKey, z;
|
||||||
for (tileSourceKey in tileUsage) {
|
for (tileSourceKey in usedTiles) {
|
||||||
goog.asserts.assert(tileSourceKey in tileSources);
|
goog.asserts.assert(tileSourceKey in tileSources);
|
||||||
tileSource = tileSources[tileSourceKey];
|
tileSource = tileSources[tileSourceKey];
|
||||||
tileSourceAttributions = tileSource.getAttributions();
|
tileSourceAttributions = tileSource.getAttributions();
|
||||||
if (goog.isNull(tileSourceAttributions)) {
|
if (goog.isNull(tileSourceAttributions)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tileRanges = tileUsage[tileSourceKey];
|
tileRanges = usedTiles[tileSourceKey];
|
||||||
for (i = 0; i < tileSourceAttributions.length; ++i) {
|
for (i = 0; i < tileSourceAttributions.length; ++i) {
|
||||||
tileSourceAttribution = tileSourceAttributions[i];
|
tileSourceAttribution = tileSourceAttributions[i];
|
||||||
tileSourceAttributionKey = goog.getUid(tileSourceAttribution).toString();
|
tileSourceAttributionKey = goog.getUid(tileSourceAttribution).toString();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// FIXME add view3DState
|
// FIXME add view3DState
|
||||||
|
// FIXME factor out common code between usedTiles and wantedTiles
|
||||||
|
|
||||||
goog.provide('ol.FrameState');
|
goog.provide('ol.FrameState');
|
||||||
goog.provide('ol.PostRenderFunction');
|
goog.provide('ol.PostRenderFunction');
|
||||||
@@ -26,10 +27,11 @@ goog.require('ol.layer.LayerState');
|
|||||||
* postRenderFunctions: Array.<ol.PostRenderFunction>,
|
* postRenderFunctions: Array.<ol.PostRenderFunction>,
|
||||||
* size: ol.Size,
|
* size: ol.Size,
|
||||||
* tileQueue: ol.TileQueue,
|
* tileQueue: ol.TileQueue,
|
||||||
* tileUsage: Object.<string, Object.<string, ol.TileRange>>,
|
|
||||||
* time: number,
|
* time: number,
|
||||||
|
* usedTiles: Object.<string, Object.<string, ol.TileRange>>,
|
||||||
* view2DState: ol.View2DState,
|
* view2DState: ol.View2DState,
|
||||||
* viewHints: Array.<number>}}
|
* viewHints: Array.<number>,
|
||||||
|
* wantedTiles: Object.<string, Object.<string, ol.TileRange>>}}
|
||||||
*/
|
*/
|
||||||
ol.FrameState;
|
ol.FrameState;
|
||||||
|
|
||||||
|
|||||||
@@ -453,19 +453,24 @@ ol.Map.prototype.getOverlayContainer = function() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ol.Tile} tile Tile.
|
* @param {ol.Tile} tile Tile.
|
||||||
|
* @param {string} tileSourceKey Tile source key.
|
||||||
* @param {ol.Coordinate} tileCenter Tile center.
|
* @param {ol.Coordinate} tileCenter Tile center.
|
||||||
* @param {number} tileResolution Tile resolution.
|
* @return {number} Tile priority.
|
||||||
* @return {number|undefined} Tile priority.
|
|
||||||
*/
|
*/
|
||||||
ol.Map.prototype.getTilePriority = function(tile, tileCenter, tileResolution) {
|
ol.Map.prototype.getTilePriority = function(tile, tileSourceKey, tileCenter) {
|
||||||
if (goog.isNull(this.frameState_)) {
|
var frameState = this.frameState_;
|
||||||
return undefined;
|
if (goog.isNull(frameState) || !(tileSourceKey in frameState.wantedTiles)) {
|
||||||
} else {
|
return ol.TileQueue.DROP;
|
||||||
var center = this.frameState_.view2DState.center;
|
|
||||||
var deltaX = tileCenter.x - center.x;
|
|
||||||
var deltaY = tileCenter.y - center.y;
|
|
||||||
return Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution;
|
|
||||||
}
|
}
|
||||||
|
var zKey = tile.tileCoord.z.toString();
|
||||||
|
if (!(zKey in frameState.wantedTiles[tileSourceKey]) ||
|
||||||
|
!frameState.wantedTiles[tileSourceKey][zKey].contains(tile.tileCoord)) {
|
||||||
|
return ol.TileQueue.DROP;
|
||||||
|
}
|
||||||
|
var center = frameState.view2DState.center;
|
||||||
|
var deltaX = tileCenter.x - center.x;
|
||||||
|
var deltaY = tileCenter.y - center.y;
|
||||||
|
return deltaX * deltaX + deltaY * deltaY;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -627,10 +632,11 @@ ol.Map.prototype.renderFrame_ = function(time) {
|
|||||||
postRenderFunctions: [],
|
postRenderFunctions: [],
|
||||||
size: size,
|
size: size,
|
||||||
tileQueue: this.tileQueue_,
|
tileQueue: this.tileQueue_,
|
||||||
tileUsage: {},
|
time: time,
|
||||||
|
usedTiles: {},
|
||||||
view2DState: view2DState,
|
view2DState: view2DState,
|
||||||
viewHints: viewHints,
|
viewHints: viewHints,
|
||||||
time: time
|
wantedTiles: {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -664,6 +670,8 @@ ol.Map.prototype.renderFrame_ = function(time) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.renderer_.renderFrame(frameState);
|
this.renderer_.renderFrame(frameState);
|
||||||
|
this.frameState_ = frameState;
|
||||||
|
this.dirty_ = false;
|
||||||
|
|
||||||
if (!goog.isNull(frameState)) {
|
if (!goog.isNull(frameState)) {
|
||||||
if (frameState.animate) {
|
if (frameState.animate) {
|
||||||
@@ -672,8 +680,6 @@ ol.Map.prototype.renderFrame_ = function(time) {
|
|||||||
Array.prototype.push.apply(
|
Array.prototype.push.apply(
|
||||||
this.postRenderFunctions_, frameState.postRenderFunctions);
|
this.postRenderFunctions_, frameState.postRenderFunctions);
|
||||||
}
|
}
|
||||||
this.frameState_ = frameState;
|
|
||||||
this.dirty_ = false;
|
|
||||||
|
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new ol.MapEvent(ol.MapEventType.POSTRENDER, this, frameState));
|
new ol.MapEvent(ol.MapEventType.POSTRENDER, this, frameState));
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
|
|||||||
|
|
||||||
var tileLayer = this.getTileLayer();
|
var tileLayer = this.getTileLayer();
|
||||||
var tileSource = tileLayer.getTileSource();
|
var tileSource = tileLayer.getTileSource();
|
||||||
|
var tileSourceKey = goog.getUid(tileSource).toString();
|
||||||
var tileGrid = tileSource.getTileGrid();
|
var tileGrid = tileSource.getTileGrid();
|
||||||
var tileSize = tileGrid.getTileSize();
|
var tileSize = tileGrid.getTileSize();
|
||||||
var z = tileGrid.getZForResolution(view2DState.resolution);
|
var z = tileGrid.getZForResolution(view2DState.resolution);
|
||||||
@@ -165,7 +166,7 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
|
|||||||
tileState = tile.getState();
|
tileState = tile.getState();
|
||||||
if (tileState == ol.TileState.IDLE) {
|
if (tileState == ol.TileState.IDLE) {
|
||||||
tileCenter = tileGrid.getTileCoordCenter(tileCoord);
|
tileCenter = tileGrid.getTileCoordCenter(tileCoord);
|
||||||
frameState.tileQueue.enqueue(tile, tileCenter, tileResolution);
|
frameState.tileQueue.enqueue(tile, tileSourceKey, tileCenter);
|
||||||
} else if (tileState == ol.TileState.LOADED) {
|
} else if (tileState == ol.TileState.LOADED) {
|
||||||
tilesToDrawByZ[z][tileCoord.toString()] = tile;
|
tilesToDrawByZ[z][tileCoord.toString()] = tile;
|
||||||
continue;
|
continue;
|
||||||
@@ -213,9 +214,10 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
|
|||||||
|
|
||||||
if (!allTilesLoaded) {
|
if (!allTilesLoaded) {
|
||||||
frameState.animate = true;
|
frameState.animate = true;
|
||||||
|
this.updateWantedTiles(frameState.wantedTiles, tileSource, z, tileRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateTileUsage(frameState.tileUsage, tileSource, z, tileRange);
|
this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
|
||||||
|
|
||||||
var transform = this.transform_;
|
var transform = this.transform_;
|
||||||
goog.vec.Mat4.makeIdentity(transform);
|
goog.vec.Mat4.makeIdentity(transform);
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
|
|||||||
|
|
||||||
var tileLayer = this.getTileLayer();
|
var tileLayer = this.getTileLayer();
|
||||||
var tileSource = tileLayer.getTileSource();
|
var tileSource = tileLayer.getTileSource();
|
||||||
|
var tileSourceKey = goog.getUid(tileSource).toString();
|
||||||
var tileGrid = tileSource.getTileGrid();
|
var tileGrid = tileSource.getTileGrid();
|
||||||
var z = tileGrid.getZForResolution(view2DState.resolution);
|
var z = tileGrid.getZForResolution(view2DState.resolution);
|
||||||
var tileResolution = tileGrid.getResolution(z);
|
var tileResolution = tileGrid.getResolution(z);
|
||||||
@@ -132,7 +133,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
|
|||||||
tileState = tile.getState();
|
tileState = tile.getState();
|
||||||
if (tileState == ol.TileState.IDLE) {
|
if (tileState == ol.TileState.IDLE) {
|
||||||
tileCenter = tileGrid.getTileCoordCenter(tileCoord);
|
tileCenter = tileGrid.getTileCoordCenter(tileCoord);
|
||||||
frameState.tileQueue.enqueue(tile, tileCenter, tileResolution);
|
frameState.tileQueue.enqueue(tile, tileSourceKey, tileCenter);
|
||||||
} else if (tileState == ol.TileState.LOADED) {
|
} else if (tileState == ol.TileState.LOADED) {
|
||||||
tilesToDrawByZ[z][tileCoord.toString()] = tile;
|
tilesToDrawByZ[z][tileCoord.toString()] = tile;
|
||||||
continue;
|
continue;
|
||||||
@@ -234,9 +235,10 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
|
|||||||
|
|
||||||
if (!allTilesLoaded) {
|
if (!allTilesLoaded) {
|
||||||
frameState.animate = true;
|
frameState.animate = true;
|
||||||
|
this.updateWantedTiles(frameState.wantedTiles, tileSource, z, tileRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateTileUsage(frameState.tileUsage, tileSource, z, tileRange);
|
this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -130,24 +130,49 @@ ol.renderer.Layer.prototype.handleLayerVisibleChange = goog.nullFunction;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @protected
|
* @protected
|
||||||
* @param {Object.<string, Object.<string, ol.TileRange>>} tileUsage Tile usage.
|
* @param {Object.<string, Object.<string, ol.TileRange>>} usedTiles Used tiles.
|
||||||
* @param {ol.source.Source} source Source.
|
* @param {ol.source.Source} source Source.
|
||||||
* @param {number} z Z.
|
* @param {number} z Z.
|
||||||
* @param {ol.TileRange} tileRange Tile range.
|
* @param {ol.TileRange} tileRange Tile range.
|
||||||
*/
|
*/
|
||||||
ol.renderer.Layer.prototype.updateTileUsage =
|
ol.renderer.Layer.prototype.updateUsedTiles =
|
||||||
function(tileUsage, source, z, tileRange) {
|
function(usedTiles, source, z, tileRange) {
|
||||||
// FIXME should we use tilesToDrawByZ instead?
|
// FIXME should we use tilesToDrawByZ instead?
|
||||||
var sourceKey = goog.getUid(source).toString();
|
var sourceKey = goog.getUid(source).toString();
|
||||||
var zKey = z.toString();
|
var zKey = z.toString();
|
||||||
if (sourceKey in tileUsage) {
|
if (sourceKey in usedTiles) {
|
||||||
if (z in tileUsage[sourceKey]) {
|
if (zKey in usedTiles[sourceKey]) {
|
||||||
tileUsage[sourceKey][zKey].extend(tileRange);
|
usedTiles[sourceKey][zKey].extend(tileRange);
|
||||||
} else {
|
} else {
|
||||||
tileUsage[sourceKey][zKey] = tileRange;
|
usedTiles[sourceKey][zKey] = tileRange;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tileUsage[sourceKey] = {};
|
usedTiles[sourceKey] = {};
|
||||||
tileUsage[sourceKey][zKey] = tileRange;
|
usedTiles[sourceKey][zKey] = tileRange;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @protected
|
||||||
|
* @param {Object.<string, Object.<string, ol.TileRange>>} wantedTiles Wanted
|
||||||
|
* tile ranges.
|
||||||
|
* @param {ol.source.Source} source Source.
|
||||||
|
* @param {number} z Z.
|
||||||
|
* @param {ol.TileRange} tileRange Tile range.
|
||||||
|
*/
|
||||||
|
ol.renderer.Layer.prototype.updateWantedTiles =
|
||||||
|
function(wantedTiles, source, z, tileRange) {
|
||||||
|
var sourceKey = goog.getUid(source).toString();
|
||||||
|
var zKey = z.toString();
|
||||||
|
if (sourceKey in wantedTiles) {
|
||||||
|
if (zKey in wantedTiles[sourceKey]) {
|
||||||
|
wantedTiles[sourceKey][zKey].extend(tileRange);
|
||||||
|
} else {
|
||||||
|
wantedTiles[sourceKey][zKey] = tileRange;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wantedTiles[sourceKey] = {};
|
||||||
|
wantedTiles[sourceKey][zKey] = tileRange;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -270,6 +270,7 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
|
|||||||
|
|
||||||
var tileLayer = this.getTileLayer();
|
var tileLayer = this.getTileLayer();
|
||||||
var tileSource = tileLayer.getTileSource();
|
var tileSource = tileLayer.getTileSource();
|
||||||
|
var tileSourceKey = goog.getUid(tileSource).toString();
|
||||||
var tileGrid = tileSource.getTileGrid();
|
var tileGrid = tileSource.getTileGrid();
|
||||||
var z = tileGrid.getZForResolution(view2DState.resolution);
|
var z = tileGrid.getZForResolution(view2DState.resolution);
|
||||||
var tileResolution = tileGrid.getResolution(z);
|
var tileResolution = tileGrid.getResolution(z);
|
||||||
@@ -392,7 +393,7 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
|
|||||||
tileState = tile.getState();
|
tileState = tile.getState();
|
||||||
if (tileState == ol.TileState.IDLE) {
|
if (tileState == ol.TileState.IDLE) {
|
||||||
tileCenter = tileGrid.getTileCoordCenter(tileCoord);
|
tileCenter = tileGrid.getTileCoordCenter(tileCoord);
|
||||||
frameState.tileQueue.enqueue(tile, tileCenter, tileResolution);
|
frameState.tileQueue.enqueue(tile, tileSourceKey, tileCenter);
|
||||||
} else if (tileState == ol.TileState.LOADED) {
|
} else if (tileState == ol.TileState.LOADED) {
|
||||||
if (mapRenderer.isTileTextureLoaded(tile)) {
|
if (mapRenderer.isTileTextureLoaded(tile)) {
|
||||||
tilesToDrawByZ[z][tileCoord.toString()] = tile;
|
tilesToDrawByZ[z][tileCoord.toString()] = tile;
|
||||||
@@ -455,11 +456,12 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
|
|||||||
this.renderedTileRange_ = null;
|
this.renderedTileRange_ = null;
|
||||||
this.renderedFramebufferExtent_ = null;
|
this.renderedFramebufferExtent_ = null;
|
||||||
frameState.animate = true;
|
frameState.animate = true;
|
||||||
|
this.updateWantedTiles(frameState.wantedTiles, tileSource, z, tileRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateTileUsage(frameState.tileUsage, tileSource, z, tileRange);
|
this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
|
||||||
|
|
||||||
goog.vec.Mat4.makeIdentity(this.matrix_);
|
goog.vec.Mat4.makeIdentity(this.matrix_);
|
||||||
goog.vec.Mat4.translate(this.matrix_,
|
goog.vec.Mat4.translate(this.matrix_,
|
||||||
|
|||||||
@@ -3,14 +3,24 @@ goog.provide('ol.TileQueue');
|
|||||||
|
|
||||||
goog.require('goog.events');
|
goog.require('goog.events');
|
||||||
goog.require('goog.events.EventType');
|
goog.require('goog.events.EventType');
|
||||||
goog.require('goog.structs.PriorityQueue');
|
|
||||||
goog.require('ol.Coordinate');
|
goog.require('ol.Coordinate');
|
||||||
goog.require('ol.Tile');
|
goog.require('ol.Tile');
|
||||||
goog.require('ol.TileState');
|
goog.require('ol.TileState');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {function(ol.Tile, ol.Coordinate, number): (number|undefined)}
|
* Tile Queue.
|
||||||
|
*
|
||||||
|
* The implementation is inspired from the Closure Library's Heap
|
||||||
|
* class and Python's heapq module.
|
||||||
|
*
|
||||||
|
* http://closure-library.googlecode.com/svn/docs/closure_goog_structs_heap.js.source.html
|
||||||
|
* http://hg.python.org/cpython/file/2.7/Lib/heapq.py
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {function(ol.Tile, string, ol.Coordinate): number}
|
||||||
*/
|
*/
|
||||||
ol.TilePriorityFunction;
|
ol.TilePriorityFunction;
|
||||||
|
|
||||||
@@ -43,9 +53,9 @@ ol.TileQueue = function(tilePriorityFunction) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {goog.structs.PriorityQueue}
|
* @type {Array.<Array.<*>>}
|
||||||
*/
|
*/
|
||||||
this.queue_ = new goog.structs.PriorityQueue();
|
this.heap_ = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@@ -57,23 +67,49 @@ ol.TileQueue = function(tilePriorityFunction) {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ol.Tile} tile Tile.
|
* @const {number}
|
||||||
* @param {ol.Coordinate} tileCenter Tile center.
|
|
||||||
* @param {number} tileResolution Tile resolution.
|
|
||||||
*/
|
*/
|
||||||
ol.TileQueue.prototype.enqueue =
|
ol.TileQueue.DROP = Infinity;
|
||||||
function(tile, tileCenter, tileResolution) {
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove and return the highest-priority tile. O(logn).
|
||||||
|
* @private
|
||||||
|
* @return {ol.Tile} Tile.
|
||||||
|
*/
|
||||||
|
ol.TileQueue.prototype.dequeue_ = function() {
|
||||||
|
var heap = this.heap_;
|
||||||
|
goog.asserts.assert(heap.length > 0);
|
||||||
|
var tile = /** @type {ol.Tile} */ (heap[0][1]);
|
||||||
|
if (heap.length == 1) {
|
||||||
|
heap.length = 0;
|
||||||
|
} else {
|
||||||
|
heap[0] = heap.pop();
|
||||||
|
this.siftUp_(0);
|
||||||
|
}
|
||||||
|
var tileKey = tile.getKey();
|
||||||
|
delete this.queuedTileKeys_[tileKey];
|
||||||
|
return tile;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue a tile. O(logn).
|
||||||
|
* @param {ol.Tile} tile Tile.
|
||||||
|
* @param {string} tileSourceKey Tile source key.
|
||||||
|
* @param {ol.Coordinate} tileCenter Tile center.
|
||||||
|
*/
|
||||||
|
ol.TileQueue.prototype.enqueue = function(tile, tileSourceKey, tileCenter) {
|
||||||
if (tile.getState() != ol.TileState.IDLE) {
|
if (tile.getState() != ol.TileState.IDLE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var tileKey = tile.getKey();
|
var tileKey = tile.getKey();
|
||||||
if (!(tileKey in this.queuedTileKeys_)) {
|
if (!(tileKey in this.queuedTileKeys_)) {
|
||||||
var priority = this.tilePriorityFunction_(tile, tileCenter, tileResolution);
|
var priority = this.tilePriorityFunction_(tile, tileSourceKey, tileCenter);
|
||||||
if (goog.isDef(priority)) {
|
if (priority != ol.TileQueue.DROP) {
|
||||||
this.queue_.enqueue(priority, arguments);
|
this.heap_.push([priority, tile, tileSourceKey, tileCenter]);
|
||||||
this.queuedTileKeys_[tileKey] = true;
|
this.queuedTileKeys_[tileKey] = true;
|
||||||
} else {
|
this.siftDown_(0, this.heap_.length - 1);
|
||||||
// FIXME fire drop event?
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -87,15 +123,57 @@ ol.TileQueue.prototype.handleTileChange = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the index of the left child of the node at the given index.
|
||||||
|
* @param {number} index The index of the node to get the left child for.
|
||||||
|
* @return {number} The index of the left child.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.TileQueue.prototype.getLeftChildIndex_ = function(index) {
|
||||||
|
return index * 2 + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the index of the right child of the node at the given index.
|
||||||
|
* @param {number} index The index of the node to get the right child for.
|
||||||
|
* @return {number} The index of the right child.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.TileQueue.prototype.getRightChildIndex_ = function(index) {
|
||||||
|
return index * 2 + 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the index of the parent of the node at the given index.
|
||||||
|
* @param {number} index The index of the node to get the parent for.
|
||||||
|
* @return {number} The index of the parent.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.TileQueue.prototype.getParentIndex_ = function(index) {
|
||||||
|
return (index - 1) >> 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make _heap a heap. O(n).
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.TileQueue.prototype.heapify_ = function() {
|
||||||
|
for (var i = (this.heap_.length >> 1) - 1; i >= 0; i--) {
|
||||||
|
this.siftUp_(i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FIXME empty description for jsdoc
|
* FIXME empty description for jsdoc
|
||||||
*/
|
*/
|
||||||
ol.TileQueue.prototype.loadMoreTiles = function() {
|
ol.TileQueue.prototype.loadMoreTiles = function() {
|
||||||
var tile, tileKey;
|
var tile;
|
||||||
while (!this.queue_.isEmpty() && this.tilesLoading_ < this.maxTilesLoading_) {
|
while (this.heap_.length > 0 && this.tilesLoading_ < this.maxTilesLoading_) {
|
||||||
tile = (/** @type {Array} */ (this.queue_.dequeue()))[0];
|
tile = /** @type {ol.Tile} */ (this.dequeue_());
|
||||||
tileKey = tile.getKey();
|
|
||||||
delete this.queuedTileKeys_[tileKey];
|
|
||||||
goog.events.listen(tile, goog.events.EventType.CHANGE,
|
goog.events.listen(tile, goog.events.EventType.CHANGE,
|
||||||
this.handleTileChange, false, this);
|
this.handleTileChange, false, this);
|
||||||
tile.load();
|
tile.load();
|
||||||
@@ -104,17 +182,75 @@ ol.TileQueue.prototype.loadMoreTiles = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} index The index of the node to move down.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.TileQueue.prototype.siftUp_ = function(index) {
|
||||||
|
var heap = this.heap_;
|
||||||
|
var count = heap.length;
|
||||||
|
var node = heap[index];
|
||||||
|
var startIndex = index;
|
||||||
|
|
||||||
|
while (index < (count >> 1)) {
|
||||||
|
var lIndex = this.getLeftChildIndex_(index);
|
||||||
|
var rIndex = this.getRightChildIndex_(index);
|
||||||
|
|
||||||
|
var smallerChildIndex = rIndex < count &&
|
||||||
|
heap[rIndex][0] < heap[lIndex][0] ?
|
||||||
|
rIndex : lIndex;
|
||||||
|
|
||||||
|
heap[index] = heap[smallerChildIndex];
|
||||||
|
index = smallerChildIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
heap[index] = node;
|
||||||
|
this.siftDown_(startIndex, index);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} startIndex The index of the root.
|
||||||
|
* @param {number} index The index of the node to move up.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ol.TileQueue.prototype.siftDown_ = function(startIndex, index) {
|
||||||
|
var heap = this.heap_;
|
||||||
|
var node = heap[index];
|
||||||
|
|
||||||
|
while (index > startIndex) {
|
||||||
|
var parentIndex = this.getParentIndex_(index);
|
||||||
|
if (heap[parentIndex][0] > node[0]) {
|
||||||
|
heap[index] = heap[parentIndex];
|
||||||
|
index = parentIndex;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
heap[index] = node;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FIXME empty description for jsdoc
|
* FIXME empty description for jsdoc
|
||||||
*/
|
*/
|
||||||
ol.TileQueue.prototype.reprioritize = function() {
|
ol.TileQueue.prototype.reprioritize = function() {
|
||||||
if (!this.queue_.isEmpty()) {
|
var heap = this.heap_;
|
||||||
var values = /** @type {Array.<Array>} */ (this.queue_.getValues());
|
var i, n = 0, node, priority, tile, tileCenter, tileKey, tileSourceKey;
|
||||||
this.queue_.clear();
|
for (i = 0; i < heap.length; ++i) {
|
||||||
this.queuedTileKeys_ = {};
|
node = heap[i];
|
||||||
var i;
|
tile = /** @type {ol.Tile} */ (node[1]);
|
||||||
for (i = 0; i < values.length; ++i) {
|
tileSourceKey = /** @type {string} */ (node[2]);
|
||||||
this.enqueue.apply(this, values[i]);
|
tileCenter = /** @type {ol.Coordinate} */ (node[3]);
|
||||||
|
priority = this.tilePriorityFunction_(tile, tileSourceKey, tileCenter);
|
||||||
|
if (priority == ol.TileQueue.DROP) {
|
||||||
|
tileKey = tile.getKey();
|
||||||
|
delete this.queuedTileKeys_[tileKey];
|
||||||
|
} else {
|
||||||
|
node[0] = priority;
|
||||||
|
heap[n++] = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
heap.length = n;
|
||||||
|
this.heapify_();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -84,6 +84,7 @@
|
|||||||
<script type="text/javascript" src="spec/ol/source/xyz.test.js"></script>
|
<script type="text/javascript" src="spec/ol/source/xyz.test.js"></script>
|
||||||
<script type="text/javascript" src="spec/ol/tilecoord.test.js"></script>
|
<script type="text/javascript" src="spec/ol/tilecoord.test.js"></script>
|
||||||
<script type="text/javascript" src="spec/ol/tilegrid.test.js"></script>
|
<script type="text/javascript" src="spec/ol/tilegrid.test.js"></script>
|
||||||
|
<script type="text/javascript" src="spec/ol/tilequeue.test.js"></script>
|
||||||
<script type="text/javascript" src="spec/ol/tilerange.test.js"></script>
|
<script type="text/javascript" src="spec/ol/tilerange.test.js"></script>
|
||||||
<script type="text/javascript" src="spec/ol/tileurlfunction.test.js"></script>
|
<script type="text/javascript" src="spec/ol/tileurlfunction.test.js"></script>
|
||||||
<script type="text/javascript" src="spec/ol/control/control.test.js"></script>
|
<script type="text/javascript" src="spec/ol/control/control.test.js"></script>
|
||||||
|
|||||||
68
test/spec/ol/tilequeue.test.js
Normal file
68
test/spec/ol/tilequeue.test.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
describe('ol.TileQueue', function() {
|
||||||
|
|
||||||
|
// is the tile queue's array a heap?
|
||||||
|
function isHeap(tq) {
|
||||||
|
var heap = tq.heap_;
|
||||||
|
var i;
|
||||||
|
var key;
|
||||||
|
var leftKey;
|
||||||
|
var rightKey;
|
||||||
|
for (i = 0; i < (heap.length >> 1) - 1; i++) {
|
||||||
|
key = heap[i][0];
|
||||||
|
leftKey = heap[tq.getLeftChildIndex_(i)][0];
|
||||||
|
rightKey = heap[tq.getRightChildIndex_(i)][0];
|
||||||
|
if (leftKey < key || rightKey < key) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addRandomPriorityTiles(tq, num) {
|
||||||
|
var i, tile, priority;
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
tile = new ol.Tile();
|
||||||
|
priority = Math.floor(Math.random() * 100);
|
||||||
|
tq.heap_.push([priority, tile, '', new ol.Coordinate(0, 0)]);
|
||||||
|
tq.queuedTileKeys_[tile.getKey()] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('heapify', function() {
|
||||||
|
it('does convert an arbitrary array into a heap', function() {
|
||||||
|
|
||||||
|
var tq = new ol.TileQueue(function() {});
|
||||||
|
addRandomPriorityTiles(tq, 100);
|
||||||
|
|
||||||
|
tq.heapify_();
|
||||||
|
expect(isHeap(tq)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('reprioritize', function() {
|
||||||
|
it('does reprioritize the array', function() {
|
||||||
|
|
||||||
|
var tq = new ol.TileQueue(function() {});
|
||||||
|
addRandomPriorityTiles(tq, 100);
|
||||||
|
|
||||||
|
tq.heapify_();
|
||||||
|
|
||||||
|
// now reprioritize, changing the priority of 50 tiles and removing the
|
||||||
|
// rest
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
tq.tilePriorityFunction_ = function() {
|
||||||
|
if ((i++) % 2 === 0) {
|
||||||
|
return ol.TileQueue.DROP;
|
||||||
|
}
|
||||||
|
return Math.floor(Math.random() * 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
tq.reprioritize();
|
||||||
|
expect(tq.heap_.length).toEqual(50);
|
||||||
|
expect(isHeap(tq)).toBeTruthy();
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
Reference in New Issue
Block a user