Skip to content

Commit 9966a08

Browse files
committed
Use DiscardEmptyTileImagePolicy for all Bing styles.
This removes the need to inspect pixel values to detect the placeholder "missing tile" image. Also change `DiscardEmptyTileImagePolicy.EMPTY_IMAGE` to be a real (blank) image. This way we always satisfy the documented API of `requestImage`. Fixes #1353.
1 parent f84594a commit 9966a08

6 files changed

+58
-62
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Change Log
44

55
##### Additions :tada:
66
* Added support for new `BingMapsStyle` values `ROAD_ON_DEMAND` and `AERIAL_WITH_LABELS_ON_DEMAND`. The older versions of these, `ROAD` and `AERIAL_WITH_LABELS`, have been deprecated by Bing. [#7808](https://github.com/AnalyticalGraphicsInc/cesium/pull/7808)
7+
* `BingMapsImageryProvider` now uses `DiscardEmptyTileImagePolicy` by default to detect missing tiles as zero-length responses instead of inspecting pixel values. [#7810](https://github.com/AnalyticalGraphicsInc/cesium/pull/7810)
78

89
### 1.57 - 2019-05-01
910

Source/Core/Resource.js

+8-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ define([
1010
'./defineProperties',
1111
'./DeveloperError',
1212
'./freezeObject',
13-
'./FeatureDetection',
1413
'./getAbsoluteUri',
1514
'./getBaseUri',
1615
'./getExtensionFromUri',
@@ -38,7 +37,6 @@ define([
3837
defineProperties,
3938
DeveloperError,
4039
freezeObject,
41-
FeatureDetection,
4240
getAbsoluteUri,
4341
getBaseUri,
4442
getExtensionFromUri,
@@ -929,9 +927,11 @@ define([
929927
if (!defined(image)) {
930928
return;
931929
}
932-
// This is because the blob object is needed for DiscardMissingTileImagePolicy
933-
// See https://github.com/AnalyticalGraphicsInc/cesium/issues/1353
930+
931+
// The blob object may be needed for use by a TileDiscardPolicy,
932+
// so attach it to the image.
934933
image.blob = generatedBlob;
934+
935935
if (useImageBitmap) {
936936
return image;
937937
}
@@ -944,8 +944,10 @@ define([
944944
window.URL.revokeObjectURL(generatedBlobResource.url);
945945
}
946946

947-
// If the blob load succeeded but the image decode failed, provide access to the blob on the error object because it may provide useful insight.
948-
// In particular, BingMapsImageryProvider uses this to detect the zero-length "image" that some map styles return when a real tile is not available.
947+
// If the blob load succeeded but the image decode failed, attach the blob
948+
// to the error object for use by a TileDiscardPolicy.
949+
// In particular, BingMapsImageryProvider uses this to detect the
950+
// zero-length response that is returned when a tile is not available.
949951
error.blob = generatedBlob;
950952

951953
return when.reject(error);

Source/Scene/BingMapsImageryProvider.js

+16-35
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
define([
22
'../Core/BingMapsApi',
33
'../Core/buildModuleUrl',
4-
'../Core/Cartesian2',
54
'../Core/Check',
65
'../Core/Credit',
76
'../Core/defaultValue',
@@ -17,13 +16,11 @@ define([
1716
'../Core/WebMercatorTilingScheme',
1817
'../ThirdParty/when',
1918
'./BingMapsStyle',
20-
'./DiscardMissingTileImagePolicy',
2119
'./DiscardEmptyTileImagePolicy',
2220
'./ImageryProvider'
2321
], function(
2422
BingMapsApi,
2523
buildModuleUrl,
26-
Cartesian2,
2724
Check,
2825
Credit,
2926
defaultValue,
@@ -39,7 +36,6 @@ define([
3936
WebMercatorTilingScheme,
4037
when,
4138
BingMapsStyle,
42-
DiscardMissingTileImagePolicy,
4339
DiscardEmptyTilePolicy,
4440
ImageryProvider) {
4541
'use strict';
@@ -63,16 +59,9 @@ define([
6359
* for information on the supported cultures.
6460
* @param {Ellipsoid} [options.ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used.
6561
* @param {TileDiscardPolicy} [options.tileDiscardPolicy] The policy that determines if a tile
66-
* is invalid and should be discarded. The default value will depend on the map style. If
67-
* `BingMapsStyle.AERIAL_WITH_LABELS_ON_DEMAND` or `BingMapsStyle.ROADS_ON_DEMAND` is used, then a
68-
* {@link DiscardEmptyTileImagePolicy} will be used to handle the Bing Maps API sending no content instead of
69-
* a missing tile image, a behaviour specific to that imagery set. In all other cases, a default
70-
* {@link DiscardMissingTileImagePolicy} is used which requests tile 0,0 at the maximum tile level and checks
71-
* pixels (0,0), (120,140), (130,160), (200,50), and (200,200). If all of these pixels are transparent, the
72-
* discard check is disabled and no tiles are discarded. If any of them have a non-transparent color, any
73-
* tile that has the same values in these pixel locations is discarded. The end result of these defaults
74-
* should be correct tile discarding for a standard Bing Maps server. To ensure that no tiles are discarded,
75-
* construct and pass a {@link NeverTileDiscardPolicy} for this parameter.
62+
* is invalid and should be discarded. By default, a {@link DiscardEmptyTileImagePolicy}
63+
* will be used, with the expectation that the Bing Maps server will send a zero-length response for missing tiles.
64+
* To ensure that no tiles are discarded, construct and pass a {@link NeverTileDiscardPolicy} for this parameter.
7665
*
7766
* @see ArcGisMapServerImageryProvider
7867
* @see GoogleEarthEnterpriseMapsProvider
@@ -109,7 +98,12 @@ define([
10998
this._tileProtocol = options.tileProtocol;
11099
this._mapStyle = defaultValue(options.mapStyle, BingMapsStyle.AERIAL);
111100
this._culture = defaultValue(options.culture, '');
101+
112102
this._tileDiscardPolicy = options.tileDiscardPolicy;
103+
if (!defined(this._tileDiscardPolicy)) {
104+
this._tileDiscardPolicy = new DiscardEmptyTilePolicy();
105+
}
106+
113107
this._proxy = options.proxy;
114108
this._credit = new Credit('<a href="http://www.bing.com"><img src="' + BingMapsImageryProvider.logoUrl + '" title="Bing Imagery"/></a>');
115109

@@ -172,22 +166,6 @@ define([
172166

173167
that._imageUrlTemplate = that._imageUrlTemplate.replace(/^http:/, tileProtocol);
174168

175-
// Install the default tile discard policy if none has been supplied.
176-
if (!defined(that._tileDiscardPolicy)) {
177-
// Our default depends on which map style we're using.
178-
if (that._mapStyle === BingMapsStyle.AERIAL_WITH_LABELS_ON_DEMAND
179-
|| that._mapStyle === BingMapsStyle.ROAD_ON_DEMAND) {
180-
// this map style uses a different API, which returns a tile with no data instead of a placeholder image
181-
that._tileDiscardPolicy = new DiscardEmptyTilePolicy();
182-
} else {
183-
that._tileDiscardPolicy = new DiscardMissingTileImagePolicy({
184-
missingImageUrl : buildImageResource(that, 0, 0, that._maximumLevel).url,
185-
pixelsToCheck : [new Cartesian2(0, 0), new Cartesian2(120, 140), new Cartesian2(130, 160), new Cartesian2(200, 50), new Cartesian2(200, 200)],
186-
disableCheckIfAllPixelsAreTransparent : true
187-
});
188-
}
189-
}
190-
191169
var attributionList = that._attributionList = resource.imageryProviders;
192170
if (!attributionList) {
193171
attributionList = that._attributionList = [];
@@ -547,11 +525,9 @@ define([
547525

548526
if (defined(promise)) {
549527
return promise.otherwise(function(error) {
550-
551-
// One possible cause of an error here is that the image we tried to load was empty. This isn't actually
552-
// a problem. In some imagery sets (eg. `BingMapsStyle.AERIAL_WITH_LABELS_ON_DEMAND`), an empty image is
553-
// returned rather than a blank "This Image is Missing" placeholder image. In this case, we supress the
554-
// error.
528+
// One cause of an error here is that the image we tried to load was zero-length.
529+
// This isn't actually a problem, since it indicates that there is no tile.
530+
// So, in that case we return the EMPTY_IMAGE sentinel value for later discarding.
555531
if (defined(error.blob) && error.blob.size === 0) {
556532
return DiscardEmptyTilePolicy.EMPTY_IMAGE;
557533
}
@@ -680,6 +656,11 @@ define([
680656
quadkey: BingMapsImageryProvider.tileXYToQuadKey(x, y, level),
681657
subdomain: subdomains[subdomainIndex],
682658
culture: imageryProvider._culture
659+
},
660+
queryParameters: {
661+
// this parameter tells the Bing servers to send a zero-length response
662+
// instead of a placeholder image for missing tiles.
663+
n: 'z'
683664
}
684665
});
685666
}

Source/Scene/DiscardEmptyTileImagePolicy.js

+26-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
define([
2-
'../Core/defined',
3-
'../Core/defaultValue'
4-
], function(
2+
'../Core/defined',
3+
'../Core/defineProperties'
4+
], function(
55
defined,
6-
defaultValue) {
6+
defineProperties) {
77
'use strict';
88

99
/**
1010
* A policy for discarding tile images that contain no data (and so aren't actually images).
11+
* This policy discards {@link DiscardEmptyTileImagePolicy.EMPTY_IMAGE}, which is
12+
* expected to be used in place of any empty tile images by the image loading code.
1113
*
1214
* @alias DiscardEmptyTileImagePolicy
1315
* @constructor
@@ -35,10 +37,26 @@ define([
3537
return DiscardEmptyTileImagePolicy.EMPTY_IMAGE === image;
3638
};
3739

38-
/**
39-
* Default value for representing an empty image.
40-
*/
41-
DiscardEmptyTileImagePolicy.EMPTY_IMAGE = {};
40+
var emptyImage;
41+
42+
defineProperties(DiscardEmptyTileImagePolicy, {
43+
/**
44+
* Default value for representing an empty image.
45+
* @type {Image}
46+
* @readonly
47+
* @memberof DiscardEmptyTileImagePolicy
48+
*/
49+
EMPTY_IMAGE: {
50+
get: function() {
51+
if (!defined(emptyImage)) {
52+
emptyImage = new Image();
53+
// load a blank data URI with a 1x1 transparent pixel.
54+
emptyImage.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
55+
}
56+
return emptyImage;
57+
}
58+
}
59+
});
4260

4361
return DiscardEmptyTileImagePolicy;
4462
});

Source/Scene/DiscardMissingTileImagePolicy.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@ define([
33
'../Core/defined',
44
'../Core/DeveloperError',
55
'../Core/getImagePixels',
6-
'../Core/Resource',
7-
'../ThirdParty/when'
6+
'../Core/Resource'
87
], function(
98
defaultValue,
109
defined,
1110
DeveloperError,
1211
getImagePixels,
13-
Resource,
14-
when) {
12+
Resource) {
1513
'use strict';
1614

1715
/**

Specs/Scene/BingMapsImageryProviderSpec.js

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,37 @@
11
defineSuite([
22
'Scene/BingMapsImageryProvider',
33
'Core/appendForwardSlash',
4-
'Core/DefaultProxy',
54
'Core/defined',
65
'Core/queryToObject',
76
'Core/RequestScheduler',
87
'Core/Resource',
98
'Core/WebMercatorTilingScheme',
109
'Scene/BingMapsStyle',
11-
'Scene/DiscardMissingTileImagePolicy',
10+
'Scene/DiscardEmptyTileImagePolicy',
1211
'Scene/Imagery',
1312
'Scene/ImageryLayer',
1413
'Scene/ImageryProvider',
1514
'Scene/ImageryState',
1615
'Specs/pollToPromise',
1716
'ThirdParty/Uri',
18-
'ThirdParty/when',
19-
'Scene/DiscardEmptyTileImagePolicy'
17+
'ThirdParty/when'
2018
], function(
2119
BingMapsImageryProvider,
2220
appendForwardSlash,
23-
DefaultProxy,
2421
defined,
2522
queryToObject,
2623
RequestScheduler,
2724
Resource,
2825
WebMercatorTilingScheme,
2926
BingMapsStyle,
30-
DiscardMissingTileImagePolicy,
27+
DiscardEmptyTileImagePolicy,
3128
Imagery,
3229
ImageryLayer,
3330
ImageryProvider,
3431
ImageryState,
3532
pollToPromise,
3633
Uri,
37-
when,
38-
DiscardEmptyTileImagePolicy) {
34+
when) {
3935
'use strict';
4036

4137
var supportsImageBitmapOptions;
@@ -366,7 +362,7 @@ defineSuite([
366362
expect(provider.tileHeight).toEqual(256);
367363
expect(provider.maximumLevel).toEqual(20);
368364
expect(provider.tilingScheme).toBeInstanceOf(WebMercatorTilingScheme);
369-
expect(provider.tileDiscardPolicy).toBeInstanceOf(DiscardMissingTileImagePolicy);
365+
expect(provider.tileDiscardPolicy).toBeInstanceOf(DiscardEmptyTileImagePolicy);
370366
expect(provider.rectangle).toEqual(new WebMercatorTilingScheme().rectangle);
371367
expect(provider.credit).toBeInstanceOf(Object);
372368

0 commit comments

Comments
 (0)