Merge pull request #1066 from avandecreme/wrapping

Remove reliance on getTileAtPoint for wrapping
This commit is contained in:
Ian Gilman 2016-11-07 13:38:58 -08:00 committed by GitHub
commit ec46f85024
7 changed files with 262 additions and 37 deletions

View File

@ -998,6 +998,47 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
} else { } else {
this._setFullyLoaded(this._tilesLoading === 0); this._setFullyLoaded(this._tilesLoading === 0);
} }
},
// private
_getCornerTiles: function(level, topLeftBound, bottomRightBound) {
var leftX;
var rightX;
if (this.wrapHorizontal) {
leftX = $.positiveModulo(topLeftBound.x, 1);
rightX = $.positiveModulo(bottomRightBound.x, 1);
} else {
leftX = Math.max(0, topLeftBound.x);
rightX = Math.min(1, bottomRightBound.x);
}
var topY;
var bottomY;
var aspectRatio = 1 / this.source.aspectRatio;
if (this.wrapVertical) {
topY = $.positiveModulo(topLeftBound.y, aspectRatio);
bottomY = $.positiveModulo(bottomRightBound.y, aspectRatio);
} else {
topY = Math.max(0, topLeftBound.y);
bottomY = Math.min(aspectRatio, bottomRightBound.y);
}
var topLeftTile = this.source.getTileAtPoint(level, new $.Point(leftX, topY));
var bottomRightTile = this.source.getTileAtPoint(level, new $.Point(rightX, bottomY));
var numTiles = this.source.getNumTiles(level);
if (this.wrapHorizontal) {
topLeftTile.x += numTiles.x * Math.floor(topLeftBound.x);
bottomRightTile.x += numTiles.x * Math.floor(bottomRightBound.x);
}
if (this.wrapVertical) {
topLeftTile.y += numTiles.y * Math.floor(topLeftBound.y / aspectRatio);
bottomRightTile.y += numTiles.y * Math.floor(bottomRightBound.y / aspectRatio);
}
return {
topLeft: topLeftTile,
bottomRight: bottomRightTile,
};
} }
}); });
@ -1041,23 +1082,13 @@ function updateLevel(tiledImage, haveDrawn, drawLevel, level, levelOpacity,
}); });
} }
//OK, a new drawing so do your calculations
var topLeftTile = tiledImage.source.getTileAtPoint(level, topLeftBound);
var bottomRightTile = tiledImage.source.getTileAtPoint(level, bottomRightBound);
var numberOfTiles = tiledImage.source.getNumTiles(level);
resetCoverage(tiledImage.coverage, level); resetCoverage(tiledImage.coverage, level);
if (!tiledImage.wrapHorizontal) { //OK, a new drawing so do your calculations
// Adjust for floating point error var cornerTiles = tiledImage._getCornerTiles(level, topLeftBound, bottomRightBound);
topLeftTile.x = Math.max(topLeftTile.x, 0); var topLeftTile = cornerTiles.topLeft;
bottomRightTile.x = Math.min(bottomRightTile.x, numberOfTiles.x - 1); var bottomRightTile = cornerTiles.bottomRight;
} var numberOfTiles = tiledImage.source.getNumTiles(level);
if (!tiledImage.wrapVertical) {
// Adjust for floating point error
topLeftTile.y = Math.max(topLeftTile.y, 0);
bottomRightTile.y = Math.min(bottomRightTile.y, numberOfTiles.y - 1);
}
var viewportCenter = tiledImage.viewport.pixelFromPoint( var viewportCenter = tiledImage.viewport.pixelFromPoint(
tiledImage.viewport.getCenter()); tiledImage.viewport.getCenter());

View File

@ -345,18 +345,17 @@ $.TileSource.prototype = {
* @param {OpenSeadragon.Point} point * @param {OpenSeadragon.Point} point
*/ */
getTileAtPoint: function(level, point) { getTileAtPoint: function(level, point) {
var validPoint = point.x >= 0 && point.x <= 1 &&
point.y >= 0 && point.y <= 1 / this.aspectRatio;
$.console.assert(validPoint, "[TileSource.getTileAtPoint] must be called with a valid point.");
var widthScaled = this.dimensions.x * this.getLevelScale(level); var widthScaled = this.dimensions.x * this.getLevelScale(level);
var pixelX = $.positiveModulo(point.x, 1) * widthScaled; var pixelX = point.x * widthScaled;
var pixelY = $.positiveModulo(point.y, 1 / this.aspectRatio) * widthScaled; var pixelY = point.y * widthScaled;
var x = Math.floor(pixelX / this.getTileWidth()); var x = Math.floor(pixelX / this.getTileWidth());
var y = Math.floor(pixelY / this.getTileHeight()); var y = Math.floor(pixelY / this.getTileHeight());
// Fix for wrapping
var numTiles = this.getNumTiles(level);
x += numTiles.x * Math.floor(point.x);
y += numTiles.y * Math.floor(point.y * this.aspectRatio);
return new $.Point(x, y); return new $.Point(x, y);
}, },

View File

@ -32,6 +32,7 @@
<script src="/src/iiiftilesource.js"></script> <script src="/src/iiiftilesource.js"></script>
<script src="/src/osmtilesource.js"></script> <script src="/src/osmtilesource.js"></script>
<script src="/src/tmstilesource.js"></script> <script src="/src/tmstilesource.js"></script>
<script src="/src/zoomifytilesource.js"></script>
<script src="/src/legacytilesource.js"></script> <script src="/src/legacytilesource.js"></script>
<script src="/src/imagetilesource.js"></script> <script src="/src/imagetilesource.js"></script>
<script src="/src/tilesourcecollection.js"></script> <script src="/src/tilesourcecollection.js"></script>

View File

@ -331,7 +331,7 @@
height: 155 height: 155
} ] } ]
} ); } );
viewer.addHandler('tile-drawn', function() { viewer.addOnceHandler('tile-drawn', function() {
ok(OpenSeadragon.isCanvasTainted(viewer.drawer.context.canvas), ok(OpenSeadragon.isCanvasTainted(viewer.drawer.context.canvas),
"Canvas should be tainted."); "Canvas should be tainted.");
start(); start();
@ -355,7 +355,7 @@
height: 155 height: 155
} ] } ]
} ); } );
viewer.addHandler('tile-drawn', function() { viewer.addOnceHandler('tile-drawn', function() {
ok(!OpenSeadragon.isCanvasTainted(viewer.drawer.context.canvas), ok(!OpenSeadragon.isCanvasTainted(viewer.drawer.context.canvas),
"Canvas should not be tainted."); "Canvas should not be tainted.");
start(); start();
@ -385,7 +385,7 @@
}, },
crossOriginPolicy : false crossOriginPolicy : false
} ); } );
viewer.addHandler('tile-drawn', function() { viewer.addOnceHandler('tile-drawn', function() {
ok(OpenSeadragon.isCanvasTainted(viewer.drawer.context.canvas), ok(OpenSeadragon.isCanvasTainted(viewer.drawer.context.canvas),
"Canvas should be tainted."); "Canvas should be tainted.");
start(); start();
@ -414,7 +414,7 @@
crossOriginPolicy : "Anonymous" crossOriginPolicy : "Anonymous"
} }
} ); } );
viewer.addHandler('tile-drawn', function() { viewer.addOnceHandler('tile-drawn', function() {
ok(!OpenSeadragon.isCanvasTainted(viewer.drawer.context.canvas), ok(!OpenSeadragon.isCanvasTainted(viewer.drawer.context.canvas),
"Canvas should not be tainted."); "Canvas should not be tainted.");
start(); start();

View File

@ -217,7 +217,7 @@
var firstImage = viewer.world.getItemAt(0); var firstImage = viewer.world.getItemAt(0);
firstImage.addHandler('fully-loaded-change', function() { firstImage.addHandler('fully-loaded-change', function() {
var imageData = viewer.drawer.context.getImageData(0, 0, var imageData = viewer.drawer.context.getImageData(0, 0,
500 * OpenSeadragon.pixelDensityRatio, 500 * density); 500 * density, 500 * density);
// Pixel 250,250 will be in the hole of the A // Pixel 250,250 will be in the hole of the A
var expectedVal = getPixelValue(imageData, 250 * density, 250 * density); var expectedVal = getPixelValue(imageData, 250 * density, 250 * density);

View File

@ -515,4 +515,159 @@
}]); }]);
}); });
// PhantomJS is missing Function.prototype.bind
function bind(func, _this) {
return function() {
return func.apply(_this, arguments);
};
}
test('_getCornerTiles without wrapping', function() {
var tiledImageMock = {
wrapHorizontal: false,
wrapVertical: false,
source: new OpenSeadragon.TileSource({
width: 1500,
height: 1000,
tileWidth: 200,
tileHeight: 150,
tileOverlap: 1,
}),
};
var _getCornerTiles = bind(
OpenSeadragon.TiledImage.prototype._getCornerTiles,
tiledImageMock);
function assertCornerTiles(topLeftBound, bottomRightBound,
expectedTopLeft, expectedBottomRight) {
var cornerTiles = _getCornerTiles(11, topLeftBound, bottomRightBound);
ok(cornerTiles.topLeft.equals(expectedTopLeft),
'Top left tile should be ' + expectedTopLeft.toString() +
' found ' + cornerTiles.topLeft.toString());
ok(cornerTiles.bottomRight.equals(expectedBottomRight),
'Bottom right tile should be ' + expectedBottomRight.toString() +
' found ' + cornerTiles.bottomRight.toString());
}
assertCornerTiles(
new OpenSeadragon.Point(0, 0),
new OpenSeadragon.Point(1, 10 / 15),
new OpenSeadragon.Point(0, 0),
new OpenSeadragon.Point(7, 6)
)
// Floating point errors should be handled
assertCornerTiles(
new OpenSeadragon.Point(-1e-14, -1e-14),
new OpenSeadragon.Point(1 + 1e-14, 10 / 15 + 1e-14),
new OpenSeadragon.Point(0, 0),
new OpenSeadragon.Point(7, 6)
)
assertCornerTiles(
new OpenSeadragon.Point(0.3, 0.5),
new OpenSeadragon.Point(0.5, 0.6),
new OpenSeadragon.Point(2, 5),
new OpenSeadragon.Point(3, 6)
)
});
test('_getCornerTiles with horizontal wrapping', function() {
var tiledImageMock = {
wrapHorizontal: true,
wrapVertical: false,
source: new OpenSeadragon.TileSource({
width: 1500,
height: 1000,
tileWidth: 200,
tileHeight: 150,
tileOverlap: 1,
}),
};
var _getCornerTiles = bind(
OpenSeadragon.TiledImage.prototype._getCornerTiles,
tiledImageMock);
function assertCornerTiles(topLeftBound, bottomRightBound,
expectedTopLeft, expectedBottomRight) {
var cornerTiles = _getCornerTiles(11, topLeftBound, bottomRightBound);
ok(cornerTiles.topLeft.equals(expectedTopLeft),
'Top left tile should be ' + expectedTopLeft.toString() +
' found ' + cornerTiles.topLeft.toString());
ok(cornerTiles.bottomRight.equals(expectedBottomRight),
'Bottom right tile should be ' + expectedBottomRight.toString() +
' found ' + cornerTiles.bottomRight.toString());
}
assertCornerTiles(
new OpenSeadragon.Point(0, 0),
new OpenSeadragon.Point(1, 10 / 15),
new OpenSeadragon.Point(0, 0),
new OpenSeadragon.Point(8, 6)
)
assertCornerTiles(
new OpenSeadragon.Point(-1, 0),
new OpenSeadragon.Point(0.5, 10 / 15 + 1e-14),
new OpenSeadragon.Point(-8, 0),
new OpenSeadragon.Point(3, 6)
)
assertCornerTiles(
new OpenSeadragon.Point(1.3, 0.5),
new OpenSeadragon.Point(1.5, 0.6),
new OpenSeadragon.Point(10, 5),
new OpenSeadragon.Point(11, 6)
)
});
test('_getCornerTiles with vertical wrapping', function() {
var tiledImageMock = {
wrapHorizontal: false,
wrapVertical: true,
source: new OpenSeadragon.TileSource({
width: 1500,
height: 1000,
tileWidth: 200,
tileHeight: 150,
tileOverlap: 1,
}),
};
var _getCornerTiles = bind(
OpenSeadragon.TiledImage.prototype._getCornerTiles,
tiledImageMock);
function assertCornerTiles(topLeftBound, bottomRightBound,
expectedTopLeft, expectedBottomRight) {
var cornerTiles = _getCornerTiles(11, topLeftBound, bottomRightBound);
ok(cornerTiles.topLeft.equals(expectedTopLeft),
'Top left tile should be ' + expectedTopLeft.toString() +
' found ' + cornerTiles.topLeft.toString());
ok(cornerTiles.bottomRight.equals(expectedBottomRight),
'Bottom right tile should be ' + expectedBottomRight.toString() +
' found ' + cornerTiles.bottomRight.toString());
}
assertCornerTiles(
new OpenSeadragon.Point(0, 0),
new OpenSeadragon.Point(1, 10 / 15),
new OpenSeadragon.Point(0, 0),
new OpenSeadragon.Point(7, 7)
)
assertCornerTiles(
new OpenSeadragon.Point(0, -10 / 15 / 2),
new OpenSeadragon.Point(0.5, 0.5),
new OpenSeadragon.Point(0, -4),
new OpenSeadragon.Point(3, 5)
)
assertCornerTiles(
new OpenSeadragon.Point(0, 10 / 15 + 0.1),
new OpenSeadragon.Point(0.3, 10 / 15 + 0.3),
new OpenSeadragon.Point(0, 7),
new OpenSeadragon.Point(2, 9)
)
});
})(); })();

View File

@ -48,4 +48,43 @@
Util.testDeprecation(source, 'getTileSize'); Util.testDeprecation(source, 'getTileSize');
}); });
test('getTileAtPoint', function() {
var tileSource = new OpenSeadragon.TileSource({
width: 1500,
height: 1000,
tileWidth: 200,
tileHeight: 150,
tileOverlap: 1,
});
equal(tileSource.maxLevel, 11, "The max level should be 11.");
function assertTileAtPoint(level, position, expected) {
var actual = tileSource.getTileAtPoint(level, position);
ok(actual.equals(expected), "The tile at level " + level +
", position " + position.toString() +
" should be tile " + expected.toString() +
" got " + actual.toString());
}
assertTileAtPoint(11, new OpenSeadragon.Point(0, 0), new OpenSeadragon.Point(0, 0));
assertTileAtPoint(11, new OpenSeadragon.Point(0.5, 0.5), new OpenSeadragon.Point(3, 5));
assertTileAtPoint(11, new OpenSeadragon.Point(1, 10 / 15), new OpenSeadragon.Point(7, 6));
assertTileAtPoint(10, new OpenSeadragon.Point(0, 0), new OpenSeadragon.Point(0, 0));
assertTileAtPoint(10, new OpenSeadragon.Point(0.5, 0.5), new OpenSeadragon.Point(1, 2));
assertTileAtPoint(10, new OpenSeadragon.Point(1, 10 / 15), new OpenSeadragon.Point(3, 3));
assertTileAtPoint(9, new OpenSeadragon.Point(0, 0), new OpenSeadragon.Point(0, 0));
assertTileAtPoint(9, new OpenSeadragon.Point(0.5, 0.5), new OpenSeadragon.Point(0, 1));
assertTileAtPoint(9, new OpenSeadragon.Point(1, 10 / 15), new OpenSeadragon.Point(1, 1));
// For all other levels, there is only one tile.
for (var level = 8; level >= 0; level--) {
assertTileAtPoint(level, new OpenSeadragon.Point(0, 0), new OpenSeadragon.Point(0, 0));
assertTileAtPoint(level, new OpenSeadragon.Point(0.5, 0.5), new OpenSeadragon.Point(0, 0));
assertTileAtPoint(level, new OpenSeadragon.Point(1, 10 / 15), new OpenSeadragon.Point(0, 0));
}
});
}()); }());