diff --git a/lib/OpenLayers/Layer/ArcGISCache.js b/lib/OpenLayers/Layer/ArcGISCache.js index 27173392c4..e52ea645e6 100644 --- a/lib/OpenLayers/Layer/ArcGISCache.js +++ b/lib/OpenLayers/Layer/ArcGISCache.js @@ -358,6 +358,17 @@ OpenLayers.Layer.ArcGISCache = OpenLayers.Class(OpenLayers.Layer.XYZ, { return OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]); }, + /** + * Method: initGriddedTiles + * + * Parameters: + * bounds - {} + */ + initGriddedTiles: function(bounds) { + delete this._tileOrigin; + OpenLayers.Layer.XYZ.prototype.initGriddedTiles.apply(this, arguments); + }, + /** * Method: getMaxExtent * Get this layer's maximum extent. @@ -379,8 +390,11 @@ OpenLayers.Layer.ArcGISCache = OpenLayers.Class(OpenLayers.Layer.XYZ, { * {} The tile origin. */ getTileOrigin: function() { - var extent = this.getMaxExtent(); - return new OpenLayers.LonLat(extent.left, extent.bottom); + if (!this._tileOrigin) { + var extent = this.getMaxExtent(); + this._tileOrigin = new OpenLayers.LonLat(extent.left, extent.bottom); + } + return this._tileOrigin; }, /** diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index de12b76396..0985f231bb 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -271,6 +271,20 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * tile that could not be loaded. */ + /** + * Property: gridLayout + * {Object} Object containing properties tilelon, tilelat, startcol, + * startrow + */ + gridLayout: null, + + /** + * Property: rowSign + * {Number} 1 for grids starting at the top, -1 for grids starting at the + * bottom. This is used for several grid index and offset calculations. + */ + rowSign: null, + /** * Constructor: OpenLayers.Layer.Grid * Create a new grid layer @@ -302,6 +316,8 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.moveTimerId = null; }, this); } + + this.rowSign = this.tileOriginCorner.substr(0, 1) === "t" ? 1 : -1; }, /** @@ -364,6 +380,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { } this.grid = []; this.gridResolution = null; + this.gridLayout = null; } }, @@ -867,35 +884,24 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * resolution - {Number} * * Returns: - * {Object} containing properties tilelon, tilelat, tileoffsetlat, - * tileoffsetlat, tileoffsetx, tileoffsety + * {Object} Object containing properties tilelon, tilelat, startcol, + * startrow */ calculateGridLayout: function(bounds, origin, resolution) { var tilelon = resolution * this.tileSize.w; var tilelat = resolution * this.tileSize.h; - var ratio = resolution / this.map.getResolution(), - tileSize = { - w: Math.round(this.tileSize.w * ratio), - h: Math.round(this.tileSize.h * ratio) - }; - var offsetlon = bounds.left - origin.lon; var tilecol = Math.floor(offsetlon/tilelon) - this.buffer; - var tilecolremain = offsetlon/tilelon - tilecol; - var tileoffsetx = -tilecolremain * tileSize.w; - var tileoffsetlon = origin.lon + tilecol * tilelon; - var offsetlat = bounds.top - (origin.lat + tilelat); - var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer; - var tilerowremain = tilerow - offsetlat/tilelat; - var tileoffsety = -tilerowremain * tileSize.h; - var tileoffsetlat = origin.lat + tilerow * tilelat; + var rowSign = this.rowSign; + + var offsetlat = rowSign * (origin.lat - bounds.top + tilelat); + var tilerow = Math[~rowSign ? 'floor' : 'ceil'](offsetlat/tilelat) - this.buffer * rowSign; return { tilelon: tilelon, tilelat: tilelat, - tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat, - tileoffsetx: tileoffsetx, tileoffsety: tileoffsety + startcol: tilecol, startrow: tilerow }; }, @@ -926,6 +932,32 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { return origin; }, + /** + * Method: getTileBoundsForGridIndex + * + * Parameters: + * row - {Number} The row of the grid + * col - {Number} The column of the grid + * + * Returns: + * {} 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 startcol = tileLayout.startcol; + var startrow = tileLayout.startrow; + var rowSign = this.rowSign; + return new OpenLayers.Bounds( + origin.lon + (startcol + col) * tilelon, + origin.lat - (startrow + row * rowSign) * tilelat * rowSign, + origin.lon + (startcol + col + 1) * tilelon, + origin.lat - (startrow + (row - 1) * rowSign) * tilelat * rowSign + ); + }, + /** * Method: initGriddedTiles * @@ -955,50 +987,38 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { 2 * this.buffer + 1; var tileLayout = this.calculateGridLayout(bounds, origin, serverResolution); - var tileoffsetx = Math.round(tileLayout.tileoffsetx); // heaven help us - var tileoffsety = Math.round(tileLayout.tileoffsety); - - var tileoffsetlon = tileLayout.tileoffsetlon; - var tileoffsetlat = tileLayout.tileoffsetlat; + this.gridLayout = tileLayout; var tilelon = tileLayout.tilelon; var tilelat = tileLayout.tilelat; - - var startX = tileoffsetx; - var startLon = tileoffsetlon; - - var rowidx = 0; var layerContainerDivLeft = this.map.layerContainerOriginPx.x; var layerContainerDivTop = this.map.layerContainerOriginPx.y; + var tileBounds = this.getTileBoundsForGridIndex(0, 0); + var startPx = this.map.getViewPortPxFromLonLat( + new OpenLayers.LonLat(tileBounds.left, tileBounds.top) + ); + startPx.x = Math.round(startPx.x) - layerContainerDivLeft; + startPx.y = Math.round(startPx.y) - layerContainerDivTop; + var tileData = [], center = this.map.getCenter(); + + var rowidx = 0; do { - var row = this.grid[rowidx++]; + var row = this.grid[rowidx]; if (!row) { row = []; this.grid.push(row); } - - tileoffsetlon = startLon; - tileoffsetx = startX; + var colidx = 0; - do { - var tileBounds = - new OpenLayers.Bounds(tileoffsetlon, - tileoffsetlat, - tileoffsetlon + tilelon, - tileoffsetlat + tilelat); - - var x = tileoffsetx; - x -= layerContainerDivLeft; - - var y = tileoffsety; - y -= layerContainerDivTop; - - var px = new OpenLayers.Pixel(x, y); - var tile = row[colidx++]; + tileBounds = this.getTileBoundsForGridIndex(rowidx, colidx); + var px = startPx.clone(); + px.x = px.x + colidx * Math.round(tileSize.w); + px.y = px.y + rowidx * Math.round(tileSize.h); + var tile = row[colidx]; if (!tile) { tile = this.addTile(tileBounds, px); this.addTileMonitoringHooks(tile); @@ -1013,14 +1033,12 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { Math.pow(tileCenter.lat - center.lat, 2) }); - tileoffsetlon += tilelon; - tileoffsetx += Math.round(tileSize.w); - } while ((tileoffsetlon <= bounds.right + tilelon * this.buffer) + colidx += 1; + } while ((tileBounds.right <= bounds.right + tilelon * this.buffer) || colidx < minCols); - tileoffsetlat -= tilelat; - tileoffsety += Math.round(tileSize.h); - } while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer) + rowidx += 1; + } while((tileBounds.bottom >= bounds.bottom - tilelat * this.buffer) || rowidx < minRows); //shave off exceess rows and colums @@ -1198,31 +1216,23 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * if false, then append to end * tileSize - {Object} rendered tile size; object with w and h properties */ - shiftRow:function(prepend, tileSize) { - var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1); + shiftRow: function(prepend, tileSize) { var grid = this.grid; - var modelRow = grid[modelRowIndex]; - + var rowIndex = prepend ? 0 : (grid.length - 1); var sign = prepend ? -1 : 1; - var deltaLat = this.getServerResolution() * -sign * this.tileSize.h; + var rowSign = this.rowSign; + var tileLayout = this.gridLayout; + tileLayout.startrow += sign * rowSign; - var row = (prepend) ? grid.pop() : grid.shift(); - - for (var i=0, len=modelRow.length; i} 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 minX = (tileLayout.startcol + col) * tilelon; + var minY = (tileLayout.startrow - row) * tilelat; + return new OpenLayers.Bounds( + minX, minY, + minX + tilelon, minY + tilelat + ); + }, + /** * APIMethod: clone * diff --git a/lib/OpenLayers/Layer/MapGuide.js b/lib/OpenLayers/Layer/MapGuide.js index 7bf95018ec..6824b8ad51 100644 --- a/lib/OpenLayers/Layer/MapGuide.js +++ b/lib/OpenLayers/Layer/MapGuide.js @@ -439,41 +439,5 @@ OpenLayers.Layer.MapGuide = OpenLayers.Class(OpenLayers.Layer.Grid, { return requestString; }, - /** - * Method: calculateGridLayout - * Generate parameters for the grid layout. This - * - * Parameters: - * bounds - {} - * origin - {} - * 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" }); diff --git a/lib/OpenLayers/Layer/Zoomify.js b/lib/OpenLayers/Layer/Zoomify.js index d0b482ab29..8c5a8a9e4d 100644 --- a/lib/OpenLayers/Layer/Zoomify.js +++ b/lib/OpenLayers/Layer/Zoomify.js @@ -256,41 +256,5 @@ OpenLayers.Layer.Zoomify = OpenLayers.Class(OpenLayers.Layer.Grid, { this.map.maxExtent.top); }, - /** - * Method: calculateGridLayout - * Generate parameters for the grid layout. This - * - * Parameters: - * bounds - {} - * origin - {} - * 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" }); diff --git a/lib/OpenLayers/Tile/Image.js b/lib/OpenLayers/Tile/Image.js index e3c412a8ed..8d2fa84f47 100644 --- a/lib/OpenLayers/Tile/Image.js +++ b/lib/OpenLayers/Tile/Image.js @@ -217,8 +217,8 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { if (this.layer instanceof OpenLayers.Layer.Grid) { ratio = this.layer.getServerResolution() / this.layer.map.getResolution(); } - style.left = (this.position.x | 0) + "px"; - style.top = (this.position.y | 0) + "px"; + style.left = this.position.x + "px"; + style.top = this.position.y + "px"; style.width = Math.round(ratio * size.w) + "px"; style.height = Math.round(ratio * size.h) + "px"; }, diff --git a/tests/Layer/WMS.html b/tests/Layer/WMS.html index 0e9fb9a8fc..cdc00705a3 100644 --- a/tests/Layer/WMS.html +++ b/tests/Layer/WMS.html @@ -533,6 +533,30 @@ map.destroy(); } + + function test_tileBounds(t) { + // do not defer moveGriddedTiles + var isNative = OpenLayers.Animation.isNative; + OpenLayers.Animation.isNative = true; + t.plan(3); + + var map = new OpenLayers.Map("map", {projection: "EPSG:3857"}); + var layer = new OpenLayers.Layer.WMS("wms", "../../img/blank.gif"); + map.addLayer(layer); + map.setCenter([0, 0], 1); + map.pan(2, -100); + map.zoomIn(); + t.eq(layer.grid[1][0].bounds, new OpenLayers.Bounds(-10018754.17, 0, 0, 10018754.17), "no floating point errors after zooming"); + map.setCenter([0, 0], 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"); + t.eq(bounds.right, 0, "0 is 0, and not some super small number"); + + map.destroy(); + OpenLayers.Animation.isNative = isNative; + } diff --git a/tests/Layer/WrapDateLine.html b/tests/Layer/WrapDateLine.html index 700abf3f34..6b84362d59 100644 --- a/tests/Layer/WrapDateLine.html +++ b/tests/Layer/WrapDateLine.html @@ -154,9 +154,9 @@ var m = new OpenLayers.Map('map', {adjustZoom: function(z) {return z;}}); m.addLayer(layer); m.zoomToMaxExtent(); - t.eq(layer.grid[5][7].url, "http://www.openlayers.org/world/index.php?g=satellite&map=world&i=jpeg&t=0&l=-256&s=221471921.25", "grid[5][7] kamap is okay"); - t.eq(layer.grid[5][6].url, "http://www.openlayers.org/world/index.php?g=satellite&map=world&i=jpeg&t=0&l=0&s=221471921.25", "grid[5][6] kamap is okay"); - t.eq(layer.grid[5][5].url, "http://www.openlayers.org/world/index.php?g=satellite&map=world&i=jpeg&t=0&l=-256&s=221471921.25", "grid[5][5] is okay"); + t.eq(layer.grid[4][7].url, "http://www.openlayers.org/world/index.php?g=satellite&map=world&i=jpeg&t=0&l=-256&s=221471921.25", "grid[5][7] kamap is okay"); + t.eq(layer.grid[4][6].url, "http://www.openlayers.org/world/index.php?g=satellite&map=world&i=jpeg&t=0&l=0&s=221471921.25", "grid[5][6] kamap is okay"); + t.eq(layer.grid[4][5].url, "http://www.openlayers.org/world/index.php?g=satellite&map=world&i=jpeg&t=0&l=-256&s=221471921.25", "grid[5][5] is okay"); t.ok(layer.grid[7][6].url == null, "no latitudinal wrapping - tile not loaded if outside maxExtent"); m.destroy(); }