Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TileMapServiceImageryProvider defaults can cause the browser to hang. #8448

Merged
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Change Log
##### Fixes :wrench:

* Interacting with the Cesium canvas will now blur the previously focused element. This prevents unintended modification of input elements when interacting with the globe.
* `TileMapServiceImageryProvider` will now force `minimumLevel` to 0 if the `tilemapresource.xml` metadata request fails and the `rectangle` is too large for the given detail level [#8448](https://github.com/AnalyticalGraphicsInc/cesium/pull/8448)

### 1.67.0 - 2020-03-02

Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,3 +248,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu
* [Jan Wąsak](https://github.com/jhnwsk)
* [Julian Fell](https://github.com/jtfell)
* [Richard Becker](https://github.com/richard3d)
* [Daniel Leone](https://github.com/danielleone)
64 changes: 41 additions & 23 deletions Source/Scene/TileMapServiceImageryProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,38 @@ import UrlTemplateImageryProvider from './UrlTemplateImageryProvider.js';
this._xmlResource.fetchXML().then(this._metadataSuccess).otherwise(this._metadataFailure);
};

/**
* Mutates the properties of a given rectangle so it does not extend outside of the given tiling scheme's rectangle
*/
function confineRectangleToTilingScheme(rectangle, tilingScheme) {
if (rectangle.west < tilingScheme.rectangle.west) {
rectangle.west = tilingScheme.rectangle.west;
}
if (rectangle.east > tilingScheme.rectangle.east) {
rectangle.east = tilingScheme.rectangle.east;
}
if (rectangle.south < tilingScheme.rectangle.south) {
rectangle.south = tilingScheme.rectangle.south;
}
if (rectangle.north > tilingScheme.rectangle.north) {
rectangle.north = tilingScheme.rectangle.north;
}
return rectangle;
}

function calculateSafeMinimumDetailLevel(tilingScheme, rectangle, minimumLevel) {
// Check the number of tiles at the minimum level. If it's more than four,
// try requesting the lower levels anyway, because starting at the higher minimum
// level will cause too many tiles to be downloaded and rendered.
var swTile = tilingScheme.positionToTileXY(Rectangle.southwest(rectangle), minimumLevel);
var neTile = tilingScheme.positionToTileXY(Rectangle.northeast(rectangle), minimumLevel);
var tileCount = (Math.abs(neTile.x - swTile.x) + 1) * (Math.abs(neTile.y - swTile.y) + 1);
if (tileCount > 4) {
return 0;
}
return minimumLevel;
}

TileMapServiceImageryProvider.prototype._metadataSuccess = function(xml) {
var tileFormatRegex = /tileformat/i;
var tileSetRegex = /tileset/i;
Expand Down Expand Up @@ -221,28 +253,9 @@ import UrlTemplateImageryProvider from './UrlTemplateImageryProvider.js';
}

// The rectangle must not be outside the bounds allowed by the tiling scheme.
if (rectangle.west < tilingScheme.rectangle.west) {
rectangle.west = tilingScheme.rectangle.west;
}
if (rectangle.east > tilingScheme.rectangle.east) {
rectangle.east = tilingScheme.rectangle.east;
}
if (rectangle.south < tilingScheme.rectangle.south) {
rectangle.south = tilingScheme.rectangle.south;
}
if (rectangle.north > tilingScheme.rectangle.north) {
rectangle.north = tilingScheme.rectangle.north;
}

// Check the number of tiles at the minimum level. If it's more than four,
// try requesting the lower levels anyway, because starting at the higher minimum
// level will cause too many tiles to be downloaded and rendered.
var swTile = tilingScheme.positionToTileXY(Rectangle.southwest(rectangle), minimumLevel);
var neTile = tilingScheme.positionToTileXY(Rectangle.northeast(rectangle), minimumLevel);
var tileCount = (Math.abs(neTile.x - swTile.x) + 1) * (Math.abs(neTile.y - swTile.y) + 1);
if (tileCount > 4) {
minimumLevel = 0;
}
rectangle = confineRectangleToTilingScheme(rectangle, tilingScheme);
// clamp our minimum detail level to something that isn't going to request a ridiculous number of tiles
minimumLevel = calculateSafeMinimumDetailLevel(tilingScheme, rectangle, minimumLevel);

var templateResource = this._tmsResource.getDerivedResource({
url : '{z}/{x}/{reverseY}.' + fileExtension
Expand All @@ -267,10 +280,15 @@ import UrlTemplateImageryProvider from './UrlTemplateImageryProvider.js';
var fileExtension = defaultValue(options.fileExtension, 'png');
var tileWidth = defaultValue(options.tileWidth, 256);
var tileHeight = defaultValue(options.tileHeight, 256);
var minimumLevel = defaultValue(options.minimumLevel, 0);
var maximumLevel = options.maximumLevel;
var tilingScheme = defined(options.tilingScheme) ? options.tilingScheme : new WebMercatorTilingScheme({ellipsoid : options.ellipsoid});

var rectangle = defaultValue(options.rectangle, tilingScheme.rectangle);
// The rectangle must not be outside the bounds allowed by the tiling scheme.
rectangle = confineRectangleToTilingScheme(rectangle, tilingScheme);

// make sure we use a safe minimum detail level, so we don't request a ridiculous number of tiles
var minimumLevel = calculateSafeMinimumDetailLevel(tilingScheme, rectangle, options.maximumLevel);

var templateResource = this._tmsResource.getDerivedResource({
url : '{z}/{x}/{reverseY}.' + fileExtension
Expand Down
Loading