diff --git a/Source/Scene/ArcGisMapServerImageryProvider.js b/Source/Scene/ArcGisMapServerImageryProvider.js
index 8575ef77babd..cbe2ea3a4589 100644
--- a/Source/Scene/ArcGisMapServerImageryProvider.js
+++ b/Source/Scene/ArcGisMapServerImageryProvider.js
@@ -256,6 +256,23 @@ define([
return this._maximumLevel;
};
+ /**
+ * Gets the minimum level-of-detail that can be requested. This function should
+ * not be called before {@link ArcGisMapServerImageryProvider#isReady} returns true.
+ *
+ * @memberof ArcGisMapServerImageryProvider
+ *
+ * @returns {Number} The minimum level. Unlike the maximum level, the minimum level must not be undefined.
+ *
+ * @exception {DeveloperError} getMinimumLevel
must not be called before the imagery provider is ready.
+ */
+ ArcGisMapServerImageryProvider.prototype.getMinimumLevel = function() {
+ if (!this._ready) {
+ throw new DeveloperError('getMinimumLevel must not be called before the imagery provider is ready.');
+ }
+ return 0;
+ };
+
/**
* Gets the tiling scheme used by this provider. This function should
* not be called before {@link ArcGisMapServerImageryProvider#isReady} returns true.
diff --git a/Source/Scene/BingMapsImageryProvider.js b/Source/Scene/BingMapsImageryProvider.js
index fe819618679c..f5b71316a255 100644
--- a/Source/Scene/BingMapsImageryProvider.js
+++ b/Source/Scene/BingMapsImageryProvider.js
@@ -307,6 +307,23 @@ define([
return this._maximumLevel;
};
+ /**
+ * Gets the minimum level-of-detail that can be requested. This function should
+ * not be called before {@link BingMapsImageryProvider#isReady} returns true.
+ *
+ * @memberof BingMapsImageryProvider
+ *
+ * @returns {Number} The minimum level. Unlike the maximum level, the minimum level must not be undefined.
+ *
+ * @exception {DeveloperError} getMinimumLevel
must not be called before the imagery provider is ready.
+ */
+ BingMapsImageryProvider.prototype.getMinimumLevel = function() {
+ if (!this._ready) {
+ throw new DeveloperError('getMinimumLevel must not be called before the imagery provider is ready.');
+ }
+ return 0;
+ };
+
/**
* Gets the tiling scheme used by this provider. This function should
* not be called before {@link BingMapsImageryProvider#isReady} returns true.
diff --git a/Source/Scene/CentralBodySurface.js b/Source/Scene/CentralBodySurface.js
index 022b099ef4f0..13b91d87e52c 100644
--- a/Source/Scene/CentralBodySurface.js
+++ b/Source/Scene/CentralBodySurface.js
@@ -670,7 +670,7 @@ define([
if (imageryLayer.getImageryProvider().isReady()) {
// Remove the placeholder and add the actual skeletons (if any)
// at the same position. Then continue the loop at the same index.
- imagery.releaseReference();
+ tileImagery.freeResources();
tileImageryCollection.splice(i, 1);
imageryLayer._createTileImagerySkeletons(tile, terrainProvider, i);
--i;
@@ -704,6 +704,15 @@ define([
parent = parent.parent;
}
+ // If there's no valid parent, remove this TileImagery from the tile.
+ if (typeof parent === 'undefined') {
+ tileImagery.freeResources();
+ tileImageryCollection.splice(i, 1);
+ --i;
+ len = tileImageryCollection.length;
+ continue;
+ }
+
// use that parent imagery instead, storing the original imagery
// in originalImagery to keep it alive
tileImagery.originalImagery = imagery;
diff --git a/Source/Scene/ImageryLayer.js b/Source/Scene/ImageryLayer.js
index c4fcaa5076f4..5d37d6323f73 100755
--- a/Source/Scene/ImageryLayer.js
+++ b/Source/Scene/ImageryLayer.js
@@ -260,9 +260,13 @@ define([
var imageryLevel = getLevelWithMaximumTexelSpacing(this, targetGeometricError, latitudeClosestToEquator);
imageryLevel = Math.max(0, imageryLevel);
var maximumLevel = imageryProvider.getMaximumLevel();
+ var minimumLevel = imageryProvider.getMinimumLevel();
if (imageryLevel > maximumLevel) {
imageryLevel = maximumLevel;
}
+ if (imageryLevel < minimumLevel) {
+ imageryLevel = minimumLevel;
+ }
var imageryTilingScheme = imageryProvider.getTilingScheme();
var northwestTileCoordinates = imageryTilingScheme.positionToTileXY(extent.getNorthwest(), imageryLevel);
diff --git a/Source/Scene/ImageryProvider.js b/Source/Scene/ImageryProvider.js
index 026ab5976a3e..bd1a43ad0fd4 100755
--- a/Source/Scene/ImageryProvider.js
+++ b/Source/Scene/ImageryProvider.js
@@ -83,6 +83,18 @@ define([
throw new DeveloperError('This type should not be instantiated directly.');
};
+ /**
+ * Gets the minimum level-of-detail that can be requested. This function should
+ * not be called before {@link ImageryProvider#isReady} returns true.
+ *
+ * @returns {Number} The minimum level. Unlike the maximum level, the minimum level must not be undefined.
+ *
+ * @exception {DeveloperError} getMinimumLevel
must not be called before the imagery provider is ready.
+ */
+ ImageryProvider.prototype.getMinimumLevel = function() {
+ throw new DeveloperError('This type should not be instantiated directly.');
+ };
+
/**
* Gets the tiling scheme used by this provider. This function should
* not be called before {@link ImageryProvider#isReady} returns true.
diff --git a/Source/Scene/OpenStreetMapImageryProvider.js b/Source/Scene/OpenStreetMapImageryProvider.js
index 0cda620a7835..f1925bbfcbe3 100644
--- a/Source/Scene/OpenStreetMapImageryProvider.js
+++ b/Source/Scene/OpenStreetMapImageryProvider.js
@@ -153,6 +153,23 @@ define([
return this._maximumLevel;
};
+ /**
+ * Gets the minimum level-of-detail that can be requested. This function should
+ * not be called before {@link OpenStreetMapImageryProvider#isReady} returns true.
+ *
+ * @memberof OpenStreetMapImageryProvider
+ *
+ * @returns {Number} The minimum level. Unlike the maximum level, the minimum level must not be undefined.
+ *
+ * @exception {DeveloperError} getMinimumLevel
must not be called before the imagery provider is ready.
+ */
+ OpenStreetMapImageryProvider.prototype.getMinimumLevel = function() {
+ if (!this._ready) {
+ throw new DeveloperError('getMinimumLevel must not be called before the imagery provider is ready.');
+ }
+ return 0;
+ };
+
/**
* Gets the tiling scheme used by this provider. This function should
* not be called before {@link OpenStreetMapImageryProvider#isReady} returns true.
diff --git a/Source/Scene/SingleTileImageryProvider.js b/Source/Scene/SingleTileImageryProvider.js
index c2853887eeaf..a2936e12e3e2 100644
--- a/Source/Scene/SingleTileImageryProvider.js
+++ b/Source/Scene/SingleTileImageryProvider.js
@@ -174,6 +174,23 @@ define([
return 0;
};
+ /**
+ * Gets the minimum level-of-detail that can be requested. This function should
+ * not be called before {@link SingleTileImageryProvider#isReady} returns true.
+ *
+ * @memberof SingleTileImageryProvider
+ *
+ * @returns {Number} The minimum level. Unlike the maximum level, the minimum level must not be undefined.
+ *
+ * @exception {DeveloperError} getMinimumLevel
must not be called before the imagery provider is ready.
+ */
+ SingleTileImageryProvider.prototype.getMinimumLevel = function() {
+ if (!this._ready) {
+ throw new DeveloperError('getMinimumLevel must not be called before the imagery provider is ready.');
+ }
+ return 0;
+ };
+
/**
* Gets the tiling scheme used by this provider. This function should
* not be called before {@link SingleTileImageryProvider#isReady} returns true.
diff --git a/Source/Scene/WebMapServiceImageryProvider.js b/Source/Scene/WebMapServiceImageryProvider.js
index 339a9ce642ce..fc0e0e52d6d4 100644
--- a/Source/Scene/WebMapServiceImageryProvider.js
+++ b/Source/Scene/WebMapServiceImageryProvider.js
@@ -229,6 +229,23 @@ define([
return this._maximumLevel;
};
+ /**
+ * Gets the minimum level-of-detail that can be requested. This function should
+ * not be called before {@link WebMapServiceImageryProvider#isReady} returns true.
+ *
+ * @memberof WebMapServiceImageryProvider
+ *
+ * @returns {Number} The minimum level. Unlike the maximum level, the minimum level must not be undefined.
+ *
+ * @exception {DeveloperError} getMinimumLevel
must not be called before the imagery provider is ready.
+ */
+ WebMapServiceImageryProvider.prototype.getMinimumLevel = function() {
+ if (!this._ready) {
+ throw new DeveloperError('getMinimumLevel must not be called before the imagery provider is ready.');
+ }
+ return 0;
+ };
+
/**
* Gets the tiling scheme used by this provider. This function should
* not be called before {@link WebMapServiceImageryProvider#isReady} returns true.
diff --git a/Specs/Scene/ArcGisMapServerImageryProviderSpec.js b/Specs/Scene/ArcGisMapServerImageryProviderSpec.js
index 9ac2f60ff3a3..cc7867d9bc58 100644
--- a/Specs/Scene/ArcGisMapServerImageryProviderSpec.js
+++ b/Specs/Scene/ArcGisMapServerImageryProviderSpec.js
@@ -88,6 +88,7 @@ defineSuite([
runs(function() {
expect(provider.getTileWidth()).toEqual(128);
expect(provider.getTileHeight()).toEqual(256);
+ expect(provider.getMinimumLevel()).toEqual(0);
expect(provider.getMaximumLevel()).toEqual(2);
expect(provider.getTilingScheme()).toBeInstanceOf(WebMercatorTilingScheme);
expect(provider.getLogo()).not.toBeUndefined();
@@ -161,6 +162,7 @@ defineSuite([
runs(function() {
expect(provider.getTileWidth()).toEqual(128);
expect(provider.getTileHeight()).toEqual(256);
+ expect(provider.getMinimumLevel()).toEqual(0);
expect(provider.getMaximumLevel()).toEqual(2);
expect(provider.getTilingScheme()).toBeInstanceOf(GeographicTilingScheme);
expect(provider.getLogo()).not.toBeUndefined();
@@ -218,6 +220,7 @@ defineSuite([
runs(function() {
expect(provider.getTileWidth()).toEqual(256);
expect(provider.getTileHeight()).toEqual(256);
+ expect(provider.getMinimumLevel()).toEqual(0);
expect(provider.getMaximumLevel()).toBeUndefined();
expect(provider.getTilingScheme()).toBeInstanceOf(GeographicTilingScheme);
expect(provider.getLogo()).not.toBeUndefined();
@@ -303,6 +306,7 @@ defineSuite([
runs(function() {
expect(provider.getTileWidth()).toEqual(128);
expect(provider.getTileHeight()).toEqual(256);
+ expect(provider.getMinimumLevel()).toEqual(0);
expect(provider.getMaximumLevel()).toEqual(2);
expect(provider.getTilingScheme()).toBeInstanceOf(GeographicTilingScheme);
expect(provider.getLogo()).not.toBeUndefined();
diff --git a/Specs/Scene/BingMapsImageryProviderSpec.js b/Specs/Scene/BingMapsImageryProviderSpec.js
index d844691996b5..2173e9311158 100644
--- a/Specs/Scene/BingMapsImageryProviderSpec.js
+++ b/Specs/Scene/BingMapsImageryProviderSpec.js
@@ -180,6 +180,7 @@ defineSuite([
runs(function() {
expect(provider.getTileWidth()).toEqual(256);
expect(provider.getTileHeight()).toEqual(256);
+ expect(provider.getMinimumLevel()).toEqual(0);
expect(provider.getMaximumLevel()).toEqual(20);
expect(provider.getTilingScheme()).toBeInstanceOf(WebMercatorTilingScheme);
expect(provider.getTileDiscardPolicy()).toBeInstanceOf(DiscardMissingTileImagePolicy);
diff --git a/Specs/Scene/CentralBodySurfaceSpec.js b/Specs/Scene/CentralBodySurfaceSpec.js
index ec35301d6dda..eb00a223d9ec 100644
--- a/Specs/Scene/CentralBodySurfaceSpec.js
+++ b/Specs/Scene/CentralBodySurfaceSpec.js
@@ -17,7 +17,8 @@ defineSuite([
'Scene/ImageryLayerCollection',
'Scene/OrthographicFrustum',
'Scene/SceneMode',
- 'Scene/SingleTileImageryProvider'
+ 'Scene/SingleTileImageryProvider',
+ 'Scene/WebMapServiceImageryProvider'
], function(
CentralBodySurface,
createContext,
@@ -36,7 +37,8 @@ defineSuite([
ImageryLayerCollection,
OrthographicFrustum,
SceneMode,
- SingleTileImageryProvider) {
+ SingleTileImageryProvider,
+ WebMapServiceImageryProvider) {
"use strict";
/*global jasmine,describe,xdescribe,it,xit,expect,beforeEach,afterEach,beforeAll,afterAll,spyOn,runs,waits,waitsFor*/
@@ -346,5 +348,25 @@ defineSuite([
expect(render(context, frameState, cb)).toBeGreaterThan(0);
});
});
+
+ it('renders even if imagery root tiles fail to load', function() {
+ var layerCollection = cb.getImageryLayers();
+ layerCollection.removeAll();
+
+ var providerWithInvalidRootTiles = new WebMapServiceImageryProvider({
+ url : '/invalid',
+ layers : 'invalid'
+ });
+
+ layerCollection.addImageryProvider(providerWithInvalidRootTiles);
+
+ frameState.camera.viewExtent(new Extent(0.0001, 0.0001, 0.0025, 0.0025), Ellipsoid.WGS84);
+
+ updateUntilDone(cb);
+
+ runs(function() {
+ expect(render(context, frameState, cb)).toBeGreaterThan(0);
+ });
+ });
});
});
diff --git a/Specs/Scene/ImageryLayerSpec.js b/Specs/Scene/ImageryLayerSpec.js
index 4130754a0b83..6d35aed07959 100644
--- a/Specs/Scene/ImageryLayerSpec.js
+++ b/Specs/Scene/ImageryLayerSpec.js
@@ -7,10 +7,13 @@ defineSuite([
'Core/jsonp',
'Core/loadImage',
'Scene/BingMapsImageryProvider',
+ 'Scene/EllipsoidTerrainProvider',
+ 'Scene/GeographicTilingScheme',
'Scene/Imagery',
'Scene/ImageryState',
'Scene/NeverTileDiscardPolicy',
'Scene/SingleTileImageryProvider',
+ 'Scene/Tile',
'Scene/WebMapServiceImageryProvider'
], function(
ImageryLayer,
@@ -20,10 +23,13 @@ defineSuite([
jsonp,
loadImage,
BingMapsImageryProvider,
+ EllipsoidTerrainProvider,
+ GeographicTilingScheme,
Imagery,
ImageryState,
NeverTileDiscardPolicy,
SingleTileImageryProvider,
+ Tile,
WebMapServiceImageryProvider) {
"use strict";
/*global jasmine,describe,xdescribe,it,xit,expect,beforeEach,afterEach,beforeAll,afterAll,spyOn,runs,waits,waitsFor*/
@@ -182,4 +188,51 @@ defineSuite([
expect(layer.getExtent()).toEqual(extent);
expect(layer.isDestroyed()).toEqual(false);
});
+
+ it('honors the imagery provider\'s minimum level', function() {
+ var tilingScheme = new GeographicTilingScheme();
+ var imageryProviderWithMinimumLevel = {
+ isReady : function() { return true; },
+ getExtent : function() { return Extent.MAX_VALUE; },
+ getTileWidth : function() { return 256; },
+ getTileHeight : function() { return 256; },
+ getMaximumLevel : function() { return 10; },
+ getMinimumLevel : function() { return 5; },
+ getTilingScheme : function() { return tilingScheme; },
+ getTileDiscardPolicy : function() { return undefined; },
+ getErrorEvent : function() { return undefined; },
+ getLogo : function() { return undefined; },
+ requestImage : function(hostnames, hostnameIndex, x, y, level) {
+ expect(level).toBeLessThanOrEqualTo(this.getMaximumLevel());
+ expect(level).toBeGreaterThanOrEqualTo(this.getMinimumLevel());
+ return undefined;
+ }
+ };
+
+ var layer = new ImageryLayer(imageryProviderWithMinimumLevel);
+
+ waitsFor(function() {
+ return imageryProviderWithMinimumLevel.isReady();
+ }, 'imagery provider to become ready');
+
+ runs(function() {
+ var tile = new Tile({
+ x : 0,
+ y: 0,
+ level : 0,
+ tilingScheme : tilingScheme
+ });
+ var terrainProvider = new EllipsoidTerrainProvider();
+ layer._createTileImagerySkeletons(tile, terrainProvider);
+
+ expect(tile.imagery.length).toBeGreaterThan(0);
+
+ for (var i = 0, len = tile.imagery.length; i < len; ++i) {
+ var tileImagery = tile.imagery[i];
+ var imagery = tileImagery.imagery;
+ expect(imagery.level).toBeLessThanOrEqualTo(imageryProviderWithMinimumLevel.getMaximumLevel());
+ expect(imagery.level).toBeGreaterThanOrEqualTo(imageryProviderWithMinimumLevel.getMinimumLevel());
+ }
+ });
+ });
});
diff --git a/Specs/Scene/OpenStreetMapImageryProviderSpec.js b/Specs/Scene/OpenStreetMapImageryProviderSpec.js
index 46f2f7d60327..93cd68701b3c 100644
--- a/Specs/Scene/OpenStreetMapImageryProviderSpec.js
+++ b/Specs/Scene/OpenStreetMapImageryProviderSpec.js
@@ -110,6 +110,7 @@ defineSuite([
runs(function() {
expect(provider.getTileWidth()).toEqual(256);
expect(provider.getTileHeight()).toEqual(256);
+ expect(provider.getMinimumLevel()).toEqual(0);
expect(provider.getMaximumLevel()).toEqual(18);
expect(provider.getTilingScheme()).toBeInstanceOf(WebMercatorTilingScheme);
expect(provider.getExtent()).toEqual(new WebMercatorTilingScheme().getExtent());
@@ -200,6 +201,7 @@ defineSuite([
runs(function() {
expect(provider.getTileWidth()).toEqual(256);
expect(provider.getTileHeight()).toEqual(256);
+ expect(provider.getMinimumLevel()).toEqual(0);
expect(provider.getMaximumLevel()).toEqual(18);
expect(provider.getTilingScheme()).toBeInstanceOf(WebMercatorTilingScheme);
expect(provider.getExtent()).toEqual(extent);
diff --git a/Specs/Scene/SingleTileImageryProviderSpec.js b/Specs/Scene/SingleTileImageryProviderSpec.js
index 57ffce441ae4..ae045801e410 100644
--- a/Specs/Scene/SingleTileImageryProviderSpec.js
+++ b/Specs/Scene/SingleTileImageryProviderSpec.js
@@ -59,6 +59,7 @@ defineSuite([
expect(provider.getTilingScheme().getExtent()).toEqual(extent);
expect(provider.getTileWidth()).toEqual(16);
expect(provider.getTileHeight()).toEqual(16);
+ expect(provider.getMinimumLevel()).toEqual(0);
expect(provider.getMaximumLevel()).toEqual(0);
expect(provider.getTileDiscardPolicy()).toBeUndefined();
});
diff --git a/Specs/Scene/WebMapServiceImageryProviderSpec.js b/Specs/Scene/WebMapServiceImageryProviderSpec.js
index ad419d7819df..0cce2793e276 100644
--- a/Specs/Scene/WebMapServiceImageryProviderSpec.js
+++ b/Specs/Scene/WebMapServiceImageryProviderSpec.js
@@ -195,6 +195,7 @@ defineSuite([
runs(function() {
expect(provider.getTileWidth()).toEqual(256);
expect(provider.getTileHeight()).toEqual(256);
+ expect(provider.getMinimumLevel()).toEqual(0);
expect(provider.getMaximumLevel()).toBeUndefined();
expect(provider.getTilingScheme()).toBeInstanceOf(GeographicTilingScheme);
expect(provider.getExtent()).toEqual(new GeographicTilingScheme().getExtent());
@@ -315,6 +316,7 @@ defineSuite([
runs(function() {
expect(provider.getTileWidth()).toEqual(256);
expect(provider.getTileHeight()).toEqual(256);
+ expect(provider.getMinimumLevel()).toEqual(0);
expect(provider.getMaximumLevel()).toBeUndefined();
expect(provider.getTilingScheme()).toBeInstanceOf(GeographicTilingScheme);
expect(provider.getExtent()).toEqual(extent);