Merge pull request #338 from twpayne/snap-center-to-pixel2
Snap center to pixel
This commit is contained in:
@@ -45,6 +45,35 @@ ol.Extent.boundingExtent = function(var_args) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Coordinate} center Center.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} rotation Rotation.
|
||||
* @param {ol.Size} size Size.
|
||||
* @return {ol.Extent} Extent.
|
||||
*/
|
||||
ol.Extent.getForView2DAndSize = function(center, resolution, rotation, size) {
|
||||
var dx = resolution * size.width / 2;
|
||||
var dy = resolution * size.height / 2;
|
||||
var cosRotation = Math.cos(rotation);
|
||||
var sinRotation = Math.sin(rotation);
|
||||
var xs = [-dx, -dx, dx, dx];
|
||||
var ys = [-dy, dy, -dy, dy];
|
||||
var i, x, y;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
x = xs[i];
|
||||
y = ys[i];
|
||||
xs[i] = center.x + x * cosRotation - y * sinRotation;
|
||||
ys[i] = center.y + x * sinRotation + y * cosRotation;
|
||||
}
|
||||
var minX = Math.min.apply(null, xs);
|
||||
var minY = Math.min.apply(null, ys);
|
||||
var maxX = Math.max.apply(null, xs);
|
||||
var maxY = Math.max.apply(null, ys);
|
||||
return new ol.Extent(minX, minY, maxX, maxY);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the passed coordinate is contained or on the edge
|
||||
* of the extent.
|
||||
|
||||
@@ -728,24 +728,8 @@ ol.Map.prototype.renderFrame_ = function(time) {
|
||||
|
||||
if (!goog.isNull(frameState)) {
|
||||
// FIXME works for View2D only
|
||||
var center = view2DState.center;
|
||||
var resolution = view2DState.resolution;
|
||||
var rotation = view2DState.rotation;
|
||||
var x = resolution * size.width / 2;
|
||||
var y = resolution * size.height / 2;
|
||||
var corners = [
|
||||
new ol.Coordinate(-x, -y),
|
||||
new ol.Coordinate(-x, y),
|
||||
new ol.Coordinate(x, -y),
|
||||
new ol.Coordinate(x, y)
|
||||
];
|
||||
var corner;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
corner = corners[i];
|
||||
corner.rotate(rotation);
|
||||
corner.add(center);
|
||||
}
|
||||
frameState.extent = ol.Extent.boundingExtent.apply(null, corners);
|
||||
frameState.extent = ol.Extent.getForView2DAndSize(view2DState.center,
|
||||
view2DState.resolution, view2DState.rotation, frameState.size);
|
||||
}
|
||||
|
||||
this.frameState_ = frameState;
|
||||
|
||||
@@ -6,6 +6,7 @@ goog.provide('ol.renderer.canvas.TileLayer');
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.vec.Mat4');
|
||||
goog.require('ol.Extent');
|
||||
goog.require('ol.Size');
|
||||
goog.require('ol.Tile');
|
||||
goog.require('ol.TileCoord');
|
||||
@@ -103,8 +104,17 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
|
||||
var z = tileGrid.getZForResolution(view2DState.resolution);
|
||||
var tileSize = tileGrid.getTileSize(z);
|
||||
var tileResolution = tileGrid.getResolution(z);
|
||||
var center = view2DState.center;
|
||||
var extent;
|
||||
if (tileResolution == view2DState.resolution) {
|
||||
center = this.snapCenterToPixel(center, tileResolution, frameState.size);
|
||||
extent = ol.Extent.getForView2DAndSize(
|
||||
center, tileResolution, view2DState.rotation, frameState.size);
|
||||
} else {
|
||||
extent = frameState.extent;
|
||||
}
|
||||
var tileRange = tileGrid.getTileRangeForExtentAndResolution(
|
||||
frameState.extent, tileResolution);
|
||||
extent, tileResolution);
|
||||
var tileRangeWidth = tileRange.getWidth();
|
||||
var tileRangeHeight = tileRange.getHeight();
|
||||
|
||||
@@ -238,7 +248,7 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
|
||||
}
|
||||
|
||||
this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
|
||||
tileSource.useLowResolutionTiles(z, frameState.extent, tileGrid);
|
||||
tileSource.useLowResolutionTiles(z, extent, tileGrid);
|
||||
this.scheduleExpireCache(frameState, tileSource);
|
||||
|
||||
var transform = this.transform_;
|
||||
@@ -253,8 +263,8 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame =
|
||||
1);
|
||||
goog.vec.Mat4.translate(
|
||||
transform,
|
||||
(origin.x - view2DState.center.x) / tileResolution,
|
||||
(view2DState.center.y - origin.y) / tileResolution,
|
||||
(origin.x - center.x) / tileResolution,
|
||||
(center.y - origin.y) / tileResolution,
|
||||
0);
|
||||
|
||||
};
|
||||
|
||||
@@ -90,8 +90,17 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
|
||||
}
|
||||
var z = tileGrid.getZForResolution(view2DState.resolution);
|
||||
var tileResolution = tileGrid.getResolution(z);
|
||||
var center = view2DState.center;
|
||||
var extent;
|
||||
if (tileResolution == view2DState.resolution) {
|
||||
center = this.snapCenterToPixel(center, tileResolution, frameState.size);
|
||||
extent = ol.Extent.getForView2DAndSize(
|
||||
center, tileResolution, view2DState.rotation, frameState.size);
|
||||
} else {
|
||||
extent = frameState.extent;
|
||||
}
|
||||
var tileRange = tileGrid.getTileRangeForExtentAndResolution(
|
||||
frameState.extent, tileResolution);
|
||||
extent, tileResolution);
|
||||
|
||||
/** @type {Object.<number, Object.<string, ol.Tile>>} */
|
||||
var tilesToDrawByZ = {};
|
||||
@@ -146,7 +155,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
|
||||
tileLayerZ = this.tileLayerZs_[tileLayerZKey];
|
||||
} else {
|
||||
tileCoordOrigin =
|
||||
tileGrid.getTileCoordForCoordAndZ(view2DState.center, tileLayerZKey);
|
||||
tileGrid.getTileCoordForCoordAndZ(center, tileLayerZKey);
|
||||
tileLayerZ = new ol.renderer.dom.TileLayerZ_(tileGrid, tileCoordOrigin);
|
||||
newTileLayerZKeys[tileLayerZKey] = true;
|
||||
this.tileLayerZs_[tileLayerZKey] = tileLayerZ;
|
||||
@@ -183,8 +192,8 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
|
||||
resolution / view2DState.resolution, 1);
|
||||
goog.vec.Mat4.translate(
|
||||
transform,
|
||||
(origin.x - view2DState.center.x) / resolution,
|
||||
(view2DState.center.y - origin.y) / resolution,
|
||||
(origin.x - center.x) / resolution,
|
||||
(center.y - origin.y) / resolution,
|
||||
0);
|
||||
tileLayerZ.setTransform(transform);
|
||||
if (tileLayerZKey in newTileLayerZKeys) {
|
||||
@@ -201,7 +210,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
|
||||
} else {
|
||||
if (!frameState.viewHints[ol.ViewHint.ANIMATING] &&
|
||||
!frameState.viewHints[ol.ViewHint.INTERACTING]) {
|
||||
tileLayerZ.removeTilesOutsideExtent(frameState.extent);
|
||||
tileLayerZ.removeTilesOutsideExtent(extent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,7 +226,7 @@ ol.renderer.dom.TileLayer.prototype.renderFrame =
|
||||
}
|
||||
|
||||
this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
|
||||
tileSource.useLowResolutionTiles(z, frameState.extent, tileGrid);
|
||||
tileSource.useLowResolutionTiles(z, extent, tileGrid);
|
||||
this.scheduleExpireCache(frameState, tileSource);
|
||||
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ goog.provide('ol.renderer.Layer');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('ol.Attribution');
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.FrameState');
|
||||
goog.require('ol.Image');
|
||||
goog.require('ol.ImageState');
|
||||
@@ -299,3 +300,18 @@ ol.renderer.Layer.prototype.createGetTileIfLoadedFunction =
|
||||
return isLoadedFunction(tile) ? tile : null;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Coordinate} center Center.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {ol.Size} size Size.
|
||||
* @return {ol.Coordinate} Snapped center.
|
||||
* @protected
|
||||
*/
|
||||
ol.renderer.Layer.prototype.snapCenterToPixel =
|
||||
function(center, resolution, size) {
|
||||
return new ol.Coordinate(
|
||||
resolution * (Math.round(center.x / resolution) + (size.width % 2) / 2),
|
||||
resolution * (Math.round(center.y / resolution) + (size.height % 2) / 2));
|
||||
};
|
||||
|
||||
@@ -282,7 +282,6 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
|
||||
|
||||
var view2DState = frameState.view2DState;
|
||||
var projection = view2DState.projection;
|
||||
var center = view2DState.center;
|
||||
|
||||
var tileLayer = this.getTileLayer();
|
||||
var tileSource = tileLayer.getTileSource();
|
||||
@@ -293,8 +292,17 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
|
||||
}
|
||||
var z = tileGrid.getZForResolution(view2DState.resolution);
|
||||
var tileResolution = tileGrid.getResolution(z);
|
||||
var center = view2DState.center;
|
||||
var extent;
|
||||
if (tileResolution == view2DState.resolution) {
|
||||
center = this.snapCenterToPixel(center, tileResolution, frameState.size);
|
||||
extent = ol.Extent.getForView2DAndSize(
|
||||
center, tileResolution, view2DState.rotation, frameState.size);
|
||||
} else {
|
||||
extent = frameState.extent;
|
||||
}
|
||||
var tileRange = tileGrid.getTileRangeForExtentAndResolution(
|
||||
frameState.extent, tileResolution);
|
||||
extent, tileResolution);
|
||||
|
||||
var framebufferExtent;
|
||||
if (!goog.isNull(this.renderedTileRange_) &&
|
||||
@@ -460,14 +468,14 @@ ol.renderer.webgl.TileLayer.prototype.renderFrame =
|
||||
}
|
||||
|
||||
this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
|
||||
tileSource.useLowResolutionTiles(z, frameState.extent, tileGrid);
|
||||
tileSource.useLowResolutionTiles(z, extent, tileGrid);
|
||||
this.scheduleExpireCache(frameState, tileSource);
|
||||
|
||||
goog.vec.Mat4.makeIdentity(this.texCoordMatrix_);
|
||||
goog.vec.Mat4.translate(this.texCoordMatrix_,
|
||||
(view2DState.center.x - framebufferExtent.minX) /
|
||||
(center.x - framebufferExtent.minX) /
|
||||
(framebufferExtent.maxX - framebufferExtent.minX),
|
||||
(view2DState.center.y - framebufferExtent.minY) /
|
||||
(center.y - framebufferExtent.minY) /
|
||||
(framebufferExtent.maxY - framebufferExtent.minY),
|
||||
0);
|
||||
goog.vec.Mat4.rotateZ(this.texCoordMatrix_, view2DState.rotation);
|
||||
|
||||
@@ -97,8 +97,59 @@ describe('ol.Extent', function() {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('getForView2DAndSize', function() {
|
||||
|
||||
it('works for a unit square', function() {
|
||||
var extent = ol.Extent.getForView2DAndSize(
|
||||
new ol.Coordinate(0, 0), 1, 0, new ol.Size(1, 1));
|
||||
expect(extent.minX).toBe(-0.5);
|
||||
expect(extent.minY).toBe(-0.5);
|
||||
expect(extent.maxX).toBe(0.5);
|
||||
expect(extent.maxY).toBe(0.5);
|
||||
});
|
||||
|
||||
it('works for center', function() {
|
||||
var extent = ol.Extent.getForView2DAndSize(
|
||||
new ol.Coordinate(5, 10), 1, 0, new ol.Size(1, 1));
|
||||
expect(extent.minX).toBe(4.5);
|
||||
expect(extent.minY).toBe(9.5);
|
||||
expect(extent.maxX).toBe(5.5);
|
||||
expect(extent.maxY).toBe(10.5);
|
||||
});
|
||||
|
||||
it('works for rotation', function() {
|
||||
var extent = ol.Extent.getForView2DAndSize(
|
||||
new ol.Coordinate(0, 0), 1, Math.PI / 4, new ol.Size(1, 1));
|
||||
expect(extent.minX).toRoughlyEqual(-Math.sqrt(0.5), 1e-9);
|
||||
expect(extent.minY).toRoughlyEqual(-Math.sqrt(0.5), 1e-9);
|
||||
expect(extent.maxX).toRoughlyEqual(Math.sqrt(0.5), 1e-9);
|
||||
expect(extent.maxY).toRoughlyEqual(Math.sqrt(0.5), 1e-9);
|
||||
});
|
||||
|
||||
it('works for resolution', function() {
|
||||
var extent = ol.Extent.getForView2DAndSize(
|
||||
new ol.Coordinate(0, 0), 2, 0, new ol.Size(1, 1));
|
||||
expect(extent.minX).toBe(-1);
|
||||
expect(extent.minY).toBe(-1);
|
||||
expect(extent.maxX).toBe(1);
|
||||
expect(extent.maxY).toBe(1);
|
||||
});
|
||||
|
||||
it('works for size', function() {
|
||||
var extent = ol.Extent.getForView2DAndSize(
|
||||
new ol.Coordinate(0, 0), 1, 0, new ol.Size(10, 5));
|
||||
expect(extent.minX).toBe(-5);
|
||||
expect(extent.minY).toBe(-2.5);
|
||||
expect(extent.maxX).toBe(5);
|
||||
expect(extent.maxY).toBe(2.5);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.Extent');
|
||||
goog.require('ol.Size');
|
||||
goog.require('ol.projection');
|
||||
|
||||
Reference in New Issue
Block a user