UrlTemplateImageryProvider.js 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240
  1. import Cartesian2 from "../Core/Cartesian2.js";
  2. import Cartesian3 from "../Core/Cartesian3.js";
  3. import Cartographic from "../Core/Cartographic.js";
  4. import combine from "../Core/combine.js";
  5. import Credit from "../Core/Credit.js";
  6. import defaultValue from "../Core/defaultValue.js";
  7. import defined from "../Core/defined.js";
  8. import DeveloperError from "../Core/DeveloperError.js";
  9. import Event from "../Core/Event.js";
  10. import GeographicProjection from "../Core/GeographicProjection.js";
  11. import CesiumMath from "../Core/Math.js";
  12. import Rectangle from "../Core/Rectangle.js";
  13. import Resource from "../Core/Resource.js";
  14. import WebMercatorTilingScheme from "../Core/WebMercatorTilingScheme.js";
  15. import ImageryProvider from "./ImageryProvider.js";
  16. const templateRegex = /{[^}]+}/g;
  17. const tags = {
  18. x: xTag,
  19. y: yTag,
  20. z: zTag,
  21. s: sTag,
  22. reverseX: reverseXTag,
  23. reverseY: reverseYTag,
  24. reverseZ: reverseZTag,
  25. westDegrees: westDegreesTag,
  26. southDegrees: southDegreesTag,
  27. eastDegrees: eastDegreesTag,
  28. northDegrees: northDegreesTag,
  29. westProjected: westProjectedTag,
  30. southProjected: southProjectedTag,
  31. eastProjected: eastProjectedTag,
  32. northProjected: northProjectedTag,
  33. width: widthTag,
  34. height: heightTag,
  35. };
  36. const pickFeaturesTags = combine(tags, {
  37. i: iTag,
  38. j: jTag,
  39. reverseI: reverseITag,
  40. reverseJ: reverseJTag,
  41. longitudeDegrees: longitudeDegreesTag,
  42. latitudeDegrees: latitudeDegreesTag,
  43. longitudeProjected: longitudeProjectedTag,
  44. latitudeProjected: latitudeProjectedTag,
  45. format: formatTag,
  46. });
  47. /**
  48. * @typedef {Object} UrlTemplateImageryProvider.ConstructorOptions
  49. *
  50. * Initialization options for the UrlTemplateImageryProvider constructor
  51. *
  52. * @property {Promise.<Object>|Object} [options] Object with the following properties:
  53. * @property {Resource|String} url The URL template to use to request tiles. It has the following keywords:
  54. * <ul>
  55. * <li><code>{z}</code>: The level of the tile in the tiling scheme. Level zero is the root of the quadtree pyramid.</li>
  56. * <li><code>{x}</code>: The tile X coordinate in the tiling scheme, where 0 is the Westernmost tile.</li>
  57. * <li><code>{y}</code>: The tile Y coordinate in the tiling scheme, where 0 is the Northernmost tile.</li>
  58. * <li><code>{s}</code>: One of the available subdomains, used to overcome browser limits on the number of simultaneous requests per host.</li>
  59. * <li><code>{reverseX}</code>: The tile X coordinate in the tiling scheme, where 0 is the Easternmost tile.</li>
  60. * <li><code>{reverseY}</code>: The tile Y coordinate in the tiling scheme, where 0 is the Southernmost tile.</li>
  61. * <li><code>{reverseZ}</code>: The level of the tile in the tiling scheme, where level zero is the maximum level of the quadtree pyramid. In order to use reverseZ, maximumLevel must be defined.</li>
  62. * <li><code>{westDegrees}</code>: The Western edge of the tile in geodetic degrees.</li>
  63. * <li><code>{southDegrees}</code>: The Southern edge of the tile in geodetic degrees.</li>
  64. * <li><code>{eastDegrees}</code>: The Eastern edge of the tile in geodetic degrees.</li>
  65. * <li><code>{northDegrees}</code>: The Northern edge of the tile in geodetic degrees.</li>
  66. * <li><code>{westProjected}</code>: The Western edge of the tile in projected coordinates of the tiling scheme.</li>
  67. * <li><code>{southProjected}</code>: The Southern edge of the tile in projected coordinates of the tiling scheme.</li>
  68. * <li><code>{eastProjected}</code>: The Eastern edge of the tile in projected coordinates of the tiling scheme.</li>
  69. * <li><code>{northProjected}</code>: The Northern edge of the tile in projected coordinates of the tiling scheme.</li>
  70. * <li><code>{width}</code>: The width of each tile in pixels.</li>
  71. * <li><code>{height}</code>: The height of each tile in pixels.</li>
  72. * </ul>
  73. * @property {Resource|String} [pickFeaturesUrl] The URL template to use to pick features. If this property is not specified,
  74. * {@link UrlTemplateImageryProvider#pickFeatures} will immediately returned undefined, indicating no
  75. * features picked. The URL template supports all of the keywords supported by the <code>url</code>
  76. * parameter, plus the following:
  77. * <ul>
  78. * <li><code>{i}</code>: The pixel column (horizontal coordinate) of the picked position, where the Westernmost pixel is 0.</li>
  79. * <li><code>{j}</code>: The pixel row (vertical coordinate) of the picked position, where the Northernmost pixel is 0.</li>
  80. * <li><code>{reverseI}</code>: The pixel column (horizontal coordinate) of the picked position, where the Easternmost pixel is 0.</li>
  81. * <li><code>{reverseJ}</code>: The pixel row (vertical coordinate) of the picked position, where the Southernmost pixel is 0.</li>
  82. * <li><code>{longitudeDegrees}</code>: The longitude of the picked position in degrees.</li>
  83. * <li><code>{latitudeDegrees}</code>: The latitude of the picked position in degrees.</li>
  84. * <li><code>{longitudeProjected}</code>: The longitude of the picked position in the projected coordinates of the tiling scheme.</li>
  85. * <li><code>{latitudeProjected}</code>: The latitude of the picked position in the projected coordinates of the tiling scheme.</li>
  86. * <li><code>{format}</code>: The format in which to get feature information, as specified in the {@link GetFeatureInfoFormat}.</li>
  87. * </ul>
  88. * @property {Object} [urlSchemeZeroPadding] Gets the URL scheme zero padding for each tile coordinate. The format is '000' where
  89. * each coordinate will be padded on the left with zeros to match the width of the passed string of zeros. e.g. Setting:
  90. * urlSchemeZeroPadding : { '{x}' : '0000'}
  91. * will cause an 'x' value of 12 to return the string '0012' for {x} in the generated URL.
  92. * It the passed object has the following keywords:
  93. * <ul>
  94. * <li> <code>{z}</code>: The zero padding for the level of the tile in the tiling scheme.</li>
  95. * <li> <code>{x}</code>: The zero padding for the tile X coordinate in the tiling scheme.</li>
  96. * <li> <code>{y}</code>: The zero padding for the the tile Y coordinate in the tiling scheme.</li>
  97. * <li> <code>{reverseX}</code>: The zero padding for the tile reverseX coordinate in the tiling scheme.</li>
  98. * <li> <code>{reverseY}</code>: The zero padding for the tile reverseY coordinate in the tiling scheme.</li>
  99. * <li> <code>{reverseZ}</code>: The zero padding for the reverseZ coordinate of the tile in the tiling scheme.</li>
  100. * </ul>
  101. * @property {String|String[]} [subdomains='abc'] The subdomains to use for the <code>{s}</code> placeholder in the URL template.
  102. * If this parameter is a single string, each character in the string is a subdomain. If it is
  103. * an array, each element in the array is a subdomain.
  104. * @property {Credit|String} [credit=''] A credit for the data source, which is displayed on the canvas.
  105. * @property {Number} [minimumLevel=0] The minimum level-of-detail supported by the imagery provider. Take care when specifying
  106. * this that the number of tiles at the minimum level is small, such as four or less. A larger number is likely
  107. * to result in rendering problems.
  108. * @property {Number} [maximumLevel] The maximum level-of-detail supported by the imagery provider, or undefined if there is no limit.
  109. * @property {Rectangle} [rectangle=Rectangle.MAX_VALUE] The rectangle, in radians, covered by the image.
  110. * @property {TilingScheme} [tilingScheme=WebMercatorTilingScheme] The tiling scheme specifying how the ellipsoidal
  111. * surface is broken into tiles. If this parameter is not provided, a {@link WebMercatorTilingScheme}
  112. * is used.
  113. * @property {Ellipsoid} [ellipsoid] The ellipsoid. If the tilingScheme is specified,
  114. * this parameter is ignored and the tiling scheme's ellipsoid is used instead. If neither
  115. * parameter is specified, the WGS84 ellipsoid is used.
  116. * @property {Number} [tileWidth=256] Pixel width of image tiles.
  117. * @property {Number} [tileHeight=256] Pixel height of image tiles.
  118. * @property {Boolean} [hasAlphaChannel=true] true if the images provided by this imagery provider
  119. * include an alpha channel; otherwise, false. If this property is false, an alpha channel, if
  120. * present, will be ignored. If this property is true, any images without an alpha channel will
  121. * be treated as if their alpha is 1.0 everywhere. When this property is false, memory usage
  122. * and texture upload time are potentially reduced.
  123. * @property {GetFeatureInfoFormat[]} [getFeatureInfoFormats] The formats in which to get feature information at a
  124. * specific location when {@link UrlTemplateImageryProvider#pickFeatures} is invoked. If this
  125. * parameter is not specified, feature picking is disabled.
  126. * @property {Boolean} [enablePickFeatures=true] If true, {@link UrlTemplateImageryProvider#pickFeatures} will
  127. * request the <code>pickFeaturesUrl</code> and attempt to interpret the features included in the response. If false,
  128. * {@link UrlTemplateImageryProvider#pickFeatures} will immediately return undefined (indicating no pickable
  129. * features) without communicating with the server. Set this property to false if you know your data
  130. * source does not support picking features or if you don't want this provider's features to be pickable. Note
  131. * that this can be dynamically overridden by modifying the {@link UriTemplateImageryProvider#enablePickFeatures}
  132. * property.
  133. * @property {Object} [customTags] Allow to replace custom keywords in the URL template. The object must have strings as keys and functions as values.
  134. */
  135. /**
  136. * Provides imagery by requesting tiles using a specified URL template.
  137. *
  138. * @alias UrlTemplateImageryProvider
  139. * @constructor
  140. *
  141. * @param {UrlTemplateImageryProvider.ConstructorOptions} options Object describing initialization options
  142. *
  143. * @example
  144. * // Access Natural Earth II imagery, which uses a TMS tiling scheme and Geographic (EPSG:4326) project
  145. * const tms = new Cesium.UrlTemplateImageryProvider({
  146. * url : Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII') + '/{z}/{x}/{reverseY}.jpg',
  147. * credit : '© Analytical Graphics, Inc.',
  148. * tilingScheme : new Cesium.GeographicTilingScheme(),
  149. * maximumLevel : 5
  150. * });
  151. * // Access the CartoDB Positron basemap, which uses an OpenStreetMap-like tiling scheme.
  152. * const positron = new Cesium.UrlTemplateImageryProvider({
  153. * url : 'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
  154. * credit : 'Map tiles by CartoDB, under CC BY 3.0. Data by OpenStreetMap, under ODbL.'
  155. * });
  156. * // Access a Web Map Service (WMS) server.
  157. * const wms = new Cesium.UrlTemplateImageryProvider({
  158. * url : 'https://programs.communications.gov.au/geoserver/ows?tiled=true&' +
  159. * 'transparent=true&format=image%2Fpng&exceptions=application%2Fvnd.ogc.se_xml&' +
  160. * 'styles=&service=WMS&version=1.1.1&request=GetMap&' +
  161. * 'layers=public%3AMyBroadband_Availability&srs=EPSG%3A3857&' +
  162. * 'bbox={westProjected}%2C{southProjected}%2C{eastProjected}%2C{northProjected}&' +
  163. * 'width=256&height=256',
  164. * rectangle : Cesium.Rectangle.fromDegrees(96.799393, -43.598214999057824, 153.63925700000001, -9.2159219997013)
  165. * });
  166. * // Using custom tags in your template url.
  167. * const custom = new Cesium.UrlTemplateImageryProvider({
  168. * url : 'https://yoururl/{Time}/{z}/{y}/{x}.png',
  169. * customTags : {
  170. * Time: function(imageryProvider, x, y, level) {
  171. * return '20171231'
  172. * }
  173. * }
  174. * });
  175. *
  176. * @see ArcGisMapServerImageryProvider
  177. * @see BingMapsImageryProvider
  178. * @see GoogleEarthEnterpriseMapsProvider
  179. * @see OpenStreetMapImageryProvider
  180. * @see SingleTileImageryProvider
  181. * @see TileMapServiceImageryProvider
  182. * @see WebMapServiceImageryProvider
  183. * @see WebMapTileServiceImageryProvider
  184. */
  185. function UrlTemplateImageryProvider(options) {
  186. //>>includeStart('debug', pragmas.debug);
  187. if (!defined(options)) {
  188. throw new DeveloperError("options is required.");
  189. }
  190. if (!defined(options.then) && !defined(options.url)) {
  191. throw new DeveloperError("options is required.");
  192. }
  193. //>>includeEnd('debug');
  194. this._errorEvent = new Event();
  195. this._resource = undefined;
  196. this._urlSchemeZeroPadding = undefined;
  197. this._pickFeaturesResource = undefined;
  198. this._tileWidth = undefined;
  199. this._tileHeight = undefined;
  200. this._maximumLevel = undefined;
  201. this._minimumLevel = undefined;
  202. this._tilingScheme = undefined;
  203. this._rectangle = undefined;
  204. this._tileDiscardPolicy = undefined;
  205. this._credit = undefined;
  206. this._hasAlphaChannel = undefined;
  207. this._readyPromise = undefined;
  208. this._tags = undefined;
  209. this._pickFeaturesTags = undefined;
  210. /**
  211. * The default alpha blending value of this provider, with 0.0 representing fully transparent and
  212. * 1.0 representing fully opaque.
  213. *
  214. * @type {Number|undefined}
  215. * @default undefined
  216. */
  217. this.defaultAlpha = undefined;
  218. /**
  219. * The default alpha blending value on the night side of the globe of this provider, with 0.0 representing fully transparent and
  220. * 1.0 representing fully opaque.
  221. *
  222. * @type {Number|undefined}
  223. * @default undefined
  224. */
  225. this.defaultNightAlpha = undefined;
  226. /**
  227. * The default alpha blending value on the day side of the globe of this provider, with 0.0 representing fully transparent and
  228. * 1.0 representing fully opaque.
  229. *
  230. * @type {Number|undefined}
  231. * @default undefined
  232. */
  233. this.defaultDayAlpha = undefined;
  234. /**
  235. * The default brightness of this provider. 1.0 uses the unmodified imagery color. Less than 1.0
  236. * makes the imagery darker while greater than 1.0 makes it brighter.
  237. *
  238. * @type {Number|undefined}
  239. * @default undefined
  240. */
  241. this.defaultBrightness = undefined;
  242. /**
  243. * The default contrast of this provider. 1.0 uses the unmodified imagery color. Less than 1.0 reduces
  244. * the contrast while greater than 1.0 increases it.
  245. *
  246. * @type {Number|undefined}
  247. * @default undefined
  248. */
  249. this.defaultContrast = undefined;
  250. /**
  251. * The default hue of this provider in radians. 0.0 uses the unmodified imagery color.
  252. *
  253. * @type {Number|undefined}
  254. * @default undefined
  255. */
  256. this.defaultHue = undefined;
  257. /**
  258. * The default saturation of this provider. 1.0 uses the unmodified imagery color. Less than 1.0 reduces the
  259. * saturation while greater than 1.0 increases it.
  260. *
  261. * @type {Number|undefined}
  262. * @default undefined
  263. */
  264. this.defaultSaturation = undefined;
  265. /**
  266. * The default gamma correction to apply to this provider. 1.0 uses the unmodified imagery color.
  267. *
  268. * @type {Number|undefined}
  269. * @default undefined
  270. */
  271. this.defaultGamma = undefined;
  272. /**
  273. * The default texture minification filter to apply to this provider.
  274. *
  275. * @type {TextureMinificationFilter}
  276. * @default undefined
  277. */
  278. this.defaultMinificationFilter = undefined;
  279. /**
  280. * The default texture magnification filter to apply to this provider.
  281. *
  282. * @type {TextureMagnificationFilter}
  283. * @default undefined
  284. */
  285. this.defaultMagnificationFilter = undefined;
  286. /**
  287. * Gets or sets a value indicating whether feature picking is enabled. If true, {@link UrlTemplateImageryProvider#pickFeatures} will
  288. * request the <code>options.pickFeaturesUrl</code> and attempt to interpret the features included in the response. If false,
  289. * {@link UrlTemplateImageryProvider#pickFeatures} will immediately return undefined (indicating no pickable
  290. * features) without communicating with the server. Set this property to false if you know your data
  291. * source does not support picking features or if you don't want this provider's features to be pickable.
  292. * @type {Boolean}
  293. * @default true
  294. */
  295. this.enablePickFeatures = true;
  296. this.reinitialize(options);
  297. }
  298. Object.defineProperties(UrlTemplateImageryProvider.prototype, {
  299. /**
  300. * Gets the URL template to use to request tiles. It has the following keywords:
  301. * <ul>
  302. * <li> <code>{z}</code>: The level of the tile in the tiling scheme. Level zero is the root of the quadtree pyramid.</li>
  303. * <li> <code>{x}</code>: The tile X coordinate in the tiling scheme, where 0 is the Westernmost tile.</li>
  304. * <li> <code>{y}</code>: The tile Y coordinate in the tiling scheme, where 0 is the Northernmost tile.</li>
  305. * <li> <code>{s}</code>: One of the available subdomains, used to overcome browser limits on the number of simultaneous requests per host.</li>
  306. * <li> <code>{reverseX}</code>: The tile X coordinate in the tiling scheme, where 0 is the Easternmost tile.</li>
  307. * <li> <code>{reverseY}</code>: The tile Y coordinate in the tiling scheme, where 0 is the Southernmost tile.</li>
  308. * <li> <code>{reverseZ}</code>: The level of the tile in the tiling scheme, where level zero is the maximum level of the quadtree pyramid. In order to use reverseZ, maximumLevel must be defined.</li>
  309. * <li> <code>{westDegrees}</code>: The Western edge of the tile in geodetic degrees.</li>
  310. * <li> <code>{southDegrees}</code>: The Southern edge of the tile in geodetic degrees.</li>
  311. * <li> <code>{eastDegrees}</code>: The Eastern edge of the tile in geodetic degrees.</li>
  312. * <li> <code>{northDegrees}</code>: The Northern edge of the tile in geodetic degrees.</li>
  313. * <li> <code>{westProjected}</code>: The Western edge of the tile in projected coordinates of the tiling scheme.</li>
  314. * <li> <code>{southProjected}</code>: The Southern edge of the tile in projected coordinates of the tiling scheme.</li>
  315. * <li> <code>{eastProjected}</code>: The Eastern edge of the tile in projected coordinates of the tiling scheme.</li>
  316. * <li> <code>{northProjected}</code>: The Northern edge of the tile in projected coordinates of the tiling scheme.</li>
  317. * <li> <code>{width}</code>: The width of each tile in pixels.</li>
  318. * <li> <code>{height}</code>: The height of each tile in pixels.</li>
  319. * </ul>
  320. * @memberof UrlTemplateImageryProvider.prototype
  321. * @type {String}
  322. * @readonly
  323. */
  324. url: {
  325. get: function () {
  326. return this._resource.url;
  327. },
  328. },
  329. /**
  330. * Gets the URL scheme zero padding for each tile coordinate. The format is '000' where each coordinate will be padded on
  331. * the left with zeros to match the width of the passed string of zeros. e.g. Setting:
  332. * urlSchemeZeroPadding : { '{x}' : '0000'}
  333. * will cause an 'x' value of 12 to return the string '0012' for {x} in the generated URL.
  334. * It has the following keywords:
  335. * <ul>
  336. * <li> <code>{z}</code>: The zero padding for the level of the tile in the tiling scheme.</li>
  337. * <li> <code>{x}</code>: The zero padding for the tile X coordinate in the tiling scheme.</li>
  338. * <li> <code>{y}</code>: The zero padding for the the tile Y coordinate in the tiling scheme.</li>
  339. * <li> <code>{reverseX}</code>: The zero padding for the tile reverseX coordinate in the tiling scheme.</li>
  340. * <li> <code>{reverseY}</code>: The zero padding for the tile reverseY coordinate in the tiling scheme.</li>
  341. * <li> <code>{reverseZ}</code>: The zero padding for the reverseZ coordinate of the tile in the tiling scheme.</li>
  342. * </ul>
  343. * @memberof UrlTemplateImageryProvider.prototype
  344. * @type {Object}
  345. * @readonly
  346. */
  347. urlSchemeZeroPadding: {
  348. get: function () {
  349. return this._urlSchemeZeroPadding;
  350. },
  351. },
  352. /**
  353. * Gets the URL template to use to use to pick features. If this property is not specified,
  354. * {@link UrlTemplateImageryProvider#pickFeatures} will immediately return undefined, indicating no
  355. * features picked. The URL template supports all of the keywords supported by the
  356. * {@link UrlTemplateImageryProvider#url} property, plus the following:
  357. * <ul>
  358. * <li><code>{i}</code>: The pixel column (horizontal coordinate) of the picked position, where the Westernmost pixel is 0.</li>
  359. * <li><code>{j}</code>: The pixel row (vertical coordinate) of the picked position, where the Northernmost pixel is 0.</li>
  360. * <li><code>{reverseI}</code>: The pixel column (horizontal coordinate) of the picked position, where the Easternmost pixel is 0.</li>
  361. * <li><code>{reverseJ}</code>: The pixel row (vertical coordinate) of the picked position, where the Southernmost pixel is 0.</li>
  362. * <li><code>{longitudeDegrees}</code>: The longitude of the picked position in degrees.</li>
  363. * <li><code>{latitudeDegrees}</code>: The latitude of the picked position in degrees.</li>
  364. * <li><code>{longitudeProjected}</code>: The longitude of the picked position in the projected coordinates of the tiling scheme.</li>
  365. * <li><code>{latitudeProjected}</code>: The latitude of the picked position in the projected coordinates of the tiling scheme.</li>
  366. * <li><code>{format}</code>: The format in which to get feature information, as specified in the {@link GetFeatureInfoFormat}.</li>
  367. * </ul>
  368. * @memberof UrlTemplateImageryProvider.prototype
  369. * @type {String}
  370. * @readonly
  371. */
  372. pickFeaturesUrl: {
  373. get: function () {
  374. return this._pickFeaturesResource.url;
  375. },
  376. },
  377. /**
  378. * Gets the proxy used by this provider.
  379. * @memberof UrlTemplateImageryProvider.prototype
  380. * @type {Proxy}
  381. * @readonly
  382. * @default undefined
  383. */
  384. proxy: {
  385. get: function () {
  386. return this._resource.proxy;
  387. },
  388. },
  389. /**
  390. * Gets the width of each tile, in pixels. This function should
  391. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  392. * @memberof UrlTemplateImageryProvider.prototype
  393. * @type {Number}
  394. * @readonly
  395. * @default 256
  396. */
  397. tileWidth: {
  398. get: function () {
  399. //>>includeStart('debug', pragmas.debug);
  400. if (!this.ready) {
  401. throw new DeveloperError(
  402. "tileWidth must not be called before the imagery provider is ready."
  403. );
  404. }
  405. //>>includeEnd('debug');
  406. return this._tileWidth;
  407. },
  408. },
  409. /**
  410. * Gets the height of each tile, in pixels. This function should
  411. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  412. * @memberof UrlTemplateImageryProvider.prototype
  413. * @type {Number}
  414. * @readonly
  415. * @default 256
  416. */
  417. tileHeight: {
  418. get: function () {
  419. //>>includeStart('debug', pragmas.debug);
  420. if (!this.ready) {
  421. throw new DeveloperError(
  422. "tileHeight must not be called before the imagery provider is ready."
  423. );
  424. }
  425. //>>includeEnd('debug');
  426. return this._tileHeight;
  427. },
  428. },
  429. /**
  430. * Gets the maximum level-of-detail that can be requested, or undefined if there is no limit.
  431. * This function should not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  432. * @memberof UrlTemplateImageryProvider.prototype
  433. * @type {Number|undefined}
  434. * @readonly
  435. * @default undefined
  436. */
  437. maximumLevel: {
  438. get: function () {
  439. //>>includeStart('debug', pragmas.debug);
  440. if (!this.ready) {
  441. throw new DeveloperError(
  442. "maximumLevel must not be called before the imagery provider is ready."
  443. );
  444. }
  445. //>>includeEnd('debug');
  446. return this._maximumLevel;
  447. },
  448. },
  449. /**
  450. * Gets the minimum level-of-detail that can be requested. This function should
  451. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  452. * @memberof UrlTemplateImageryProvider.prototype
  453. * @type {Number}
  454. * @readonly
  455. * @default 0
  456. */
  457. minimumLevel: {
  458. get: function () {
  459. //>>includeStart('debug', pragmas.debug);
  460. if (!this.ready) {
  461. throw new DeveloperError(
  462. "minimumLevel must not be called before the imagery provider is ready."
  463. );
  464. }
  465. //>>includeEnd('debug');
  466. return this._minimumLevel;
  467. },
  468. },
  469. /**
  470. * Gets the tiling scheme used by this provider. This function should
  471. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  472. * @memberof UrlTemplateImageryProvider.prototype
  473. * @type {TilingScheme}
  474. * @readonly
  475. * @default new WebMercatorTilingScheme()
  476. */
  477. tilingScheme: {
  478. get: function () {
  479. //>>includeStart('debug', pragmas.debug);
  480. if (!this.ready) {
  481. throw new DeveloperError(
  482. "tilingScheme must not be called before the imagery provider is ready."
  483. );
  484. }
  485. //>>includeEnd('debug');
  486. return this._tilingScheme;
  487. },
  488. },
  489. /**
  490. * Gets the rectangle, in radians, of the imagery provided by this instance. This function should
  491. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  492. * @memberof UrlTemplateImageryProvider.prototype
  493. * @type {Rectangle}
  494. * @readonly
  495. * @default tilingScheme.rectangle
  496. */
  497. rectangle: {
  498. get: function () {
  499. //>>includeStart('debug', pragmas.debug);
  500. if (!this.ready) {
  501. throw new DeveloperError(
  502. "rectangle must not be called before the imagery provider is ready."
  503. );
  504. }
  505. //>>includeEnd('debug');
  506. return this._rectangle;
  507. },
  508. },
  509. /**
  510. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  511. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  512. * returns undefined, no tiles are filtered. This function should
  513. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  514. * @memberof UrlTemplateImageryProvider.prototype
  515. * @type {TileDiscardPolicy}
  516. * @readonly
  517. * @default undefined
  518. */
  519. tileDiscardPolicy: {
  520. get: function () {
  521. //>>includeStart('debug', pragmas.debug);
  522. if (!this.ready) {
  523. throw new DeveloperError(
  524. "tileDiscardPolicy must not be called before the imagery provider is ready."
  525. );
  526. }
  527. //>>includeEnd('debug');
  528. return this._tileDiscardPolicy;
  529. },
  530. },
  531. /**
  532. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  533. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  534. * are passed an instance of {@link TileProviderError}.
  535. * @memberof UrlTemplateImageryProvider.prototype
  536. * @type {Event}
  537. * @readonly
  538. */
  539. errorEvent: {
  540. get: function () {
  541. return this._errorEvent;
  542. },
  543. },
  544. /**
  545. * Gets a value indicating whether or not the provider is ready for use.
  546. * @memberof UrlTemplateImageryProvider.prototype
  547. * @type {Boolean}
  548. * @readonly
  549. */
  550. ready: {
  551. get: function () {
  552. return defined(this._resource);
  553. },
  554. },
  555. /**
  556. * Gets a promise that resolves to true when the provider is ready for use.
  557. * @memberof UrlTemplateImageryProvider.prototype
  558. * @type {Promise.<Boolean>}
  559. * @readonly
  560. */
  561. readyPromise: {
  562. get: function () {
  563. return this._readyPromise;
  564. },
  565. },
  566. /**
  567. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  568. * the source of the imagery. This function should not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  569. * @memberof UrlTemplateImageryProvider.prototype
  570. * @type {Credit}
  571. * @readonly
  572. * @default undefined
  573. */
  574. credit: {
  575. get: function () {
  576. //>>includeStart('debug', pragmas.debug);
  577. if (!this.ready) {
  578. throw new DeveloperError(
  579. "credit must not be called before the imagery provider is ready."
  580. );
  581. }
  582. //>>includeEnd('debug');
  583. return this._credit;
  584. },
  585. },
  586. /**
  587. * Gets a value indicating whether or not the images provided by this imagery provider
  588. * include an alpha channel. If this property is false, an alpha channel, if present, will
  589. * be ignored. If this property is true, any images without an alpha channel will be treated
  590. * as if their alpha is 1.0 everywhere. When this property is false, memory usage
  591. * and texture upload time are reduced. This function should
  592. * not be called before {@link ImageryProvider#ready} returns true.
  593. * @memberof UrlTemplateImageryProvider.prototype
  594. * @type {Boolean}
  595. * @readonly
  596. * @default true
  597. */
  598. hasAlphaChannel: {
  599. get: function () {
  600. //>>includeStart('debug', pragmas.debug);
  601. if (!this.ready) {
  602. throw new DeveloperError(
  603. "hasAlphaChannel must not be called before the imagery provider is ready."
  604. );
  605. }
  606. //>>includeEnd('debug');
  607. return this._hasAlphaChannel;
  608. },
  609. },
  610. });
  611. /**
  612. * Reinitializes this instance. Reinitializing an instance already in use is supported, but it is not
  613. * recommended because existing tiles provided by the imagery provider will not be updated.
  614. *
  615. * @param {Promise.<Object>|Object} options Any of the options that may be passed to the {@link UrlTemplateImageryProvider} constructor.
  616. */
  617. UrlTemplateImageryProvider.prototype.reinitialize = function (options) {
  618. const that = this;
  619. that._readyPromise = Promise.resolve(options).then(function (properties) {
  620. //>>includeStart('debug', pragmas.debug);
  621. if (!defined(properties)) {
  622. throw new DeveloperError("options is required.");
  623. }
  624. if (!defined(properties.url)) {
  625. throw new DeveloperError("options.url is required.");
  626. }
  627. //>>includeEnd('debug');
  628. const customTags = properties.customTags;
  629. const allTags = combine(tags, customTags);
  630. const allPickFeaturesTags = combine(pickFeaturesTags, customTags);
  631. const resource = Resource.createIfNeeded(properties.url);
  632. const pickFeaturesResource = Resource.createIfNeeded(
  633. properties.pickFeaturesUrl
  634. );
  635. that.enablePickFeatures = defaultValue(
  636. properties.enablePickFeatures,
  637. that.enablePickFeatures
  638. );
  639. that._urlSchemeZeroPadding = defaultValue(
  640. properties.urlSchemeZeroPadding,
  641. that.urlSchemeZeroPadding
  642. );
  643. that._tileDiscardPolicy = properties.tileDiscardPolicy;
  644. that._getFeatureInfoFormats = properties.getFeatureInfoFormats;
  645. that._subdomains = properties.subdomains;
  646. if (Array.isArray(that._subdomains)) {
  647. that._subdomains = that._subdomains.slice();
  648. } else if (defined(that._subdomains) && that._subdomains.length > 0) {
  649. that._subdomains = that._subdomains.split("");
  650. } else {
  651. that._subdomains = ["a", "b", "c"];
  652. }
  653. that._tileWidth = defaultValue(properties.tileWidth, 256);
  654. that._tileHeight = defaultValue(properties.tileHeight, 256);
  655. that._minimumLevel = defaultValue(properties.minimumLevel, 0);
  656. that._maximumLevel = properties.maximumLevel;
  657. that._tilingScheme = defaultValue(
  658. properties.tilingScheme,
  659. new WebMercatorTilingScheme({ ellipsoid: properties.ellipsoid })
  660. );
  661. that._rectangle = defaultValue(
  662. properties.rectangle,
  663. that._tilingScheme.rectangle
  664. );
  665. that._rectangle = Rectangle.intersection(
  666. that._rectangle,
  667. that._tilingScheme.rectangle
  668. );
  669. that._hasAlphaChannel = defaultValue(properties.hasAlphaChannel, true);
  670. let credit = properties.credit;
  671. if (typeof credit === "string") {
  672. credit = new Credit(credit);
  673. }
  674. that._credit = credit;
  675. that._resource = resource;
  676. that._tags = allTags;
  677. that._pickFeaturesResource = pickFeaturesResource;
  678. that._pickFeaturesTags = allPickFeaturesTags;
  679. return true;
  680. });
  681. };
  682. /**
  683. * Gets the credits to be displayed when a given tile is displayed.
  684. *
  685. * @param {Number} x The tile X coordinate.
  686. * @param {Number} y The tile Y coordinate.
  687. * @param {Number} level The tile level;
  688. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  689. *
  690. * @exception {DeveloperError} <code>getTileCredits</code> must not be called before the imagery provider is ready.
  691. */
  692. UrlTemplateImageryProvider.prototype.getTileCredits = function (x, y, level) {
  693. //>>includeStart('debug', pragmas.debug);
  694. if (!this.ready) {
  695. throw new DeveloperError(
  696. "getTileCredits must not be called before the imagery provider is ready."
  697. );
  698. }
  699. //>>includeEnd('debug');
  700. return undefined;
  701. };
  702. /**
  703. * Requests the image for a given tile. This function should
  704. * not be called before {@link UrlTemplateImageryProvider#ready} returns true.
  705. *
  706. * @param {Number} x The tile X coordinate.
  707. * @param {Number} y The tile Y coordinate.
  708. * @param {Number} level The tile level.
  709. * @param {Request} [request] The request object. Intended for internal use only.
  710. * @returns {Promise.<ImageryTypes>|undefined} A promise for the image that will resolve when the image is available, or
  711. * undefined if there are too many active requests to the server, and the request should be retried later.
  712. */
  713. UrlTemplateImageryProvider.prototype.requestImage = function (
  714. x,
  715. y,
  716. level,
  717. request
  718. ) {
  719. //>>includeStart('debug', pragmas.debug);
  720. if (!this.ready) {
  721. throw new DeveloperError(
  722. "requestImage must not be called before the imagery provider is ready."
  723. );
  724. }
  725. //>>includeEnd('debug');
  726. return ImageryProvider.loadImage(
  727. this,
  728. buildImageResource(this, x, y, level, request)
  729. );
  730. };
  731. /**
  732. * Asynchronously determines what features, if any, are located at a given longitude and latitude within
  733. * a tile. This function should not be called before {@link ImageryProvider#ready} returns true.
  734. *
  735. * @param {Number} x The tile X coordinate.
  736. * @param {Number} y The tile Y coordinate.
  737. * @param {Number} level The tile level.
  738. * @param {Number} longitude The longitude at which to pick features.
  739. * @param {Number} latitude The latitude at which to pick features.
  740. * @return {Promise.<ImageryLayerFeatureInfo[]>|undefined} A promise for the picked features that will resolve when the asynchronous
  741. * picking completes. The resolved value is an array of {@link ImageryLayerFeatureInfo}
  742. * instances. The array may be empty if no features are found at the given location.
  743. * It may also be undefined if picking is not supported.
  744. */
  745. UrlTemplateImageryProvider.prototype.pickFeatures = function (
  746. x,
  747. y,
  748. level,
  749. longitude,
  750. latitude
  751. ) {
  752. //>>includeStart('debug', pragmas.debug);
  753. if (!this.ready) {
  754. throw new DeveloperError(
  755. "pickFeatures must not be called before the imagery provider is ready."
  756. );
  757. }
  758. //>>includeEnd('debug');
  759. if (
  760. !this.enablePickFeatures ||
  761. !defined(this._pickFeaturesResource) ||
  762. this._getFeatureInfoFormats.length === 0
  763. ) {
  764. return undefined;
  765. }
  766. let formatIndex = 0;
  767. const that = this;
  768. function handleResponse(format, data) {
  769. return format.callback(data);
  770. }
  771. function doRequest() {
  772. if (formatIndex >= that._getFeatureInfoFormats.length) {
  773. // No valid formats, so no features picked.
  774. return Promise.resolve([]);
  775. }
  776. const format = that._getFeatureInfoFormats[formatIndex];
  777. const resource = buildPickFeaturesResource(
  778. that,
  779. x,
  780. y,
  781. level,
  782. longitude,
  783. latitude,
  784. format.format
  785. );
  786. ++formatIndex;
  787. if (format.type === "json") {
  788. return resource.fetchJson().then(format.callback).catch(doRequest);
  789. } else if (format.type === "xml") {
  790. return resource.fetchXML().then(format.callback).catch(doRequest);
  791. } else if (format.type === "text" || format.type === "html") {
  792. return resource.fetchText().then(format.callback).catch(doRequest);
  793. }
  794. return resource
  795. .fetch({
  796. responseType: format.format,
  797. })
  798. .then(handleResponse.bind(undefined, format))
  799. .catch(doRequest);
  800. }
  801. return doRequest();
  802. };
  803. let degreesScratchComputed = false;
  804. const degreesScratch = new Rectangle();
  805. let projectedScratchComputed = false;
  806. const projectedScratch = new Rectangle();
  807. function buildImageResource(imageryProvider, x, y, level, request) {
  808. degreesScratchComputed = false;
  809. projectedScratchComputed = false;
  810. const resource = imageryProvider._resource;
  811. const url = resource.getUrlComponent(true);
  812. const allTags = imageryProvider._tags;
  813. const templateValues = {};
  814. const match = url.match(templateRegex);
  815. if (defined(match)) {
  816. match.forEach(function (tag) {
  817. const key = tag.substring(1, tag.length - 1); //strip {}
  818. if (defined(allTags[key])) {
  819. templateValues[key] = allTags[key](imageryProvider, x, y, level);
  820. }
  821. });
  822. }
  823. return resource.getDerivedResource({
  824. request: request,
  825. templateValues: templateValues,
  826. });
  827. }
  828. let ijScratchComputed = false;
  829. const ijScratch = new Cartesian2();
  830. let longitudeLatitudeProjectedScratchComputed = false;
  831. function buildPickFeaturesResource(
  832. imageryProvider,
  833. x,
  834. y,
  835. level,
  836. longitude,
  837. latitude,
  838. format
  839. ) {
  840. degreesScratchComputed = false;
  841. projectedScratchComputed = false;
  842. ijScratchComputed = false;
  843. longitudeLatitudeProjectedScratchComputed = false;
  844. const resource = imageryProvider._pickFeaturesResource;
  845. const url = resource.getUrlComponent(true);
  846. const allTags = imageryProvider._pickFeaturesTags;
  847. const templateValues = {};
  848. const match = url.match(templateRegex);
  849. if (defined(match)) {
  850. match.forEach(function (tag) {
  851. const key = tag.substring(1, tag.length - 1); //strip {}
  852. if (defined(allTags[key])) {
  853. templateValues[key] = allTags[key](
  854. imageryProvider,
  855. x,
  856. y,
  857. level,
  858. longitude,
  859. latitude,
  860. format
  861. );
  862. }
  863. });
  864. }
  865. return resource.getDerivedResource({
  866. templateValues: templateValues,
  867. });
  868. }
  869. function padWithZerosIfNecessary(imageryProvider, key, value) {
  870. if (
  871. imageryProvider &&
  872. imageryProvider.urlSchemeZeroPadding &&
  873. imageryProvider.urlSchemeZeroPadding.hasOwnProperty(key)
  874. ) {
  875. const paddingTemplate = imageryProvider.urlSchemeZeroPadding[key];
  876. if (typeof paddingTemplate === "string") {
  877. const paddingTemplateWidth = paddingTemplate.length;
  878. if (paddingTemplateWidth > 1) {
  879. value =
  880. value.length >= paddingTemplateWidth
  881. ? value
  882. : new Array(
  883. paddingTemplateWidth - value.toString().length + 1
  884. ).join("0") + value;
  885. }
  886. }
  887. }
  888. return value;
  889. }
  890. function xTag(imageryProvider, x, y, level) {
  891. return padWithZerosIfNecessary(imageryProvider, "{x}", x);
  892. }
  893. function reverseXTag(imageryProvider, x, y, level) {
  894. const reverseX =
  895. imageryProvider.tilingScheme.getNumberOfXTilesAtLevel(level) - x - 1;
  896. return padWithZerosIfNecessary(imageryProvider, "{reverseX}", reverseX);
  897. }
  898. function yTag(imageryProvider, x, y, level) {
  899. return padWithZerosIfNecessary(imageryProvider, "{y}", y);
  900. }
  901. function reverseYTag(imageryProvider, x, y, level) {
  902. const reverseY =
  903. imageryProvider.tilingScheme.getNumberOfYTilesAtLevel(level) - y - 1;
  904. return padWithZerosIfNecessary(imageryProvider, "{reverseY}", reverseY);
  905. }
  906. function reverseZTag(imageryProvider, x, y, level) {
  907. const maximumLevel = imageryProvider.maximumLevel;
  908. const reverseZ =
  909. defined(maximumLevel) && level < maximumLevel
  910. ? maximumLevel - level - 1
  911. : level;
  912. return padWithZerosIfNecessary(imageryProvider, "{reverseZ}", reverseZ);
  913. }
  914. function zTag(imageryProvider, x, y, level) {
  915. return padWithZerosIfNecessary(imageryProvider, "{z}", level);
  916. }
  917. function sTag(imageryProvider, x, y, level) {
  918. const index = (x + y + level) % imageryProvider._subdomains.length;
  919. return imageryProvider._subdomains[index];
  920. }
  921. function computeDegrees(imageryProvider, x, y, level) {
  922. if (degreesScratchComputed) {
  923. return;
  924. }
  925. imageryProvider.tilingScheme.tileXYToRectangle(x, y, level, degreesScratch);
  926. degreesScratch.west = CesiumMath.toDegrees(degreesScratch.west);
  927. degreesScratch.south = CesiumMath.toDegrees(degreesScratch.south);
  928. degreesScratch.east = CesiumMath.toDegrees(degreesScratch.east);
  929. degreesScratch.north = CesiumMath.toDegrees(degreesScratch.north);
  930. degreesScratchComputed = true;
  931. }
  932. function westDegreesTag(imageryProvider, x, y, level) {
  933. computeDegrees(imageryProvider, x, y, level);
  934. return degreesScratch.west;
  935. }
  936. function southDegreesTag(imageryProvider, x, y, level) {
  937. computeDegrees(imageryProvider, x, y, level);
  938. return degreesScratch.south;
  939. }
  940. function eastDegreesTag(imageryProvider, x, y, level) {
  941. computeDegrees(imageryProvider, x, y, level);
  942. return degreesScratch.east;
  943. }
  944. function northDegreesTag(imageryProvider, x, y, level) {
  945. computeDegrees(imageryProvider, x, y, level);
  946. return degreesScratch.north;
  947. }
  948. function computeProjected(imageryProvider, x, y, level) {
  949. if (projectedScratchComputed) {
  950. return;
  951. }
  952. imageryProvider.tilingScheme.tileXYToNativeRectangle(
  953. x,
  954. y,
  955. level,
  956. projectedScratch
  957. );
  958. projectedScratchComputed = true;
  959. }
  960. function westProjectedTag(imageryProvider, x, y, level) {
  961. computeProjected(imageryProvider, x, y, level);
  962. return projectedScratch.west;
  963. }
  964. function southProjectedTag(imageryProvider, x, y, level) {
  965. computeProjected(imageryProvider, x, y, level);
  966. return projectedScratch.south;
  967. }
  968. function eastProjectedTag(imageryProvider, x, y, level) {
  969. computeProjected(imageryProvider, x, y, level);
  970. return projectedScratch.east;
  971. }
  972. function northProjectedTag(imageryProvider, x, y, level) {
  973. computeProjected(imageryProvider, x, y, level);
  974. return projectedScratch.north;
  975. }
  976. function widthTag(imageryProvider, x, y, level) {
  977. return imageryProvider.tileWidth;
  978. }
  979. function heightTag(imageryProvider, x, y, level) {
  980. return imageryProvider.tileHeight;
  981. }
  982. function iTag(imageryProvider, x, y, level, longitude, latitude, format) {
  983. computeIJ(imageryProvider, x, y, level, longitude, latitude);
  984. return ijScratch.x;
  985. }
  986. function jTag(imageryProvider, x, y, level, longitude, latitude, format) {
  987. computeIJ(imageryProvider, x, y, level, longitude, latitude);
  988. return ijScratch.y;
  989. }
  990. function reverseITag(
  991. imageryProvider,
  992. x,
  993. y,
  994. level,
  995. longitude,
  996. latitude,
  997. format
  998. ) {
  999. computeIJ(imageryProvider, x, y, level, longitude, latitude);
  1000. return imageryProvider.tileWidth - ijScratch.x - 1;
  1001. }
  1002. function reverseJTag(
  1003. imageryProvider,
  1004. x,
  1005. y,
  1006. level,
  1007. longitude,
  1008. latitude,
  1009. format
  1010. ) {
  1011. computeIJ(imageryProvider, x, y, level, longitude, latitude);
  1012. return imageryProvider.tileHeight - ijScratch.y - 1;
  1013. }
  1014. const rectangleScratch = new Rectangle();
  1015. const longitudeLatitudeProjectedScratch = new Cartesian3();
  1016. function computeIJ(imageryProvider, x, y, level, longitude, latitude, format) {
  1017. if (ijScratchComputed) {
  1018. return;
  1019. }
  1020. computeLongitudeLatitudeProjected(
  1021. imageryProvider,
  1022. x,
  1023. y,
  1024. level,
  1025. longitude,
  1026. latitude
  1027. );
  1028. const projected = longitudeLatitudeProjectedScratch;
  1029. const rectangle = imageryProvider.tilingScheme.tileXYToNativeRectangle(
  1030. x,
  1031. y,
  1032. level,
  1033. rectangleScratch
  1034. );
  1035. ijScratch.x =
  1036. ((imageryProvider.tileWidth * (projected.x - rectangle.west)) /
  1037. rectangle.width) |
  1038. 0;
  1039. ijScratch.y =
  1040. ((imageryProvider.tileHeight * (rectangle.north - projected.y)) /
  1041. rectangle.height) |
  1042. 0;
  1043. ijScratchComputed = true;
  1044. }
  1045. function longitudeDegreesTag(
  1046. imageryProvider,
  1047. x,
  1048. y,
  1049. level,
  1050. longitude,
  1051. latitude,
  1052. format
  1053. ) {
  1054. return CesiumMath.toDegrees(longitude);
  1055. }
  1056. function latitudeDegreesTag(
  1057. imageryProvider,
  1058. x,
  1059. y,
  1060. level,
  1061. longitude,
  1062. latitude,
  1063. format
  1064. ) {
  1065. return CesiumMath.toDegrees(latitude);
  1066. }
  1067. function longitudeProjectedTag(
  1068. imageryProvider,
  1069. x,
  1070. y,
  1071. level,
  1072. longitude,
  1073. latitude,
  1074. format
  1075. ) {
  1076. computeLongitudeLatitudeProjected(
  1077. imageryProvider,
  1078. x,
  1079. y,
  1080. level,
  1081. longitude,
  1082. latitude
  1083. );
  1084. return longitudeLatitudeProjectedScratch.x;
  1085. }
  1086. function latitudeProjectedTag(
  1087. imageryProvider,
  1088. x,
  1089. y,
  1090. level,
  1091. longitude,
  1092. latitude,
  1093. format
  1094. ) {
  1095. computeLongitudeLatitudeProjected(
  1096. imageryProvider,
  1097. x,
  1098. y,
  1099. level,
  1100. longitude,
  1101. latitude
  1102. );
  1103. return longitudeLatitudeProjectedScratch.y;
  1104. }
  1105. const cartographicScratch = new Cartographic();
  1106. function computeLongitudeLatitudeProjected(
  1107. imageryProvider,
  1108. x,
  1109. y,
  1110. level,
  1111. longitude,
  1112. latitude,
  1113. format
  1114. ) {
  1115. if (longitudeLatitudeProjectedScratchComputed) {
  1116. return;
  1117. }
  1118. if (imageryProvider.tilingScheme.projection instanceof GeographicProjection) {
  1119. longitudeLatitudeProjectedScratch.x = CesiumMath.toDegrees(longitude);
  1120. longitudeLatitudeProjectedScratch.y = CesiumMath.toDegrees(latitude);
  1121. } else {
  1122. const cartographic = cartographicScratch;
  1123. cartographic.longitude = longitude;
  1124. cartographic.latitude = latitude;
  1125. imageryProvider.tilingScheme.projection.project(
  1126. cartographic,
  1127. longitudeLatitudeProjectedScratch
  1128. );
  1129. }
  1130. longitudeLatitudeProjectedScratchComputed = true;
  1131. }
  1132. function formatTag(imageryProvider, x, y, level, longitude, latitude, format) {
  1133. return format;
  1134. }
  1135. export default UrlTemplateImageryProvider;