UrlTemplateImageryProvider.js 44 KB

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