UrlTemplateImageryProvider.js 49 KB

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