Refactor ol.TileQueue to extend ol.structs.PriorityQueue
This commit is contained in:
@@ -55,6 +55,7 @@ goog.require('ol.renderer.dom.Map');
|
||||
goog.require('ol.renderer.dom.SUPPORTED');
|
||||
goog.require('ol.renderer.webgl.Map');
|
||||
goog.require('ol.renderer.webgl.SUPPORTED');
|
||||
goog.require('ol.structs.PriorityQueue');
|
||||
|
||||
|
||||
/**
|
||||
@@ -493,11 +494,11 @@ ol.Map.prototype.getTilePriority =
|
||||
// are outside the visible extent.
|
||||
var frameState = this.frameState_;
|
||||
if (goog.isNull(frameState) || !(tileSourceKey in frameState.wantedTiles)) {
|
||||
return ol.TileQueue.DROP;
|
||||
return ol.structs.PriorityQueue.DROP;
|
||||
}
|
||||
var coordKey = tile.tileCoord.toString();
|
||||
if (!frameState.wantedTiles[tileSourceKey][coordKey]) {
|
||||
return ol.TileQueue.DROP;
|
||||
return ol.structs.PriorityQueue.DROP;
|
||||
}
|
||||
// Prioritize tiles closest to the focus or center. The + 1 helps to
|
||||
// prioritize tiles at higher zoom levels over tiles at lower zoom levels,
|
||||
|
||||
@@ -307,7 +307,7 @@ ol.renderer.Layer.prototype.manageTilePyramid =
|
||||
}
|
||||
var wantedTiles = frameState.wantedTiles[tileSourceKey];
|
||||
var tileQueue = frameState.tileQueue;
|
||||
var tile, tileCenter, tileRange, tileResolution, x, y, z;
|
||||
var tile, 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);
|
||||
@@ -317,9 +317,11 @@ ol.renderer.Layer.prototype.manageTilePyramid =
|
||||
if (ol.PREEMPTIVELY_LOAD_LOW_RESOLUTION_TILES || z == currentZ) {
|
||||
tile = tileSource.getTile(z, x, y, tileGrid, projection);
|
||||
if (tile.getState() == ol.TileState.IDLE) {
|
||||
tileCenter = tileGrid.getTileCoordCenter(tile.tileCoord);
|
||||
wantedTiles[tile.tileCoord.toString()] = true;
|
||||
tileQueue.enqueue(tile, tileSourceKey, tileCenter, tileResolution);
|
||||
if (!tileQueue.isKeyQueued(tile.getKey())) {
|
||||
tileQueue.enqueue([tile, tileSourceKey,
|
||||
tileGrid.getTileCoordCenter(tile.tileCoord), tileResolution]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tileSource.useTile(z, x, y);
|
||||
|
||||
@@ -5,18 +5,7 @@ goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.Tile');
|
||||
goog.require('ol.TileState');
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
goog.require('ol.structs.PriorityQueue');
|
||||
|
||||
|
||||
/**
|
||||
@@ -28,6 +17,7 @@ ol.TilePriorityFunction;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.structs.PriorityQueue}
|
||||
* @param {ol.TilePriorityFunction} tilePriorityFunction
|
||||
* Tile priority function.
|
||||
* @param {Function} tileChangeCallback
|
||||
@@ -35,11 +25,22 @@ ol.TilePriorityFunction;
|
||||
*/
|
||||
ol.TileQueue = function(tilePriorityFunction, tileChangeCallback) {
|
||||
|
||||
goog.base(
|
||||
this,
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.TilePriorityFunction}
|
||||
* @param {Array} element Element.
|
||||
* @return {number} Priority.
|
||||
*/
|
||||
this.tilePriorityFunction_ = tilePriorityFunction;
|
||||
function(element) {
|
||||
return tilePriorityFunction.apply(null, element);
|
||||
},
|
||||
/**
|
||||
* @param {Array} element Element.
|
||||
* @return {string} Key.
|
||||
*/
|
||||
function(element) {
|
||||
return /** @type {ol.Tile} */ (element[0]).getKey();
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -59,72 +60,8 @@ ol.TileQueue = function(tilePriorityFunction, tileChangeCallback) {
|
||||
*/
|
||||
this.tilesLoading_ = 0;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<Array.<*>>}
|
||||
*/
|
||||
this.heap_ = [];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, boolean>}
|
||||
*/
|
||||
this.queuedTileKeys_ = {};
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @const {number}
|
||||
*/
|
||||
ol.TileQueue.DROP = Infinity;
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @param {number} tileResolution Tile resolution.
|
||||
*/
|
||||
ol.TileQueue.prototype.enqueue = function(
|
||||
tile, tileSourceKey, tileCenter, tileResolution) {
|
||||
if (tile.getState() != ol.TileState.IDLE) {
|
||||
return;
|
||||
}
|
||||
var tileKey = tile.getKey();
|
||||
if (!(tileKey in this.queuedTileKeys_)) {
|
||||
var priority = this.tilePriorityFunction_(
|
||||
tile, tileSourceKey, tileCenter, tileResolution);
|
||||
if (priority != ol.TileQueue.DROP) {
|
||||
this.heap_.push(
|
||||
[priority, tile, tileSourceKey, tileCenter, tileResolution]);
|
||||
this.queuedTileKeys_[tileKey] = true;
|
||||
this.siftDown_(0, this.heap_.length - 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
goog.inherits(ol.TileQueue, ol.structs.PriorityQueue);
|
||||
|
||||
|
||||
/**
|
||||
@@ -136,137 +73,16 @@ 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
|
||||
*/
|
||||
ol.TileQueue.prototype.loadMoreTiles = function() {
|
||||
var tile;
|
||||
while (this.heap_.length > 0 && this.tilesLoading_ < this.maxTilesLoading_) {
|
||||
tile = /** @type {ol.Tile} */ (this.dequeue_());
|
||||
while (!this.isEmpty() && this.tilesLoading_ < this.maxTilesLoading_) {
|
||||
tile = /** @type {ol.Tile} */ (this.dequeue()[0]);
|
||||
goog.events.listenOnce(tile, goog.events.EventType.CHANGE,
|
||||
this.handleTileChange, false, this);
|
||||
tile.load();
|
||||
++this.tilesLoading_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
ol.TileQueue.prototype.reprioritize = function() {
|
||||
var heap = this.heap_;
|
||||
var i, n = 0, node, priority;
|
||||
var tile, tileCenter, tileKey, tileResolution, tileSourceKey;
|
||||
for (i = 0; i < heap.length; ++i) {
|
||||
node = heap[i];
|
||||
tile = /** @type {ol.Tile} */ (node[1]);
|
||||
tileSourceKey = /** @type {string} */ (node[2]);
|
||||
tileCenter = /** @type {ol.Coordinate} */ (node[3]);
|
||||
tileResolution = /** @type {number} */ (node[4]);
|
||||
priority = this.tilePriorityFunction_(
|
||||
tile, tileSourceKey, tileCenter, tileResolution);
|
||||
if (priority == ol.TileQueue.DROP) {
|
||||
tileKey = tile.getKey();
|
||||
delete this.queuedTileKeys_[tileKey];
|
||||
} else {
|
||||
node[0] = priority;
|
||||
heap[n++] = node;
|
||||
}
|
||||
}
|
||||
heap.length = n;
|
||||
this.heapify_();
|
||||
};
|
||||
|
||||
@@ -4,15 +4,15 @@ describe('ol.TileQueue', function() {
|
||||
|
||||
// is the tile queue's array a heap?
|
||||
function isHeap(tq) {
|
||||
var heap = tq.heap_;
|
||||
var priorities = tq.priorities_;
|
||||
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];
|
||||
for (i = 0; i < (priorities.length >> 1) - 1; i++) {
|
||||
key = priorities[i];
|
||||
leftKey = priorities[tq.getLeftChildIndex_(i)];
|
||||
rightKey = priorities[tq.getRightChildIndex_(i)];
|
||||
if (leftKey < key || rightKey < key) {
|
||||
return false;
|
||||
}
|
||||
@@ -25,8 +25,9 @@ describe('ol.TileQueue', function() {
|
||||
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;
|
||||
tq.elements_.push([tile, '', new ol.Coordinate(0, 0)]);
|
||||
tq.priorities_.push(priority);
|
||||
tq.queuedElements_[tile.getKey()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,15 +54,16 @@ describe('ol.TileQueue', function() {
|
||||
// rest
|
||||
|
||||
var i = 0;
|
||||
tq.tilePriorityFunction_ = function() {
|
||||
tq.priorityFunction_ = function() {
|
||||
if ((i++) % 2 === 0) {
|
||||
return ol.TileQueue.DROP;
|
||||
return ol.structs.PriorityQueue.DROP;
|
||||
}
|
||||
return Math.floor(Math.random() * 100);
|
||||
};
|
||||
|
||||
tq.reprioritize();
|
||||
expect(tq.heap_.length).to.eql(50);
|
||||
expect(tq.elements_.length).to.eql(50);
|
||||
expect(tq.priorities_.length).to.eql(50);
|
||||
expect(isHeap(tq)).to.be.ok();
|
||||
|
||||
});
|
||||
@@ -71,3 +73,4 @@ describe('ol.TileQueue', function() {
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.Tile');
|
||||
goog.require('ol.TileQueue');
|
||||
goog.require('ol.structs.PriorityQueue');
|
||||
|
||||
Reference in New Issue
Block a user