No deltas for tile bounds/position calculation

Now we also do not use deltas for shiftRow and shiftColumn. Some
refactoring was done so we do not need different calculateGridLayout
methods for layers with top-left and bottom-left tile origin.

TODO: With this commit, ArcGisCache and KaMap layers are broken.
This commit is contained in:
ahocevar
2012-10-11 21:22:52 +02:00
parent d4f011d00c
commit c5bb52d93f
5 changed files with 104 additions and 159 deletions

View File

@@ -270,6 +270,14 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* tile that could not be loaded. * tile that could not be loaded.
*/ */
/**
* Property: gridLayout
* {Object} containing properties tilelon, tilelat, tileoffsetlat,
* tileoffsetlat, tileoffsetx, tileoffsety and optional startrow, startcol
* for grid layouts where absolute tile bounds calculation is possible.
*/
gridLayout: null,
/** /**
* Constructor: OpenLayers.Layer.Grid * Constructor: OpenLayers.Layer.Grid
* Create a new grid layer * Create a new grid layer
@@ -363,6 +371,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
} }
this.grid = []; this.grid = [];
this.gridResolution = null; this.gridResolution = null;
this.gridLayout = null;
} }
}, },
@@ -866,9 +875,8 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* resolution - {Number} * resolution - {Number}
* *
* Returns: * Returns:
* {Object} containing properties tilelon, tilelat, tileoffsetlat, * {Object} Object containing properties tilelon, tilelat, tileoffsetx,
* tileoffsetlat, tileoffsetx, tileoffsety and optional startrow, startcol * tileoffsety, startcol, startrow
* for grid layouts where absolute tile bounds calculation is possible.
*/ */
calculateGridLayout: function(bounds, origin, resolution) { calculateGridLayout: function(bounds, origin, resolution) {
var tilelon = resolution * this.tileSize.w; var tilelon = resolution * this.tileSize.w;
@@ -884,17 +892,16 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
var tilecol = Math.floor(offsetlon/tilelon) - this.buffer; var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
var tilecolremain = offsetlon/tilelon - tilecol; var tilecolremain = offsetlon/tilelon - tilecol;
var tileoffsetx = -tilecolremain * tileSize.w; var tileoffsetx = -tilecolremain * tileSize.w;
var tileoffsetlon = origin.lon + tilecol * tilelon;
var offsetlat = bounds.top - (origin.lat + tilelat); var rowSign = this.tileOriginCorner.substr(0, 1) === "t" ? 1 : -1;
var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
var offsetlat = rowSign * (origin.lat - bounds.top + tilelat);
var tilerow = Math[~rowSign ? 'floor' : 'ceil'](offsetlat/tilelat) - this.buffer * rowSign;
var tilerowremain = tilerow - offsetlat/tilelat; var tilerowremain = tilerow - offsetlat/tilelat;
var tileoffsety = -tilerowremain * tileSize.h; var tileoffsety = rowSign * tilerowremain * tileSize.h;
var tileoffsetlat = origin.lat + tilerow * tilelat;
return { return {
tilelon: tilelon, tilelat: tilelat, tilelon: tilelon, tilelat: tilelat,
tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
tileoffsetx: tileoffsetx, tileoffsety: tileoffsety, tileoffsetx: tileoffsetx, tileoffsety: tileoffsety,
startcol: tilecol, startrow: tilerow startcol: tilecol, startrow: tilerow
}; };
@@ -927,6 +934,30 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
return origin; return origin;
}, },
/**
* Method: getTileBoundsForGridIndex
*
* Parameters:
* row - {Number} The row of the grid
* col - {Number} The column of the grid
*
* Returns:
* {<OpenLayers.Bounds>} The bounds for the tile at (row, col)
*/
getTileBoundsForGridIndex: function(row, col) {
var origin = this.getTileOrigin();
var tileLayout = this.gridLayout;
var tilelon = tileLayout.tilelon;
var tilelat = tileLayout.tilelat;
var rowSign = this.tileOriginCorner.substr(0, 1) === "t" ? 1 : -1;
var minX = origin.lon + (tileLayout.startcol + col) * tilelon;
var minY = origin.lat - (tileLayout.startrow + row * rowSign) * tilelat * rowSign;
return new OpenLayers.Bounds(
minX, minY,
minX + tilelon, minY + tilelat
);
},
/** /**
* Method: initGriddedTiles * Method: initGriddedTiles
* *
@@ -956,50 +987,34 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
2 * this.buffer + 1; 2 * this.buffer + 1;
var tileLayout = this.calculateGridLayout(bounds, origin, serverResolution); var tileLayout = this.calculateGridLayout(bounds, origin, serverResolution);
var tileoffsetx = Math.round(tileLayout.tileoffsetx); // heaven help us this.gridLayout = tileLayout;
var tileoffsety = Math.round(tileLayout.tileoffsety);
var tileoffsetlon = tileLayout.tileoffsetlon; var startX = Math.round(tileLayout.tileoffsetx); // heaven help us
var tileoffsetlat = tileLayout.tileoffsetlat; var startY = Math.round(tileLayout.tileoffsety);
var tilelon = tileLayout.tilelon; var tilelon = tileLayout.tilelon;
var tilelat = tileLayout.tilelat; var tilelat = tileLayout.tilelat;
var startX = tileoffsetx;
var startLon = tileoffsetlon;
var rowidx = 0;
var layerContainerDivLeft = this.map.layerContainerOriginPx.x; var layerContainerDivLeft = this.map.layerContainerOriginPx.x;
var layerContainerDivTop = this.map.layerContainerOriginPx.y; var layerContainerDivTop = this.map.layerContainerOriginPx.y;
var tileData = [], center = this.map.getCenter(); var tileData = [], center = this.map.getCenter();
var rowidx = 0;
do { do {
var row = this.grid[rowidx++]; var row = this.grid[rowidx];
if (!row) { if (!row) {
row = []; row = [];
this.grid.push(row); this.grid.push(row);
} }
tileoffsetlon = startLon;
tileoffsetx = startX;
var colidx = 0; var colidx = 0;
do { do {
var tileBounds = var tileBounds = this.getTileBoundsForGridIndex(rowidx, colidx);
new OpenLayers.Bounds(tileoffsetlon, var x = startX + colidx * tileSize.w - layerContainerDivLeft;
tileoffsetlat, var y = startY + rowidx * tileSize.h - layerContainerDivTop;
tileoffsetlon + tilelon,
tileoffsetlat + tilelat);
var x = tileoffsetx;
x -= layerContainerDivLeft;
var y = tileoffsety;
y -= layerContainerDivTop;
var px = new OpenLayers.Pixel(x, y); var px = new OpenLayers.Pixel(x, y);
var tile = row[colidx++]; var tile = row[colidx];
if (!tile) { if (!tile) {
tile = this.addTile(tileBounds, px); tile = this.addTile(tileBounds, px);
this.addTileMonitoringHooks(tile); this.addTileMonitoringHooks(tile);
@@ -1014,18 +1029,12 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
Math.pow(tileCenter.lat - center.lat, 2) Math.pow(tileCenter.lat - center.lat, 2)
}); });
tileoffsetlon = 'startcol' in tileLayout ? colidx += 1;
origin.lon + (tileLayout.startcol + colidx) * tilelon : } while ((tileBounds.right <= bounds.right + tilelon * this.buffer)
tileoffsetlon + tilelon;
tileoffsetx += Math.round(tileSize.w);
} while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
|| colidx < minCols); || colidx < minCols);
tileoffsetlat = 'startrow' in tileLayout ? rowidx += 1;
origin.lat + (tileLayout.startrow - rowidx) * tilelat : } while((tileBounds.bottom >= bounds.bottom - tilelat * this.buffer)
tileoffsetlat - tilelat;
tileoffsety += Math.round(tileSize.h);
} while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
|| rowidx < minRows); || rowidx < minRows);
//shave off exceess rows and colums //shave off exceess rows and colums
@@ -1200,31 +1209,28 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* if false, then append to end * if false, then append to end
* tileSize - {Object} rendered tile size; object with w and h properties * tileSize - {Object} rendered tile size; object with w and h properties
*/ */
shiftRow:function(prepend, tileSize) { shiftRow: function(prepend, tileSize) {
var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
var grid = this.grid; var grid = this.grid;
var modelRow = grid[modelRowIndex]; var rowIndex = prepend ? 0 : (grid.length - 1);
var sign = prepend ? -1 : 1; var sign = prepend ? -1 : 1;
var deltaLat = this.getServerResolution() * -sign * this.tileSize.h; var rowSign = this.tileOriginCorner.substr(0, 1) === "t" ? 1 : -1;
var tileLayout = this.gridLayout;
tileLayout.startrow += sign * rowSign;
var row = (prepend) ? grid.pop() : grid.shift(); var bounds = this.getTileBoundsForGridIndex(rowIndex, 0);
var position = this.map.getViewPortPxFromLonLat(
new OpenLayers.LonLat(bounds.left, bounds.top)
);
var y = Math.round(position.y - this.map.layerContainerOriginPx.y);
for (var i=0, len=modelRow.length; i<len; i++) { var row = grid[prepend ? 'pop' : 'shift']();
var modelTile = modelRow[i]; for (var i=0, len=row.length; i<len; i++) {
var bounds = modelTile.bounds.clone(); var tile = row[i];
var position = modelTile.position.clone(); var position = tile.position.clone();
bounds.bottom = bounds.bottom + deltaLat; position.y = y;
bounds.top = bounds.top + deltaLat; tile.moveTo(this.getTileBoundsForGridIndex(rowIndex, i), position);
position.y = position.y + sign * tileSize.h;
row[i].moveTo(bounds, position);
}
if (prepend) {
grid.unshift(row);
} else {
grid.push(row);
} }
grid[prepend ? 'unshift' : 'push'](row);
}, },
/** /**
@@ -1237,27 +1243,25 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* tileSize - {Object} rendered tile size; object with w and h properties * tileSize - {Object} rendered tile size; object with w and h properties
*/ */
shiftColumn: function(prepend, tileSize) { shiftColumn: function(prepend, tileSize) {
var grid = this.grid;
var colIndex = prepend ? 0 : (grid[0].length - 1);
var sign = prepend ? -1 : 1; var sign = prepend ? -1 : 1;
var deltaLon = this.getServerResolution() * sign * this.tileSize.w; var tileLayout = this.gridLayout;
tileLayout.startcol += sign;
for (var i=0, len=this.grid.length; i<len; i++) { var bounds = this.getTileBoundsForGridIndex(0, colIndex);
var row = this.grid[i]; var position = this.map.getViewPortPxFromLonLat(
var modelTileIndex = (prepend) ? 0 : (row.length - 1); new OpenLayers.LonLat(bounds.left, bounds.top)
var modelTile = row[modelTileIndex]; );
var x = Math.round(position.x - this.map.layerContainerOriginPx.x);
var bounds = modelTile.bounds.clone(); for (var i=0, len=grid.length; i<len; i++) {
var position = modelTile.position.clone(); var row = grid[i];
bounds.left = bounds.left + deltaLon; var tile = row[prepend ? 'pop' : 'shift']();
bounds.right = bounds.right + deltaLon; var position = tile.position.clone();
position.x = position.x + sign * tileSize.w; position.x = x;
tile.moveTo(this.getTileBoundsForGridIndex(i, colIndex), position);
var tile = prepend ? this.grid[i].pop() : this.grid[i].shift(); row[prepend ? 'unshift' : 'push'](tile);
tile.moveTo(bounds, position);
if (prepend) {
row.unshift(tile);
} else {
row.push(tile);
}
} }
}, },

View File

@@ -114,7 +114,8 @@ OpenLayers.Layer.KaMap = OpenLayers.Class(OpenLayers.Layer.Grid, {
return { return {
tilelon: tilelon, tilelat: tilelat, tilelon: tilelon, tilelat: tilelat,
tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat, tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
tileoffsetx: tileoffsetx, tileoffsety: tileoffsety tileoffsetx: tileoffsetx, tileoffsety: tileoffsety,
startcol: tilecol, startrow: tilerow
}; };
}, },

View File

@@ -439,41 +439,5 @@ OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, {
return requestString; return requestString;
}, },
/**
* Method: calculateGridLayout
* Generate parameters for the grid layout. This
*
* Parameters:
* bounds - {<OpenLayers.Bound>}
* origin - {<OpenLayers.LonLat>}
* resolution - {Number}
*
* Returns:
* {Object} Object containing properties tilelon, tilelat, tileoffsetlat,
* tileoffsetlat, tileoffsetx, tileoffsety
*/
calculateGridLayout: function(bounds, origin, resolution) {
var tilelon = resolution * this.tileSize.w;
var tilelat = resolution * this.tileSize.h;
var offsetlon = bounds.left - origin.lon;
var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
var tilecolremain = offsetlon/tilelon - tilecol;
var tileoffsetx = -tilecolremain * this.tileSize.w;
var tileoffsetlon = origin.lon + tilecol * tilelon;
var offsetlat = origin.lat - bounds.top + tilelat;
var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
var tilerowremain = tilerow - offsetlat/tilelat;
var tileoffsety = tilerowremain * this.tileSize.h;
var tileoffsetlat = origin.lat - tilelat*tilerow;
return {
tilelon: tilelon, tilelat: tilelat,
tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
};
},
CLASS_NAME: "OpenLayers.Layer.MapGuide" CLASS_NAME: "OpenLayers.Layer.MapGuide"
}); });

View File

@@ -256,41 +256,5 @@ OpenLayers.Layer.Zoomify = OpenLayers.Class(OpenLayers.Layer.Grid, {
this.map.maxExtent.top); this.map.maxExtent.top);
}, },
/**
* Method: calculateGridLayout
* Generate parameters for the grid layout. This
*
* Parameters:
* bounds - {<OpenLayers.Bound>}
* origin - {<OpenLayers.LonLat>}
* resolution - {Number}
*
* Returns:
* {Object} Object containing properties tilelon, tilelat, tileoffsetlat,
* tileoffsetlat, tileoffsetx, tileoffsety
*/
calculateGridLayout: function(bounds, origin, resolution) {
var tilelon = resolution * this.tileSize.w;
var tilelat = resolution * this.tileSize.h;
var offsetlon = bounds.left - origin.lon;
var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
var tilecolremain = offsetlon/tilelon - tilecol;
var tileoffsetx = -tilecolremain * this.tileSize.w;
var tileoffsetlon = origin.lon + tilecol * tilelon;
var offsetlat = origin.lat - bounds.top + tilelat;
var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
var tilerowremain = tilerow - offsetlat/tilelat;
var tileoffsety = tilerowremain * this.tileSize.h;
var tileoffsetlat = origin.lat - tilelat*tilerow;
return {
tilelon: tilelon, tilelat: tilelat,
tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
};
},
CLASS_NAME: "OpenLayers.Layer.Zoomify" CLASS_NAME: "OpenLayers.Layer.Zoomify"
}); });

View File

@@ -535,15 +535,27 @@
} }
function test_tileBounds(t) { function test_tileBounds(t) {
t.plan(1); // do not defer moveGriddedTiles
var isNative = OpenLayers.Animation.isNative;
OpenLayers.Animation.isNative = true;
t.plan(2);
var map = new OpenLayers.Map("map", {projection: "EPSG:3857"}); var map = new OpenLayers.Map("map", {projection: "EPSG:3857"});
var layer = new OpenLayers.Layer.WMS("wms", "../../img/blank.gif"); var layer = new OpenLayers.Layer.WMS("wms", "../../img/blank.gif");
map.addLayer(layer); map.addLayer(layer);
map.setCenter([0, 0], 1); map.setCenter([0, 0], 1);
map.pan(2, -100); map.pan(2, -100);
map.zoomIn(); map.zoomIn();
t.eq(layer.grid[1][0].bounds, new OpenLayers.Bounds(-10018754.17, 0, 0, 10018754.17), "no floating point errors"); t.eq(layer.grid[1][0].bounds, new OpenLayers.Bounds(-10018754.17, 0, 0, 10018754.17), "no floating point errors after zooming");
map.zoomTo(14);
var bounds = layer.grid[0][0].bounds.clone();
map.pan(260, 520);
map.pan(-260, -520);
t.eq(layer.grid[0][0].bounds, bounds, "no floating point errors after dragging back and forth");
console.log(bounds.toString())
map.destroy(); map.destroy();
OpenLayers.Animation.isNative = isNative;
} }