智慧水务管理系统 - 精河县供水工程综合管理平台

GoogleEarthEnterpriseImageryProvider.js 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. import Check from "../Core/Check.js";
  2. import Credit from "../Core/Credit.js";
  3. import decodeGoogleEarthEnterpriseData from "../Core/decodeGoogleEarthEnterpriseData.js";
  4. import Frozen from "../Core/Frozen.js";
  5. import defined from "../Core/defined.js";
  6. import Event from "../Core/Event.js";
  7. import GeographicTilingScheme from "../Core/GeographicTilingScheme.js";
  8. import GoogleEarthEnterpriseMetadata from "../Core/GoogleEarthEnterpriseMetadata.js";
  9. import loadImageFromTypedArray from "../Core/loadImageFromTypedArray.js";
  10. import CesiumMath from "../Core/Math.js";
  11. import Rectangle from "../Core/Rectangle.js";
  12. import Request from "../Core/Request.js";
  13. import RuntimeError from "../Core/RuntimeError.js";
  14. import * as protobuf from "protobufjs/dist/minimal/protobuf.js";
  15. /**
  16. * @private
  17. */
  18. function GoogleEarthEnterpriseDiscardPolicy() {
  19. this._image = new Image();
  20. }
  21. /**
  22. * Determines if the discard policy is ready to process images.
  23. * @returns {boolean} True if the discard policy is ready to process images; otherwise, false.
  24. */
  25. GoogleEarthEnterpriseDiscardPolicy.prototype.isReady = function () {
  26. return true;
  27. };
  28. /**
  29. * Given a tile image, decide whether to discard that image.
  30. *
  31. * @param {HTMLImageElement} image An image to test.
  32. * @returns {boolean} True if the image should be discarded; otherwise, false.
  33. */
  34. GoogleEarthEnterpriseDiscardPolicy.prototype.shouldDiscardImage = function (
  35. image,
  36. ) {
  37. return image === this._image;
  38. };
  39. /**
  40. * @typedef {object} GoogleEarthEnterpriseImageryProvider.ConstructorOptions
  41. *
  42. * Initialization options for the GoogleEarthEnterpriseImageryProvider constructor
  43. *
  44. * @property {Ellipsoid} [ellipsoid=Ellipsoid.default] The ellipsoid. If not specified, the default ellipsoid is used.
  45. * @property {TileDiscardPolicy} [tileDiscardPolicy] The policy that determines if a tile
  46. * is invalid and should be discarded. If this value is not specified, a default
  47. * is to discard tiles that fail to download.
  48. * @property {Credit|string} [credit] A credit for the data source, which is displayed on the canvas.
  49. */
  50. /**
  51. * <div class="notice">
  52. * To construct a GoogleEarthEnterpriseImageryProvider, call {@link GoogleEarthEnterpriseImageryProvider.fromMetadata}. Do not call the constructor directly.
  53. * </div>
  54. *
  55. * Provides tiled imagery using the Google Earth Enterprise REST API.
  56. *
  57. * Notes: This provider is for use with the 3D Earth API of Google Earth Enterprise,
  58. * {@link GoogleEarthEnterpriseMapsProvider} should be used with 2D Maps API.
  59. *
  60. * @alias GoogleEarthEnterpriseImageryProvider
  61. * @constructor
  62. *
  63. * @param {GoogleEarthEnterpriseImageryProvider.ConstructorOptions} [options] Object describing initialization options
  64. *
  65. * @see GoogleEarthEnterpriseImageryProvider.fromMetadata
  66. * @see GoogleEarthEnterpriseTerrainProvider
  67. * @see ArcGisMapServerImageryProvider
  68. * @see GoogleEarthEnterpriseMapsProvider
  69. * @see OpenStreetMapImageryProvider
  70. * @see SingleTileImageryProvider
  71. * @see TileMapServiceImageryProvider
  72. * @see WebMapServiceImageryProvider
  73. * @see WebMapTileServiceImageryProvider
  74. * @see UrlTemplateImageryProvider
  75. *
  76. *
  77. * @example
  78. * const geeMetadata = await GoogleEarthEnterpriseMetadata.fromUrl("http://www.example.com");
  79. * const gee = Cesium.GoogleEarthEnterpriseImageryProvider.fromMetadata(geeMetadata);
  80. *
  81. * @see {@link http://www.w3.org/TR/cors/|Cross-Origin Resource Sharing}
  82. */
  83. function GoogleEarthEnterpriseImageryProvider(options) {
  84. options = options ?? Frozen.EMPTY_OBJECT;
  85. this._defaultAlpha = undefined;
  86. this._defaultNightAlpha = undefined;
  87. this._defaultDayAlpha = undefined;
  88. this._defaultBrightness = undefined;
  89. this._defaultContrast = undefined;
  90. this._defaultHue = undefined;
  91. this._defaultSaturation = undefined;
  92. this._defaultGamma = undefined;
  93. this._defaultMinificationFilter = undefined;
  94. this._defaultMagnificationFilter = undefined;
  95. this._tileDiscardPolicy = options.tileDiscardPolicy;
  96. this._tilingScheme = new GeographicTilingScheme({
  97. numberOfLevelZeroTilesX: 2,
  98. numberOfLevelZeroTilesY: 2,
  99. rectangle: new Rectangle(
  100. -CesiumMath.PI,
  101. -CesiumMath.PI,
  102. CesiumMath.PI,
  103. CesiumMath.PI,
  104. ),
  105. ellipsoid: options.ellipsoid,
  106. });
  107. let credit = options.credit;
  108. if (typeof credit === "string") {
  109. credit = new Credit(credit);
  110. }
  111. this._credit = credit;
  112. this._tileWidth = 256;
  113. this._tileHeight = 256;
  114. this._maximumLevel = 23;
  115. // Install the default tile discard policy if none has been supplied.
  116. if (!defined(this._tileDiscardPolicy)) {
  117. this._tileDiscardPolicy = new GoogleEarthEnterpriseDiscardPolicy();
  118. }
  119. this._errorEvent = new Event();
  120. }
  121. Object.defineProperties(GoogleEarthEnterpriseImageryProvider.prototype, {
  122. /**
  123. * Gets the name of the Google Earth Enterprise server url hosting the imagery.
  124. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  125. * @type {string}
  126. * @readonly
  127. */
  128. url: {
  129. get: function () {
  130. return this._metadata.url;
  131. },
  132. },
  133. /**
  134. * Gets the proxy used by this provider.
  135. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  136. * @type {Proxy}
  137. * @readonly
  138. */
  139. proxy: {
  140. get: function () {
  141. return this._metadata.proxy;
  142. },
  143. },
  144. /**
  145. * Gets the width of each tile, in pixels.
  146. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  147. * @type {number}
  148. * @readonly
  149. */
  150. tileWidth: {
  151. get: function () {
  152. return this._tileWidth;
  153. },
  154. },
  155. /**
  156. * Gets the height of each tile, in pixels.
  157. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  158. * @type {number}
  159. * @readonly
  160. */
  161. tileHeight: {
  162. get: function () {
  163. return this._tileHeight;
  164. },
  165. },
  166. /**
  167. * Gets the maximum level-of-detail that can be requested.
  168. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  169. * @type {number|undefined}
  170. * @readonly
  171. */
  172. maximumLevel: {
  173. get: function () {
  174. return this._maximumLevel;
  175. },
  176. },
  177. /**
  178. * Gets the minimum level-of-detail that can be requested.
  179. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  180. * @type {number}
  181. * @readonly
  182. */
  183. minimumLevel: {
  184. get: function () {
  185. return 0;
  186. },
  187. },
  188. /**
  189. * Gets the tiling scheme used by this provider.
  190. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  191. * @type {TilingScheme}
  192. * @readonly
  193. */
  194. tilingScheme: {
  195. get: function () {
  196. return this._tilingScheme;
  197. },
  198. },
  199. /**
  200. * Gets the rectangle, in radians, of the imagery provided by this instance.
  201. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  202. * @type {Rectangle}
  203. * @readonly
  204. */
  205. rectangle: {
  206. get: function () {
  207. return this._tilingScheme.rectangle;
  208. },
  209. },
  210. /**
  211. * Gets the tile discard policy. If not undefined, the discard policy is responsible
  212. * for filtering out "missing" tiles via its shouldDiscardImage function. If this function
  213. * returns undefined, no tiles are filtered.
  214. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  215. * @type {TileDiscardPolicy}
  216. * @readonly
  217. */
  218. tileDiscardPolicy: {
  219. get: function () {
  220. return this._tileDiscardPolicy;
  221. },
  222. },
  223. /**
  224. * Gets an event that is raised when the imagery provider encounters an asynchronous error. By subscribing
  225. * to the event, you will be notified of the error and can potentially recover from it. Event listeners
  226. * are passed an instance of {@link TileProviderError}.
  227. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  228. * @type {Event}
  229. * @readonly
  230. */
  231. errorEvent: {
  232. get: function () {
  233. return this._errorEvent;
  234. },
  235. },
  236. /**
  237. * Gets the credit to display when this imagery provider is active. Typically this is used to credit
  238. * the source of the imagery.
  239. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  240. * @type {Credit}
  241. * @readonly
  242. */
  243. credit: {
  244. get: function () {
  245. return this._credit;
  246. },
  247. },
  248. /**
  249. * Gets a value indicating whether or not the images provided by this imagery provider
  250. * include an alpha channel. If this property is false, an alpha channel, if present, will
  251. * be ignored. If this property is true, any images without an alpha channel will be treated
  252. * as if their alpha is 1.0 everywhere. Setting this property to false reduces memory usage
  253. * and texture upload time.
  254. * @memberof GoogleEarthEnterpriseImageryProvider.prototype
  255. * @type {boolean}
  256. * @readonly
  257. */
  258. hasAlphaChannel: {
  259. get: function () {
  260. return false;
  261. },
  262. },
  263. });
  264. /**
  265. * Creates a tiled imagery provider using the Google Earth Enterprise REST API.
  266. * @param {GoogleEarthEnterpriseMetadata} metadata A metadata object that can be used to share metadata requests with a GoogleEarthEnterpriseTerrainProvider.
  267. * @param {GoogleEarthEnterpriseImageryProvider.ConstructorOptions} options Object describing initialization options.
  268. * @returns {GoogleEarthEnterpriseImageryProvider}
  269. *
  270. * @exception {RuntimeError} The metadata url does not have imagery
  271. *
  272. * @example
  273. * const geeMetadata = await GoogleEarthEnterpriseMetadata.fromUrl("http://www.example.com");
  274. * const gee = Cesium.GoogleEarthEnterpriseImageryProvider.fromMetadata(geeMetadata);
  275. */
  276. GoogleEarthEnterpriseImageryProvider.fromMetadata = function (
  277. metadata,
  278. options,
  279. ) {
  280. //>>includeStart('debug', pragmas.debug);
  281. Check.defined("metadata", metadata);
  282. //>>includeEnd('debug');
  283. if (!metadata.imageryPresent) {
  284. throw new RuntimeError(`The server ${metadata.url} doesn't have imagery`);
  285. }
  286. const provider = new GoogleEarthEnterpriseImageryProvider(options);
  287. provider._metadata = metadata;
  288. return provider;
  289. };
  290. /**
  291. * Gets the credits to be displayed when a given tile is displayed.
  292. *
  293. * @param {number} x The tile X coordinate.
  294. * @param {number} y The tile Y coordinate.
  295. * @param {number} level The tile level;
  296. * @returns {Credit[]} The credits to be displayed when the tile is displayed.
  297. */
  298. GoogleEarthEnterpriseImageryProvider.prototype.getTileCredits = function (
  299. x,
  300. y,
  301. level,
  302. ) {
  303. const metadata = this._metadata;
  304. const info = metadata.getTileInformation(x, y, level);
  305. if (defined(info)) {
  306. const credit = metadata.providers[info.imageryProvider];
  307. if (defined(credit)) {
  308. return [credit];
  309. }
  310. }
  311. return undefined;
  312. };
  313. /**
  314. * Requests the image for a given tile.
  315. *
  316. * @param {number} x The tile X coordinate.
  317. * @param {number} y The tile Y coordinate.
  318. * @param {number} level The tile level.
  319. * @param {Request} [request] The request object. Intended for internal use only.
  320. * @returns {Promise<ImageryTypes>|undefined} A promise for the image that will resolve when the image is available, or
  321. * undefined if there are too many active requests to the server, and the request should be retried later.
  322. */
  323. GoogleEarthEnterpriseImageryProvider.prototype.requestImage = function (
  324. x,
  325. y,
  326. level,
  327. request,
  328. ) {
  329. const invalidImage = this._tileDiscardPolicy._image; // Empty image or undefined depending on discard policy
  330. const metadata = this._metadata;
  331. const quadKey = GoogleEarthEnterpriseMetadata.tileXYToQuadKey(x, y, level);
  332. const info = metadata.getTileInformation(x, y, level);
  333. if (!defined(info)) {
  334. if (metadata.isValid(quadKey)) {
  335. const metadataRequest = new Request({
  336. throttle: request.throttle,
  337. throttleByServer: request.throttleByServer,
  338. type: request.type,
  339. priorityFunction: request.priorityFunction,
  340. });
  341. metadata.populateSubtree(x, y, level, metadataRequest);
  342. return undefined; // No metadata so return undefined so we can be loaded later
  343. }
  344. return Promise.resolve(invalidImage); // Image doesn't exist
  345. }
  346. if (!info.hasImagery()) {
  347. // Already have info and there isn't any imagery here
  348. return Promise.resolve(invalidImage);
  349. }
  350. const promise = buildImageResource(
  351. this,
  352. info,
  353. x,
  354. y,
  355. level,
  356. request,
  357. ).fetchArrayBuffer();
  358. if (!defined(promise)) {
  359. return undefined; // Throttled
  360. }
  361. return promise.then(function (image) {
  362. decodeGoogleEarthEnterpriseData(metadata.key, image);
  363. let a = new Uint8Array(image);
  364. let type;
  365. const protoImagery = metadata.protoImagery;
  366. if (!defined(protoImagery) || !protoImagery) {
  367. type = getImageType(a);
  368. }
  369. if (!defined(type) && (!defined(protoImagery) || protoImagery)) {
  370. const message = decodeEarthImageryPacket(a);
  371. type = message.imageType;
  372. a = message.imageData;
  373. }
  374. if (!defined(type) || !defined(a)) {
  375. return invalidImage;
  376. }
  377. return loadImageFromTypedArray({
  378. uint8Array: a,
  379. format: type,
  380. flipY: true,
  381. });
  382. });
  383. };
  384. /**
  385. * Picking features is not currently supported by this imagery provider, so this function simply returns
  386. * undefined.
  387. *
  388. * @param {number} x The tile X coordinate.
  389. * @param {number} y The tile Y coordinate.
  390. * @param {number} level The tile level.
  391. * @param {number} longitude The longitude at which to pick features.
  392. * @param {number} latitude The latitude at which to pick features.
  393. * @return {undefined} Undefined since picking is not supported.
  394. */
  395. GoogleEarthEnterpriseImageryProvider.prototype.pickFeatures = function (
  396. x,
  397. y,
  398. level,
  399. longitude,
  400. latitude,
  401. ) {
  402. return undefined;
  403. };
  404. //
  405. // Functions to handle imagery packets
  406. //
  407. function buildImageResource(imageryProvider, info, x, y, level, request) {
  408. const quadKey = GoogleEarthEnterpriseMetadata.tileXYToQuadKey(x, y, level);
  409. let version = info.imageryVersion;
  410. version = defined(version) && version > 0 ? version : 1;
  411. return imageryProvider._metadata.resource.getDerivedResource({
  412. url: `flatfile?f1-0${quadKey}-i.${version.toString()}`,
  413. request: request,
  414. });
  415. }
  416. // Detects if a Uint8Array is a JPEG or PNG
  417. function getImageType(image) {
  418. const jpeg = "JFIF";
  419. if (
  420. image[6] === jpeg.charCodeAt(0) &&
  421. image[7] === jpeg.charCodeAt(1) &&
  422. image[8] === jpeg.charCodeAt(2) &&
  423. image[9] === jpeg.charCodeAt(3)
  424. ) {
  425. return "image/jpeg";
  426. }
  427. const png = "PNG";
  428. if (
  429. image[1] === png.charCodeAt(0) &&
  430. image[2] === png.charCodeAt(1) &&
  431. image[3] === png.charCodeAt(2)
  432. ) {
  433. return "image/png";
  434. }
  435. return undefined;
  436. }
  437. // Decodes an Imagery protobuf into the message
  438. // Partially generated with the help of protobuf.js static generator
  439. function decodeEarthImageryPacket(data) {
  440. const reader = protobuf.Reader.create(data);
  441. const end = reader.len;
  442. const message = {};
  443. while (reader.pos < end) {
  444. const tag = reader.uint32();
  445. let copyrightIds;
  446. switch (tag >>> 3) {
  447. case 1:
  448. message.imageType = reader.uint32();
  449. break;
  450. case 2:
  451. message.imageData = reader.bytes();
  452. break;
  453. case 3:
  454. message.alphaType = reader.uint32();
  455. break;
  456. case 4:
  457. message.imageAlpha = reader.bytes();
  458. break;
  459. case 5:
  460. copyrightIds = message.copyrightIds;
  461. if (!defined(copyrightIds)) {
  462. copyrightIds = message.copyrightIds = [];
  463. }
  464. if ((tag & 7) === 2) {
  465. const end2 = reader.uint32() + reader.pos;
  466. while (reader.pos < end2) {
  467. copyrightIds.push(reader.uint32());
  468. }
  469. } else {
  470. copyrightIds.push(reader.uint32());
  471. }
  472. break;
  473. default:
  474. reader.skipType(tag & 7);
  475. break;
  476. }
  477. }
  478. const imageType = message.imageType;
  479. if (defined(imageType)) {
  480. switch (imageType) {
  481. case 0:
  482. message.imageType = "image/jpeg";
  483. break;
  484. case 4:
  485. message.imageType = "image/png";
  486. break;
  487. default:
  488. throw new RuntimeError(
  489. "GoogleEarthEnterpriseImageryProvider: Unsupported image type.",
  490. );
  491. }
  492. }
  493. const alphaType = message.alphaType;
  494. if (defined(alphaType) && alphaType !== 0) {
  495. console.log(
  496. "GoogleEarthEnterpriseImageryProvider: External alpha not supported.",
  497. );
  498. delete message.alphaType;
  499. delete message.imageAlpha;
  500. }
  501. return message;
  502. }
  503. export default GoogleEarthEnterpriseImageryProvider;