BingMapsImageryProvider.js 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061
  1. import buildModuleUrl from "../Core/buildModuleUrl.js";
  2. import Check from "../Core/Check.js";
  3. import Credit from "../Core/Credit.js";
  4. import defaultValue from "../Core/defaultValue.js";
  5. import defined from "../Core/defined.js";
  6. import deprecationWarning from "../Core/deprecationWarning.js";
  7. import Event from "../Core/Event.js";
  8. import CesiumMath from "../Core/Math.js";
  9. import Rectangle from "../Core/Rectangle.js";
  10. import Resource from "../Core/Resource.js";
  11. import RuntimeError from "../Core/RuntimeError.js";
  12. import TileProviderError from "../Core/TileProviderError.js";
  13. import WebMercatorTilingScheme from "../Core/WebMercatorTilingScheme.js";
  14. import BingMapsStyle from "./BingMapsStyle.js";
  15. import DiscardEmptyTilePolicy from "./DiscardEmptyTileImagePolicy.js";
  16. import ImageryProvider from "./ImageryProvider.js";
  17. /**
  18. * @typedef {object} BingMapsImageryProvider.ConstructorOptions
  19. *
  20. * Initialization options for the BingMapsImageryProvider constructor
  21. *
  22. * @property {Resource|string} [url] The url of the Bing Maps server hosting the imagery. Deprecated.
  23. * @property {string} [key] The Bing Maps key for your application, which can be
  24. * created at {@link https://www.bingmapsportal.com/}.
  25. * @property {string} [tileProtocol] The protocol to use when loading tiles, e.g. 'http' or 'https'.
  26. * By default, tiles are loaded using the same protocol as the page.
  27. * @property {BingMapsStyle} [mapStyle=BingMapsStyle.AERIAL] The type of Bing Maps imagery to load.
  28. * @property {string} [culture=''] The culture to use when requesting Bing Maps imagery. Not
  29. * all cultures are supported. See {@link http://msdn.microsoft.com/en-us/library/hh441729.aspx}
  30. * for information on the supported cultures.
  31. * @property {Ellipsoid} [ellipsoid] The ellipsoid. If not specified, the WGS84 ellipsoid is used.
  32. * @property {TileDiscardPolicy} [tileDiscardPolicy] The policy that determines if a tile
  33. * is invalid and should be discarded. By default, a {@link DiscardEmptyTileImagePolicy}
  34. * will be used, with the expectation that the Bing Maps server will send a zero-length response for missing tiles.
  35. * To ensure that no tiles are discarded, construct and pass a {@link NeverTileDiscardPolicy} for this parameter.
  36. */
  37. /**
  38. * Used to track creation details while fetching initial metadata
  39. *
  40. * @constructor
  41. * @private
  42. *
  43. * @param {BingMapsImageryProvider.ConstructorOptions} options An object describing initialization options
  44. */
  45. function ImageryProviderBuilder(options) {
  46. this.tileWidth = undefined;
  47. this.tileHeight = undefined;
  48. this.maximumLevel = undefined;
  49. this.imageUrlSubdomains = undefined;
  50. this.imageUrlTemplate = undefined;
  51. this.attributionList = undefined;
  52. }
  53. /**
  54. * Complete BingMapsImageryProvider creation based on builder values.
  55. *
  56. * @private
  57. *
  58. * @param {BingMapsImageryProvider} provider
  59. */
  60. ImageryProviderBuilder.prototype.build = function (provider) {
  61. provider._tileWidth = this.tileWidth;
  62. provider._tileHeight = this.tileHeight;
  63. provider._maximumLevel = this.maximumLevel;
  64. provider._imageUrlSubdomains = this.imageUrlSubdomains;
  65. provider._imageUrlTemplate = this.imageUrlTemplate;
  66. let attributionList = (provider._attributionList = this.attributionList);
  67. if (!attributionList) {
  68. attributionList = [];
  69. }
  70. provider._attributionList = attributionList;
  71. for (
  72. let attributionIndex = 0, attributionLength = attributionList.length;
  73. attributionIndex < attributionLength;
  74. ++attributionIndex
  75. ) {
  76. const attribution = attributionList[attributionIndex];
  77. if (attribution.credit instanceof Credit) {
  78. // If attribution.credit has already been created
  79. // then we are using a cached value, which means
  80. // none of the remaining processing needs to be done.
  81. break;
  82. }
  83. attribution.credit = new Credit(attribution.attribution);
  84. const coverageAreas = attribution.coverageAreas;
  85. for (
  86. let areaIndex = 0, areaLength = attribution.coverageAreas.length;
  87. areaIndex < areaLength;
  88. ++areaIndex
  89. ) {
  90. const area = coverageAreas[areaIndex];
  91. const bbox = area.bbox;
  92. area.bbox = new Rectangle(
  93. CesiumMath.toRadians(bbox[1]),
  94. CesiumMath.toRadians(bbox[0]),
  95. CesiumMath.toRadians(bbox[3]),
  96. CesiumMath.toRadians(bbox[2])
  97. );
  98. }
  99. }
  100. provider._ready = true;
  101. };
  102. function metadataSuccess(data, imageryProviderBuilder) {
  103. if (data.resourceSets.length !== 1) {
  104. throw new RuntimeError(
  105. "metadata does not specify one resource in resourceSets"
  106. );
  107. }
  108. const resource = data.resourceSets[0].resources[0];
  109. imageryProviderBuilder.tileWidth = resource.imageWidth;
  110. imageryProviderBuilder.tileHeight = resource.imageHeight;
  111. imageryProviderBuilder.maximumLevel = resource.zoomMax - 1;
  112. imageryProviderBuilder.imageUrlSubdomains = resource.imageUrlSubdomains;
  113. imageryProviderBuilder.imageUrlTemplate = resource.imageUrl;
  114. imageryProviderBuilder.attributionList = resource.imageryProviders;
  115. }
  116. function metadataFailure(metadataResource, error, provider) {
  117. let message = `An error occurred while accessing ${metadataResource.url}`;
  118. if (defined(error) && defined(error.message)) {
  119. message += `: ${error.message}`;
  120. }
  121. TileProviderError.reportError(
  122. undefined,
  123. provider,
  124. defined(provider) ? provider._errorEvent : undefined,
  125. message,
  126. undefined,
  127. undefined,
  128. undefined,
  129. error
  130. );
  131. throw new RuntimeError(message);
  132. }
  133. async function requestMetadata(
  134. metadataResource,
  135. imageryProviderBuilder,
  136. provider
  137. ) {
  138. const cacheKey = metadataResource.url;
  139. let promise = BingMapsImageryProvider._metadataCache[cacheKey];
  140. if (!defined(promise)) {
  141. promise = metadataResource.fetchJsonp("jsonp");
  142. BingMapsImageryProvider._metadataCache[cacheKey] = promise;
  143. }
  144. try {
  145. const data = await promise;
  146. return metadataSuccess(data, imageryProviderBuilder);
  147. } catch (e) {
  148. metadataFailure(metadataResource, e, provider);
  149. }
  150. }
  151. /**
  152. * <div class="notice">
  153. * To construct a BingMapsImageryProvider, call {@link BingMapsImageryProvider.fromUrl}. Do not call the constructor directly.
  154. * </div>
  155. *
  156. * Provides tiled imagery using the Bing Maps Imagery REST API.
  157. *
  158. * @alias BingMapsImageryProvider
  159. * @constructor
  160. *
  161. * @param {BingMapsImageryProvider.ConstructorOptions} options Object describing initialization options
  162. *
  163. * @see BingMapsImageryProvider.fromUrl
  164. * @see ArcGisMapServerImageryProvider
  165. * @see GoogleEarthEnterpriseMapsProvider
  166. * @see OpenStreetMapImageryProvider
  167. * @see SingleTileImageryProvider
  168. * @see TileMapServiceImageryProvider
  169. * @see WebMapServiceImageryProvider
  170. * @see WebMapTileServiceImageryProvider
  171. * @see UrlTemplateImageryProvider
  172. *
  173. * @example
  174. * const bing = await Cesium.BingMapsImageryProvider.fromUrl(
  175. * "https://dev.virtualearth.net", {
  176. * key: "get-yours-at-https://www.bingmapsportal.com/",
  177. * mapStyle: Cesium.BingMapsStyle.AERIAL
  178. * });
  179. *
  180. * @see {@link http://msdn.microsoft.com/en-us/library/ff701713.aspx|Bing Maps REST Services}
  181. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  182. */
  183. function BingMapsImageryProvider(options) {
  184. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  185. this._defaultAlpha = undefined;
  186. this._defaultNightAlpha = undefined;
  187. this._defaultDayAlpha = undefined;
  188. this._defaultBrightness = undefined;
  189. this._defaultContrast = undefined;
  190. this._defaultHue = undefined;
  191. this._defaultSaturation = undefined;
  192. this._defaultGamma = 1.0;
  193. this._defaultMinificationFilter = undefined;
  194. this._defaultMagnificationFilter = undefined;
  195. this._mapStyle = defaultValue(options.mapStyle, BingMapsStyle.AERIAL);
  196. this._culture = defaultValue(options.culture, "");
  197. this._key = options.key;
  198. this._tileDiscardPolicy = options.tileDiscardPolicy;
  199. if (!defined(this._tileDiscardPolicy)) {
  200. this._tileDiscardPolicy = new DiscardEmptyTilePolicy();
  201. }
  202. this._proxy = options.proxy;
  203. this._credit = new Credit(
  204. `<a href="https://www.microsoft.com/en-us/maps/product/enduserterms"><img src="${BingMapsImageryProvider.logoUrl}" title="Bing Imagery"/></a>`
  205. );
  206. this._tilingScheme = new WebMercatorTilingScheme({
  207. numberOfLevelZeroTilesX: 2,
  208. numberOfLevelZeroTilesY: 2,
  209. ellipsoid: options.ellipsoid,
  210. });
  211. this._tileWidth = undefined;
  212. this._tileHeight = undefined;
  213. this._maximumLevel = undefined;
  214. this._imageUrlTemplate = undefined;
  215. this._imageUrlSubdomains = undefined;
  216. this._attributionList = undefined;
  217. this._errorEvent = new Event();
  218. this._ready = false;
  219. if (defined(options.url)) {
  220. deprecationWarning(
  221. "BingMapsImageryProvider options.url",
  222. "options.url was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use BingMapsImageryProvider.fromUrl instead."
  223. );
  224. //>>includeStart('debug', pragmas.debug);
  225. Check.defined("options.key", options.key);
  226. //>>includeEnd('debug');
  227. let tileProtocol = options.tileProtocol;
  228. // For backward compatibility reasons, the tileProtocol may end with
  229. // a `:`. Remove it.
  230. if (defined(tileProtocol)) {
  231. if (
  232. tileProtocol.length > 0 &&
  233. tileProtocol[tileProtocol.length - 1] === ":"
  234. ) {
  235. tileProtocol = tileProtocol.substr(0, tileProtocol.length - 1);
  236. }
  237. } else {
  238. // use http if the document's protocol is http, otherwise use https
  239. const documentProtocol = document.location.protocol;
  240. tileProtocol = documentProtocol === "http:" ? "http" : "https";
  241. }
  242. const resource = Resource.createIfNeeded(options.url);
  243. this._resource = resource;
  244. resource.appendForwardSlash();
  245. const metadataResource = resource.getDerivedResource({
  246. url: `REST/v1/Imagery/Metadata/${this._mapStyle}`,
  247. queryParameters: {
  248. incl: "ImageryProviders",
  249. key: options.key,
  250. uriScheme: tileProtocol,
  251. },
  252. });
  253. const imageryProviderBuilder = new ImageryProviderBuilder(options);
  254. this._readyPromise = requestMetadata(
  255. metadataResource,
  256. imageryProviderBuilder,
  257. this
  258. ).then(() => {
  259. imageryProviderBuilder.build(this);
  260. return true;
  261. });
  262. }
  263. }
  264. Object.defineProperties(BingMapsImageryProvider.prototype, {
  265. /**
  266. * Gets the name of the BingMaps server url hosting the imagery.
  267. * @memberof BingMapsImageryProvider.prototype
  268. * @type {string}
  269. * @readonly
  270. */
  271. url: {
  272. get: function () {
  273. return this._resource.url;
  274. },
  275. },
  276. /**
  277. * Gets the proxy used by this provider.
  278. * @memberof BingMapsImageryProvider.prototype
  279. * @type {Proxy}
  280. * @readonly
  281. */
  282. proxy: {
  283. get: function () {
  284. return this._resource.proxy;
  285. },
  286. },
  287. /**
  288. * Gets the Bing Maps key.
  289. * @memberof BingMapsImageryProvider.prototype
  290. * @type {string}
  291. * @readonly
  292. */
  293. key: {
  294. get: function () {
  295. return this._key;
  296. },
  297. },
  298. /**
  299. * Gets the type of Bing Maps imagery to load.
  300. * @memberof BingMapsImageryProvider.prototype
  301. * @type {BingMapsStyle}
  302. * @readonly
  303. */
  304. mapStyle: {
  305. get: function () {
  306. return this._mapStyle;
  307. },
  308. },
  309. /**
  310. * The culture to use when requesting Bing Maps imagery. Not
  311. * all cultures are supported. See {@link http://msdn.microsoft.com/en-us/library/hh441729.aspx}
  312. * for information on the supported cultures.
  313. * @memberof BingMapsImageryProvider.prototype
  314. * @type {string}
  315. * @readonly
  316. */
  317. culture: {
  318. get: function () {
  319. return this._culture;
  320. },
  321. },
  322. /**
  323. * Gets the width of each tile, in pixels.
  324. * @memberof BingMapsImageryProvider.prototype
  325. * @type {number}
  326. * @readonly
  327. */
  328. tileWidth: {
  329. get: function () {
  330. return this._tileWidth;
  331. },
  332. },
  333. /**
  334. * Gets the height of each tile, in pixels.
  335. * @memberof BingMapsImageryProvider.prototype
  336. * @type {number}
  337. * @readonly
  338. */
  339. tileHeight: {
  340. get: function () {
  341. return this._tileHeight;
  342. },
  343. },
  344. /**
  345. * Gets the maximum level-of-detail that can be requested.
  346. * @memberof BingMapsImageryProvider.prototype
  347. * @type {number|undefined}
  348. * @readonly
  349. */
  350. maximumLevel: {
  351. get: function () {
  352. return this._maximumLevel;
  353. },
  354. },
  355. /**
  356. * Gets the minimum level-of-detail that can be requested.
  357. * @memberof BingMapsImageryProvider.prototype
  358. * @type {number}
  359. * @readonly
  360. */
  361. minimumLevel: {
  362. get: function () {
  363. return 0;
  364. },
  365. },
  366. /**
  367. * Gets the tiling scheme used by this provider.
  368. * @memberof BingMapsImageryProvider.prototype
  369. * @type {TilingScheme}
  370. * @readonly
  371. */
  372. tilingScheme: {
  373. get: function () {
  374. return this._tilingScheme;
  375. },
  376. },
  377. /**
  378. * Gets the rectangle, in radians, of the imagery provided by this instance.
  379. * @memberof BingMapsImageryProvider.prototype
  380. * @type {Rectangle}
  381. * @readonly
  382. */
  383. rectangle: {
  384. get: function () {
  385. return this._tilingScheme.rectangle;
  386. },
  387. },
  388. /**
  389. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  390. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  391. * returns undefined, no tiles are filtered.
  392. * @memberof BingMapsImageryProvider.prototype
  393. * @type {TileDiscardPolicy}
  394. * @readonly
  395. */
  396. tileDiscardPolicy: {
  397. get: function () {
  398. return this._tileDiscardPolicy;
  399. },
  400. },
  401. /**
  402. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  403. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  404. * are passed an instance of {@link TileProviderError}.
  405. * @memberof BingMapsImageryProvider.prototype
  406. * @type {Event}
  407. * @readonly
  408. */
  409. errorEvent: {
  410. get: function () {
  411. return this._errorEvent;
  412. },
  413. },
  414. /**
  415. * Gets a value indicating whether or not the provider is ready for use.
  416. * @memberof BingMapsImageryProvider.prototype
  417. * @type {boolean}
  418. * @readonly
  419. * @deprecated
  420. */
  421. ready: {
  422. get: function () {
  423. deprecationWarning(
  424. "BingMapsImageryProvider.ready",
  425. "BingMapsImageryProvider.ready was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use BingMapsImageryProvider.fromUrl instead."
  426. );
  427. return this._ready;
  428. },
  429. },
  430. /**
  431. * Gets a promise that resolves to true when the provider is ready for use.
  432. * @memberof BingMapsImageryProvider.prototype
  433. * @type {Promise<boolean>}
  434. * @readonly
  435. * @deprecated
  436. */
  437. readyPromise: {
  438. get: function () {
  439. deprecationWarning(
  440. "BingMapsImageryProvider.readyPromise",
  441. "BingMapsImageryProvider.readyPromise was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use BingMapsImageryProvider.fromUrl instead."
  442. );
  443. return this._readyPromise;
  444. },
  445. },
  446. /**
  447. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  448. * the source of the imagery.
  449. * @memberof BingMapsImageryProvider.prototype
  450. * @type {Credit}
  451. * @readonly
  452. */
  453. credit: {
  454. get: function () {
  455. return this._credit;
  456. },
  457. },
  458. /**
  459. * Gets a value indicating whether or not the images provided by this imagery provider
  460. * include an alpha channel. If this property is false, an alpha channel, if present, will
  461. * be ignored. If this property is true, any images without an alpha channel will be treated
  462. * as if their alpha is 1.0 everywhere. Setting this property to false reduces memory usage
  463. * and texture upload time.
  464. * @memberof BingMapsImageryProvider.prototype
  465. * @type {boolean}
  466. * @readonly
  467. */
  468. hasAlphaChannel: {
  469. get: function () {
  470. return false;
  471. },
  472. },
  473. /**
  474. * The default alpha blending value of this provider, with 0.0 representing fully transparent and
  475. * 1.0 representing fully opaque.
  476. * @memberof BingMapsImageryProvider.prototype
  477. * @type {Number|undefined}
  478. * @deprecated
  479. */
  480. defaultAlpha: {
  481. get: function () {
  482. deprecationWarning(
  483. "BingMapsImageryProvider.defaultAlpha",
  484. "BingMapsImageryProvider.defaultAlpha was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.alpha instead."
  485. );
  486. return this._defaultAlpha;
  487. },
  488. set: function (value) {
  489. deprecationWarning(
  490. "BingMapsImageryProvider.defaultAlpha",
  491. "BingMapsImageryProvider.defaultAlpha was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.alpha instead."
  492. );
  493. this._defaultAlpha = value;
  494. },
  495. },
  496. /**
  497. * The default alpha blending value on the night side of the globe of this provider, with 0.0 representing fully transparent and
  498. * 1.0 representing fully opaque.
  499. * @memberof BingMapsImageryProvider.prototype
  500. * @type {Number|undefined}
  501. * @deprecated
  502. */
  503. defaultNightAlpha: {
  504. get: function () {
  505. deprecationWarning(
  506. "BingMapsImageryProvider.defaultNightAlpha",
  507. "BingMapsImageryProvider.defaultNightAlpha was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.nightAlpha instead."
  508. );
  509. return this.defaultNightAlpha;
  510. },
  511. set: function (value) {
  512. deprecationWarning(
  513. "BingMapsImageryProvider.defaultNightAlpha",
  514. "BingMapsImageryProvider.defaultNightAlpha was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.nightAlpha instead."
  515. );
  516. this.defaultNightAlpha = value;
  517. },
  518. },
  519. /**
  520. * The default alpha blending value on the day side of the globe of this provider, with 0.0 representing fully transparent and
  521. * 1.0 representing fully opaque.
  522. * @memberof BingMapsImageryProvider.prototype
  523. * @type {Number|undefined}
  524. * @deprecated
  525. */
  526. defaultDayAlpha: {
  527. get: function () {
  528. deprecationWarning(
  529. "BingMapsImageryProvider.defaultDayAlpha",
  530. "BingMapsImageryProvider.defaultDayAlpha was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.dayAlpha instead."
  531. );
  532. return this._defaultDayAlpha;
  533. },
  534. set: function (value) {
  535. deprecationWarning(
  536. "BingMapsImageryProvider.defaultDayAlpha",
  537. "BingMapsImageryProvider.defaultDayAlpha was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.dayAlpha instead."
  538. );
  539. this._defaultDayAlpha = value;
  540. },
  541. },
  542. /**
  543. * The default brightness of this provider. 1.0 uses the unmodified imagery color. Less than 1.0
  544. * makes the imagery darker while greater than 1.0 makes it brighter.
  545. * @memberof BingMapsImageryProvider.prototype
  546. * @type {Number|undefined}
  547. * @deprecated
  548. */
  549. defaultBrightness: {
  550. get: function () {
  551. deprecationWarning(
  552. "BingMapsImageryProvider.defaultBrightness",
  553. "BingMapsImageryProvider.defaultBrightness was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.brightness instead."
  554. );
  555. return this._defaultBrightness;
  556. },
  557. set: function (value) {
  558. deprecationWarning(
  559. "BingMapsImageryProvider.defaultBrightness",
  560. "BingMapsImageryProvider.defaultBrightness was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.brightness instead."
  561. );
  562. this._defaultBrightness = value;
  563. },
  564. },
  565. /**
  566. * The default contrast of this provider. 1.0 uses the unmodified imagery color. Less than 1.0 reduces
  567. * the contrast while greater than 1.0 increases it.
  568. * @memberof BingMapsImageryProvider.prototype
  569. * @type {Number|undefined}
  570. * @deprecated
  571. */
  572. defaultContrast: {
  573. get: function () {
  574. deprecationWarning(
  575. "BingMapsImageryProvider.defaultContrast",
  576. "BingMapsImageryProvider.defaultContrast was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.contrast instead."
  577. );
  578. return this._defaultContrast;
  579. },
  580. set: function (value) {
  581. deprecationWarning(
  582. "BingMapsImageryProvider.defaultContrast",
  583. "BingMapsImageryProvider.defaultContrast was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.contrast instead."
  584. );
  585. this._defaultContrast = value;
  586. },
  587. },
  588. /**
  589. * The default hue of this provider in radians. 0.0 uses the unmodified imagery color.
  590. * @memberof BingMapsImageryProvider.prototype
  591. * @type {Number|undefined}
  592. * @deprecated
  593. */
  594. defaultHue: {
  595. get: function () {
  596. deprecationWarning(
  597. "BingMapsImageryProvider.defaultHue",
  598. "BingMapsImageryProvider.defaultHue was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.hue instead."
  599. );
  600. return this._defaultHue;
  601. },
  602. set: function (value) {
  603. deprecationWarning(
  604. "BingMapsImageryProvider.defaultHue",
  605. "BingMapsImageryProvider.defaultHue was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.hue instead."
  606. );
  607. this._defaultHue = value;
  608. },
  609. },
  610. /**
  611. * The default saturation of this provider. 1.0 uses the unmodified imagery color. Less than 1.0 reduces the
  612. * saturation while greater than 1.0 increases it.
  613. * @memberof BingMapsImageryProvider.prototype
  614. * @type {Number|undefined}
  615. * @deprecated
  616. */
  617. defaultSaturation: {
  618. get: function () {
  619. deprecationWarning(
  620. "BingMapsImageryProvider.defaultSaturation",
  621. "BingMapsImageryProvider.defaultSaturation was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.saturation instead."
  622. );
  623. return this._defaultSaturation;
  624. },
  625. set: function (value) {
  626. deprecationWarning(
  627. "BingMapsImageryProvider.defaultSaturation",
  628. "BingMapsImageryProvider.defaultSaturation was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.saturation instead."
  629. );
  630. this._defaultSaturation = value;
  631. },
  632. },
  633. /**
  634. * The default gamma correction to apply to this provider. 1.0 uses the unmodified imagery color.
  635. * @memberof BingMapsImageryProvider.prototype
  636. * @type {Number|undefined}
  637. * @deprecated
  638. */
  639. defaultGamma: {
  640. get: function () {
  641. deprecationWarning(
  642. "BingMapsImageryProvider.defaultGamma",
  643. "BingMapsImageryProvider.defaultGamma was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.gamma instead."
  644. );
  645. return this._defaultGamma;
  646. },
  647. set: function (value) {
  648. deprecationWarning(
  649. "BingMapsImageryProvider.defaultGamma",
  650. "BingMapsImageryProvider.defaultGamma was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.gamma instead."
  651. );
  652. this._defaultGamma = value;
  653. },
  654. },
  655. /**
  656. * The default texture minification filter to apply to this provider.
  657. * @memberof BingMapsImageryProvider.prototype
  658. * @type {TextureMinificationFilter}
  659. * @deprecated
  660. */
  661. defaultMinificationFilter: {
  662. get: function () {
  663. deprecationWarning(
  664. "BingMapsImageryProvider.defaultMinificationFilter",
  665. "BingMapsImageryProvider.defaultMinificationFilter was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.minificationFilter instead."
  666. );
  667. return this._defaultMinificationFilter;
  668. },
  669. set: function (value) {
  670. deprecationWarning(
  671. "BingMapsImageryProvider.defaultMinificationFilter",
  672. "BingMapsImageryProvider.defaultMinificationFilter was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.minificationFilter instead."
  673. );
  674. this._defaultMinificationFilter = value;
  675. },
  676. },
  677. /**
  678. * The default texture magnification filter to apply to this provider.
  679. * @memberof BingMapsImageryProvider.prototype
  680. * @type {TextureMagnificationFilter}
  681. * @deprecated
  682. */
  683. defaultMagnificationFilter: {
  684. get: function () {
  685. deprecationWarning(
  686. "BingMapsImageryProvider.defaultMagnificationFilter",
  687. "BingMapsImageryProvider.defaultMagnificationFilter was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.magnificationFilter instead."
  688. );
  689. return this._defaultMagnificationFilter;
  690. },
  691. set: function (value) {
  692. deprecationWarning(
  693. "BingMapsImageryProvider.defaultMagnificationFilter",
  694. "BingMapsImageryProvider.defaultMagnificationFilter was deprecated in CesiumJS 1.104. It will be in CesiumJS 1.107. Use ImageryLayer.magnificationFilter instead."
  695. );
  696. this._defaultMagnificationFilter = value;
  697. },
  698. },
  699. });
  700. /**
  701. * Creates an {@link ImageryProvider} which provides tiled imagery using the Bing Maps Imagery REST API.
  702. *
  703. * @param {Resource|String} url The url of the Bing Maps server hosting the imagery.
  704. * @param {BingMapsImageryProvider.ConstructorOptions} options Object describing initialization options
  705. * @returns {Promise<BingMapsImageryProvider>} A promise that resolves to the created BingMapsImageryProvider
  706. *
  707. * @example
  708. * const bing = await Cesium.BingMapsImageryProvider.fromUrl(
  709. * "https://dev.virtualearth.net", {
  710. * key: "get-yours-at-https://www.bingmapsportal.com/",
  711. * mapStyle: Cesium.BingMapsStyle.AERIAL
  712. * });
  713. *
  714. * @exception {RuntimeError} metadata does not specify one resource in resourceSets
  715. */
  716. BingMapsImageryProvider.fromUrl = async function (url, options) {
  717. options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  718. //>>includeStart('debug', pragmas.debug);
  719. Check.defined("url", url);
  720. Check.defined("options.key", options.key);
  721. //>>includeEnd('debug');
  722. let tileProtocol = options.tileProtocol;
  723. // For backward compatibility reasons, the tileProtocol may end with
  724. // a `:`. Remove it.
  725. if (defined(tileProtocol)) {
  726. if (
  727. tileProtocol.length > 0 &&
  728. tileProtocol[tileProtocol.length - 1] === ":"
  729. ) {
  730. tileProtocol = tileProtocol.substr(0, tileProtocol.length - 1);
  731. }
  732. } else {
  733. // use http if the document's protocol is http, otherwise use https
  734. const documentProtocol = document.location.protocol;
  735. tileProtocol = documentProtocol === "http:" ? "http" : "https";
  736. }
  737. const mapStyle = defaultValue(options.mapStyle, BingMapsStyle.AERIAL);
  738. const resource = Resource.createIfNeeded(url);
  739. resource.appendForwardSlash();
  740. const metadataResource = resource.getDerivedResource({
  741. url: `REST/v1/Imagery/Metadata/${mapStyle}`,
  742. queryParameters: {
  743. incl: "ImageryProviders",
  744. key: options.key,
  745. uriScheme: tileProtocol,
  746. },
  747. });
  748. const provider = new BingMapsImageryProvider(options);
  749. provider._resource = resource;
  750. const imageryProviderBuilder = new ImageryProviderBuilder(options);
  751. await requestMetadata(metadataResource, imageryProviderBuilder);
  752. imageryProviderBuilder.build(provider);
  753. provider._readyPromise = Promise.resolve(true);
  754. return provider;
  755. };
  756. const rectangleScratch = new Rectangle();
  757. /**
  758. * Gets the credits to be displayed when a given tile is displayed.
  759. *
  760. * @param {number} x The tile X coordinate.
  761. * @param {number} y The tile Y coordinate.
  762. * @param {number} level The tile level;
  763. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  764. */
  765. BingMapsImageryProvider.prototype.getTileCredits = function (x, y, level) {
  766. const rectangle = this._tilingScheme.tileXYToRectangle(
  767. x,
  768. y,
  769. level,
  770. rectangleScratch
  771. );
  772. const result = getRectangleAttribution(
  773. this._attributionList,
  774. level,
  775. rectangle
  776. );
  777. return result;
  778. };
  779. /**
  780. * Requests the image for a given tile.
  781. *
  782. * @param {number} x The tile X coordinate.
  783. * @param {number} y The tile Y coordinate.
  784. * @param {number} level The tile level.
  785. * @param {Request} [request] The request object. Intended for internal use only.
  786. * @returns {Promise<ImageryTypes>|undefined} A promise for the image that will resolve when the image is available, or
  787. * undefined if there are too many active requests to the server, and the request should be retried later.
  788. */
  789. BingMapsImageryProvider.prototype.requestImage = function (
  790. x,
  791. y,
  792. level,
  793. request
  794. ) {
  795. const promise = ImageryProvider.loadImage(
  796. this,
  797. buildImageResource(this, x, y, level, request)
  798. );
  799. if (defined(promise)) {
  800. return promise.catch(function (error) {
  801. // One cause of an error here is that the image we tried to load was zero-length.
  802. // This isn't actually a problem, since it indicates that there is no tile.
  803. // So, in that case we return the EMPTY_IMAGE sentinel value for later discarding.
  804. if (defined(error.blob) && error.blob.size === 0) {
  805. return DiscardEmptyTilePolicy.EMPTY_IMAGE;
  806. }
  807. return Promise.reject(error);
  808. });
  809. }
  810. return undefined;
  811. };
  812. /**
  813. * Picking features is not currently supported by this imagery provider, so this function simply returns
  814. * undefined.
  815. *
  816. * @param {number} x The tile X coordinate.
  817. * @param {number} y The tile Y coordinate.
  818. * @param {number} level The tile level.
  819. * @param {number} longitude The longitude at which to pick features.
  820. * @param {number} latitude The latitude at which to pick features.
  821. * @return {undefined} Undefined since picking is not supported.
  822. */
  823. BingMapsImageryProvider.prototype.pickFeatures = function (
  824. x,
  825. y,
  826. level,
  827. longitude,
  828. latitude
  829. ) {
  830. return undefined;
  831. };
  832. /**
  833. * Converts a tiles (x, y, level) position into a quadkey used to request an image
  834. * from a Bing Maps server.
  835. *
  836. * @param {number} x The tile's x coordinate.
  837. * @param {number} y The tile's y coordinate.
  838. * @param {number} level The tile's zoom level.
  839. *
  840. * @see {@link http://msdn.microsoft.com/en-us/library/bb259689.aspx|Bing Maps Tile System}
  841. * @see BingMapsImageryProvider#quadKeyToTileXY
  842. */
  843. BingMapsImageryProvider.tileXYToQuadKey = function (x, y, level) {
  844. let quadkey = "";
  845. for (let i = level; i >= 0; --i) {
  846. const bitmask = 1 << i;
  847. let digit = 0;
  848. if ((x & bitmask) !== 0) {
  849. digit |= 1;
  850. }
  851. if ((y & bitmask) !== 0) {
  852. digit |= 2;
  853. }
  854. quadkey += digit;
  855. }
  856. return quadkey;
  857. };
  858. /**
  859. * Converts a tile's quadkey used to request an image from a Bing Maps server into the
  860. * (x, y, level) position.
  861. *
  862. * @param {string} quadkey The tile's quad key
  863. *
  864. * @see {@link http://msdn.microsoft.com/en-us/library/bb259689.aspx|Bing Maps Tile System}
  865. * @see BingMapsImageryProvider#tileXYToQuadKey
  866. */
  867. BingMapsImageryProvider.quadKeyToTileXY = function (quadkey) {
  868. let x = 0;
  869. let y = 0;
  870. const level = quadkey.length - 1;
  871. for (let i = level; i >= 0; --i) {
  872. const bitmask = 1 << i;
  873. const digit = +quadkey[level - i];
  874. if ((digit & 1) !== 0) {
  875. x |= bitmask;
  876. }
  877. if ((digit & 2) !== 0) {
  878. y |= bitmask;
  879. }
  880. }
  881. return {
  882. x: x,
  883. y: y,
  884. level: level,
  885. };
  886. };
  887. BingMapsImageryProvider._logoUrl = undefined;
  888. Object.defineProperties(BingMapsImageryProvider, {
  889. /**
  890. * Gets or sets the URL to the Bing logo for display in the credit.
  891. * @memberof BingMapsImageryProvider
  892. * @type {string}
  893. */
  894. logoUrl: {
  895. get: function () {
  896. if (!defined(BingMapsImageryProvider._logoUrl)) {
  897. BingMapsImageryProvider._logoUrl = buildModuleUrl(
  898. "Assets/Images/bing_maps_credit.png"
  899. );
  900. }
  901. return BingMapsImageryProvider._logoUrl;
  902. },
  903. set: function (value) {
  904. //>>includeStart('debug', pragmas.debug);
  905. Check.defined("value", value);
  906. //>>includeEnd('debug');
  907. BingMapsImageryProvider._logoUrl = value;
  908. },
  909. },
  910. });
  911. function buildImageResource(imageryProvider, x, y, level, request) {
  912. const imageUrl = imageryProvider._imageUrlTemplate;
  913. const subdomains = imageryProvider._imageUrlSubdomains;
  914. const subdomainIndex = (x + y + level) % subdomains.length;
  915. return imageryProvider._resource.getDerivedResource({
  916. url: imageUrl,
  917. request: request,
  918. templateValues: {
  919. quadkey: BingMapsImageryProvider.tileXYToQuadKey(x, y, level),
  920. subdomain: subdomains[subdomainIndex],
  921. culture: imageryProvider._culture,
  922. },
  923. queryParameters: {
  924. // this parameter tells the Bing servers to send a zero-length response
  925. // instead of a placeholder image for missing tiles.
  926. n: "z",
  927. },
  928. });
  929. }
  930. const intersectionScratch = new Rectangle();
  931. function getRectangleAttribution(attributionList, level, rectangle) {
  932. // Bing levels start at 1, while ours start at 0.
  933. ++level;
  934. const result = [];
  935. for (
  936. let attributionIndex = 0, attributionLength = attributionList.length;
  937. attributionIndex < attributionLength;
  938. ++attributionIndex
  939. ) {
  940. const attribution = attributionList[attributionIndex];
  941. const coverageAreas = attribution.coverageAreas;
  942. let included = false;
  943. for (
  944. let areaIndex = 0, areaLength = attribution.coverageAreas.length;
  945. !included && areaIndex < areaLength;
  946. ++areaIndex
  947. ) {
  948. const area = coverageAreas[areaIndex];
  949. if (level >= area.zoomMin && level <= area.zoomMax) {
  950. const intersection = Rectangle.intersection(
  951. rectangle,
  952. area.bbox,
  953. intersectionScratch
  954. );
  955. if (defined(intersection)) {
  956. included = true;
  957. }
  958. }
  959. }
  960. if (included) {
  961. result.push(attribution.credit);
  962. }
  963. }
  964. return result;
  965. }
  966. // Exposed for testing
  967. BingMapsImageryProvider._metadataCache = {};
  968. export default BingMapsImageryProvider;