Store symbol sizes by tile

The reason for this change is that symbolSizes and maxSymbolSize
on the instance will be wrong as soon as the resolution changes
and cached tiles are used. It turned out that the approach used
now has several advantages: smaller symbolSizes objects, no need
to merge symbolSizes objects, and cache management for free (no
risk of memory leaks). Note that the symbolSizes and
maxSymbolSize for each tile are not strictly tile specific -
they represent the rendering pass that created the tile. This
has no negative side effects, and it has the advantage that
there is not a single additional loop needed to create these
structures.
This commit is contained in:
ahocevar
2013-05-16 09:57:26 +02:00
parent 037e44e084
commit 4e7ffc2711

View File

@@ -70,6 +70,10 @@ ol.renderer.canvas.VectorLayer = function(mapRenderer, layer) {
this.sketchTransform_ = goog.vec.Mat4.createNumber();
/**
* Tile cache entries are arrays. The first item in each array is the tile
* itself, the second are the symbol sizes, and the third is the maximum
* symbol size.
*
* @private
* @type {ol.TileCache}
*/
@@ -137,18 +141,6 @@ ol.renderer.canvas.VectorLayer = function(mapRenderer, layer) {
*/
this.tileGrid_ = null;
/**
* @type {Object.<number, Array.<number>>}
* @private
*/
this.symbolSizes_ = {};
/**
* @type {Array.<number>}
* @private
*/
this.maxSymbolSize_ = [0, 0];
/**
* @private
* @type {function()}
@@ -173,8 +165,6 @@ ol.renderer.canvas.VectorLayer.prototype.expireTiles_ = function(opt_extent) {
// TODO: implement this
}
this.tileCache_.clear();
this.symbolSizes_ = {};
this.maxSymbolSize_ = [0, 0];
};
@@ -213,48 +203,56 @@ ol.renderer.canvas.VectorLayer.prototype.getTransform = function() {
ol.renderer.canvas.VectorLayer.prototype.getFeatureInfoForPixel =
function(pixel, success) {
var map = this.getMap();
var hw = this.maxSymbolSize_[0] / 2;
var hh = this.maxSymbolSize_[1] / 2;
var location = map.getCoordinateFromPixel(pixel);
var locationMin = [location[0] - hw, location[1] - hh];
var locationMax = [location[0] + hw, location[1] + hh];
var locationBbox = ol.extent.boundingExtent([locationMin, locationMax]);
var filter = new ol.filter.Extent(locationBbox);
var candidates = this.getLayer().getFeatures(filter);
var result = [];
var candidate, geom, type, symbolBounds, symbolSize, halfWidth, halfHeight,
coordinates, j;
for (var i = 0, ii = candidates.length; i < ii; ++i) {
candidate = candidates[i];
geom = candidate.getGeometry();
type = geom.getType();
if (type === ol.geom.GeometryType.POINT ||
type === ol.geom.GeometryType.MULTIPOINT) {
// For points, check if the pixel coordinate is inside the candidate's
// symbol
symbolSize = this.symbolSizes_[goog.getUid(candidate)];
halfWidth = symbolSize[0] / 2;
halfHeight = symbolSize[1] / 2;
symbolBounds = ol.extent.boundingExtent(
[[location[0] - halfWidth, location[1] - halfHeight],
[location[0] + halfWidth, location[1] + halfHeight]]);
coordinates = geom.getCoordinates();
if (ol.extent.containsCoordinate(symbolBounds, coordinates)) {
result.push(candidate);
}
} else if (goog.isFunction(geom.containsCoordinate)) {
// For polygons, check if the pixel location is inside the polygon
if (geom.containsCoordinate(location)) {
result.push(candidate);
}
} else if (goog.isFunction(geom.distanceFromCoordinate)) {
// For lines, check if the distance to the pixel location is
// within the rendered line width
if (2 * geom.distanceFromCoordinate(location) <=
this.symbolSizes_[goog.getUid(candidate)][0]) {
result.push(candidate);
var location = map.getCoordinateFromPixel(pixel);
var tileCoord = this.tileGrid_.getTileCoordForCoordAndResolution(
location, this.getMap().getView().getView2D().getResolution());
var key = tileCoord.toString();
if (this.tileCache_.containsKey(key)) {
var cachedTile = this.tileCache_.get(key);
var symbolSizes = cachedTile[1];
var maxSymbolSize = cachedTile[2];
var hw = maxSymbolSize[0] / 2;
var hh = maxSymbolSize[1] / 2;
var locationMin = [location[0] - hw, location[1] - hh];
var locationMax = [location[0] + hw, location[1] + hh];
var locationBbox = ol.extent.boundingExtent([locationMin, locationMax]);
var filter = new ol.filter.Extent(locationBbox);
var candidates = this.getLayer().getFeatures(filter);
var candidate, geom, type, symbolBounds, symbolSize, halfWidth, halfHeight,
coordinates, j;
for (var i = 0, ii = candidates.length; i < ii; ++i) {
candidate = candidates[i];
geom = candidate.getGeometry();
type = geom.getType();
if (type === ol.geom.GeometryType.POINT ||
type === ol.geom.GeometryType.MULTIPOINT) {
// For points, check if the pixel coordinate is inside the candidate's
// symbol
symbolSize = symbolSizes[goog.getUid(candidate)];
halfWidth = symbolSize[0] / 2;
halfHeight = symbolSize[1] / 2;
symbolBounds = ol.extent.boundingExtent(
[[location[0] - halfWidth, location[1] - halfHeight],
[location[0] + halfWidth, location[1] + halfHeight]]);
coordinates = geom.getCoordinates();
if (ol.extent.containsCoordinate(symbolBounds, coordinates)) {
result.push(candidate);
}
} else if (goog.isFunction(geom.containsCoordinate)) {
// For polygons, check if the pixel location is inside the polygon
if (geom.containsCoordinate(location)) {
result.push(candidate);
}
} else if (goog.isFunction(geom.distanceFromCoordinate)) {
// For lines, check if the distance to the pixel location is
// within the rendered line width
if (2 * geom.distanceFromCoordinate(location) <=
symbolSizes[goog.getUid(candidate)][0]) {
result.push(candidate);
}
}
}
}
@@ -421,7 +419,6 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
}
}
var renderedNew = false;
renderByGeometryType:
for (type in featuresToRender) {
groups = layer.groupFeaturesBySymbolizerLiteral(featuresToRender[type]);
@@ -434,31 +431,26 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
if (deferred) {
break renderByGeometryType;
}
renderedNew = true;
}
}
if (renderedNew) {
goog.object.extend(this.symbolSizes_,
sketchCanvasRenderer.getSymbolSizes());
this.maxSymbolSize_ = sketchCanvasRenderer.getMaxSymbolSize();
}
if (!deferred) {
goog.object.extend(tilesToRender, tilesOnSketchCanvas);
}
var symbolSizes = sketchCanvasRenderer.getSymbolSizes(),
maxSymbolSize = sketchCanvasRenderer.getMaxSymbolSize();
for (key in tilesToRender) {
tileCoord = tilesToRender[key];
if (this.tileCache_.containsKey(key)) {
tile = /** @type {HTMLCanvasElement} */ (this.tileCache_.get(key));
tile = /** @type {HTMLCanvasElement} */ (this.tileCache_.get(key)[0]);
} else {
tile = /** @type {HTMLCanvasElement} */
(this.tileArchetype_.cloneNode(false));
tile.getContext('2d').drawImage(sketchCanvas,
(tileRange.minX - tileCoord.x) * tileSize.width,
(tileCoord.y - tileRange.maxY) * tileSize.height);
this.tileCache_.set(key, tile);
this.tileCache_.set(key, [tile, symbolSizes, maxSymbolSize]);
}
finalContext.drawImage(tile,
tileSize.width * (tileCoord.x - tileRange.minX),