diff --git a/Source/Core/Resource.js b/Source/Core/Resource.js index 54afd88ea9d0..00c387e0ab32 100644 --- a/Source/Core/Resource.js +++ b/Source/Core/Resource.js @@ -957,6 +957,8 @@ define([ window.URL.revokeObjectURL(generatedBlobResource.url); } + error.blob = generatedBlob; + return when.reject(error); }); }; diff --git a/Source/Scene/BingMapsImageryProvider.js b/Source/Scene/BingMapsImageryProvider.js index a403bd1338de..d17d2a57de9b 100644 --- a/Source/Scene/BingMapsImageryProvider.js +++ b/Source/Scene/BingMapsImageryProvider.js @@ -18,6 +18,7 @@ define([ '../ThirdParty/when', './BingMapsStyle', './DiscardMissingTileImagePolicy', + './DiscardEmptyTileImagePolicy', './ImageryProvider' ], function( BingMapsApi, @@ -39,6 +40,7 @@ define([ when, BingMapsStyle, DiscardMissingTileImagePolicy, + DiscardEmptyTilePolicy, ImageryProvider) { 'use strict'; @@ -61,15 +63,16 @@ define([ * for information on the supported cultures. * @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used. * @param {TileDiscardPolicy} [options.tileDiscardPolicy] The policy that determines if a tile - * is invalid and should be discarded. If this value is not specified, a default - * {@link DiscardMissingTileImagePolicy} is used which requests - * tile 0,0 at the maximum tile level and checks pixels (0,0), (120,140), (130,160), - * (200,50), and (200,200). If all of these pixels are transparent, the discard check is - * disabled and no tiles are discarded. If any of them have a non-transparent color, any - * tile that has the same values in these pixel locations is discarded. The end result of - * these defaults should be correct tile discarding for a standard Bing Maps server. To ensure - * that no tiles are discarded, construct and pass a {@link NeverTileDiscardPolicy} for this - * parameter. + * is invalid and should be discarded. The default value will depend on the map style. If + * `BingMapsStyle.AERIAL_WITH_LABELS_ON_DEMAND` or `BingMapsStyle.ROADS_ON_DEMAND` is used, then a + * {@link DiscardEmptyTileImagePolicy} will be used to handle the Bing Maps API sending no content instead of + * a missing tile image, a behaviour specific to that imagery set. In all over cases, a default + * {@link DiscardMissingTileImagePolicy} is used which requests tile 0,0 at the maximum tile level and checks + * pixels (0,0), (120,140), (130,160), (200,50), and (200,200). If all of these pixels are transparent, the + * discard check is disabled and no tiles are discarded. If any of them have a non-transparent color, any + * tile that has the same values in these pixel locations is discarded. The end result of these defaults + * should be correct tile discarding for a standard Bing Maps server. To ensure that no tiles are discarded, + * construct and pass a {@link NeverTileDiscardPolicy} for this parameter. * * @see ArcGisMapServerImageryProvider * @see GoogleEarthEnterpriseMapsProvider @@ -171,11 +174,18 @@ define([ // Install the default tile discard policy if none has been supplied. if (!defined(that._tileDiscardPolicy)) { - that._tileDiscardPolicy = new DiscardMissingTileImagePolicy({ - missingImageUrl : buildImageResource(that, 0, 0, that._maximumLevel).url, - pixelsToCheck : [new Cartesian2(0, 0), new Cartesian2(120, 140), new Cartesian2(130, 160), new Cartesian2(200, 50), new Cartesian2(200, 200)], - disableCheckIfAllPixelsAreTransparent : true - }); + // Our default depends on which map style we're using. + if (that._mapStyle === BingMapsStyle.AERIAL_WITH_LABELS_ON_DEMAND + || that._mapStyle === BingMapsStyle.ROAD_ON_DEMAND) { + // this map style uses a different API, which returns a tile with no data instead of a placeholder image + that._tileDiscardPolicy = new DiscardEmptyTilePolicy(); + } else { + that._tileDiscardPolicy = new DiscardMissingTileImagePolicy({ + missingImageUrl : buildImageResource(that, 0, 0, that._maximumLevel).url, + pixelsToCheck : [new Cartesian2(0, 0), new Cartesian2(120, 140), new Cartesian2(130, 160), new Cartesian2(200, 50), new Cartesian2(200, 200)], + disableCheckIfAllPixelsAreTransparent : true + }); + } } var attributionList = that._attributionList = resource.imageryProviders; @@ -533,7 +543,23 @@ define([ } //>>includeEnd('debug'); - return ImageryProvider.loadImage(this, buildImageResource(this, x, y, level, request)); + var promise = ImageryProvider.loadImage(this, buildImageResource(this, x, y, level, request)); + + if (defined(promise)) { + return promise.otherwise(function(error) { + + // One possible cause of an error here is that the image we tried to load was empty. This isn't actually + // a problem. In some imagery sets (eg. `BingMapsStyle.AERIAL_WITH_LABELS_ON_DEMAND`), an empty image is + // returned rather than a blank "This Image is Missing" placeholder image. In this case, we supress the + // error. + if (defined(error.blob) && error.blob.size === 0) { + return DiscardEmptyTilePolicy.EMPTY_IMAGE; + } + return when.reject(error); + }); + } + + return undefined; }; /** diff --git a/Source/Scene/BingMapsStyle.js b/Source/Scene/BingMapsStyle.js index 1415ed6f0220..151d23f3e3ba 100644 --- a/Source/Scene/BingMapsStyle.js +++ b/Source/Scene/BingMapsStyle.js @@ -25,17 +25,37 @@ define([ * * @type {String} * @constant + * @deprecated See https://github.com/AnalyticalGraphicsInc/cesium/issues/7128. + * Use `BingMapsStyle.AERIAL_WITH_LABELS_ON_DEMAND` instead */ AERIAL_WITH_LABELS : 'AerialWithLabels', + /** + * Aerial imagery with a road overlay. + * + * @type {String} + * @constant + */ + AERIAL_WITH_LABELS_ON_DEMAND : 'AerialWithLabelsOnDemand', + /** * Roads without additional imagery. * * @type {String} * @constant + * @deprecated See https://github.com/AnalyticalGraphicsInc/cesium/issues/7128. + * Use `BingMapsStyle.ROAD_ON_DEMAND` instead */ ROAD : 'Road', + /** + * Roads without additional imagery. + * + * @type {String} + * @constant + */ + ROAD_ON_DEMAND : 'RoadOnDemand', + /** * A dark version of the road maps. * diff --git a/Source/Scene/DiscardEmptyTileImagePolicy.js b/Source/Scene/DiscardEmptyTileImagePolicy.js new file mode 100644 index 000000000000..f63dbaed3ea6 --- /dev/null +++ b/Source/Scene/DiscardEmptyTileImagePolicy.js @@ -0,0 +1,43 @@ +define([ + '../Core/defined', + '../Core/defaultValue' +], function( + defined, + defaultValue) { + + /** + * A policy for discarding tile images that contain no data (and so aren't actually images). + * + * @alias DiscardEmptyTileImagePolicy + * @constructor + * + * @see DiscardMissingTileImagePolicy + */ + function DiscardEmptyTileImagePolicy(options) { + } + + /** + * Determines if the discard policy is ready to process images. + * @returns {Boolean} True if the discard policy is ready to process images; otherwise, false. + */ + DiscardEmptyTileImagePolicy.prototype.isReady = function() { + return true; + }; + + /** + * Given a tile image, decide whether to discard that image. + * + * @param {Image} image An image to test. + * @returns {Boolean} True if the image should be discarded; otherwise, false. + */ + DiscardEmptyTileImagePolicy.prototype.shouldDiscardImage = function(image) { + return DiscardEmptyTileImagePolicy.EMPTY_IMAGE === image; + }; + + /** + * Default value for representing an empty image. + */ + DiscardEmptyTileImagePolicy.EMPTY_IMAGE = {}; + + return DiscardEmptyTileImagePolicy; +});