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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. import ApproximateTerrainHeights from "../Core/ApproximateTerrainHeights.js";
  2. import BoundingSphere from "../Core/BoundingSphere.js";
  3. import Check from "../Core/Check.js";
  4. import defined from "../Core/defined.js";
  5. import destroyObject from "../Core/destroyObject.js";
  6. import EventHelper from "../Core/EventHelper.js";
  7. import GroundPolylinePrimitive from "../Scene/GroundPolylinePrimitive.js";
  8. import GroundPrimitive from "../Scene/GroundPrimitive.js";
  9. import OrderedGroundPrimitiveCollection from "../Scene/OrderedGroundPrimitiveCollection.js";
  10. import PrimitiveCollection from "../Scene/PrimitiveCollection.js";
  11. import BillboardVisualizer from "./BillboardVisualizer.js";
  12. import BoundingSphereState from "./BoundingSphereState.js";
  13. import CustomDataSource from "./CustomDataSource.js";
  14. import GeometryVisualizer from "./GeometryVisualizer.js";
  15. import LabelVisualizer from "./LabelVisualizer.js";
  16. import ModelVisualizer from "./ModelVisualizer.js";
  17. import Cesium3DTilesetVisualizer from "./Cesium3DTilesetVisualizer.js";
  18. import PathVisualizer from "./PathVisualizer.js";
  19. import PointVisualizer from "./PointVisualizer.js";
  20. import PolylineVisualizer from "./PolylineVisualizer.js";
  21. /**
  22. * Visualizes a collection of {@link DataSource} instances.
  23. * @alias DataSourceDisplay
  24. * @constructor
  25. *
  26. * @param {object} options Object with the following properties:
  27. * @param {Scene} options.scene The scene in which to display the data.
  28. * @param {DataSourceCollection} options.dataSourceCollection The data sources to display.
  29. * @param {DataSourceDisplay.VisualizersCallback} [options.visualizersCallback=DataSourceDisplay.defaultVisualizersCallback]
  30. * A function which creates an array of visualizers used for visualization.
  31. * If undefined, all standard visualizers are used.
  32. */
  33. function DataSourceDisplay(options) {
  34. //>>includeStart('debug', pragmas.debug);
  35. Check.typeOf.object("options", options);
  36. Check.typeOf.object("options.scene", options.scene);
  37. Check.typeOf.object(
  38. "options.dataSourceCollection",
  39. options.dataSourceCollection,
  40. );
  41. //>>includeEnd('debug');
  42. GroundPrimitive.initializeTerrainHeights();
  43. GroundPolylinePrimitive.initializeTerrainHeights();
  44. const scene = options.scene;
  45. const dataSourceCollection = options.dataSourceCollection;
  46. this._eventHelper = new EventHelper();
  47. this._eventHelper.add(
  48. dataSourceCollection.dataSourceAdded,
  49. this._onDataSourceAdded,
  50. this,
  51. );
  52. this._eventHelper.add(
  53. dataSourceCollection.dataSourceRemoved,
  54. this._onDataSourceRemoved,
  55. this,
  56. );
  57. this._eventHelper.add(
  58. dataSourceCollection.dataSourceMoved,
  59. this._onDataSourceMoved,
  60. this,
  61. );
  62. this._eventHelper.add(scene.postRender, this._postRender, this);
  63. this._dataSourceCollection = dataSourceCollection;
  64. this._scene = scene;
  65. this._visualizersCallback =
  66. options.visualizersCallback ?? DataSourceDisplay.defaultVisualizersCallback;
  67. let primitivesAdded = false;
  68. const primitives = new PrimitiveCollection();
  69. const groundPrimitives = new PrimitiveCollection();
  70. if (dataSourceCollection.length > 0) {
  71. scene.primitives.add(primitives);
  72. scene.groundPrimitives.add(groundPrimitives);
  73. primitivesAdded = true;
  74. }
  75. this._primitives = primitives;
  76. this._groundPrimitives = groundPrimitives;
  77. for (let i = 0, len = dataSourceCollection.length; i < len; i++) {
  78. this._onDataSourceAdded(dataSourceCollection, dataSourceCollection.get(i));
  79. }
  80. const defaultDataSource = new CustomDataSource();
  81. this._onDataSourceAdded(undefined, defaultDataSource);
  82. this._defaultDataSource = defaultDataSource;
  83. let removeDefaultDataSourceListener;
  84. let removeDataSourceCollectionListener;
  85. if (!primitivesAdded) {
  86. const that = this;
  87. const addPrimitives = function () {
  88. scene.primitives.add(primitives);
  89. scene.groundPrimitives.add(groundPrimitives);
  90. removeDefaultDataSourceListener();
  91. removeDataSourceCollectionListener();
  92. that._removeDefaultDataSourceListener = undefined;
  93. that._removeDataSourceCollectionListener = undefined;
  94. };
  95. removeDefaultDataSourceListener =
  96. defaultDataSource.entities.collectionChanged.addEventListener(
  97. addPrimitives,
  98. );
  99. removeDataSourceCollectionListener =
  100. dataSourceCollection.dataSourceAdded.addEventListener(addPrimitives);
  101. }
  102. this._removeDefaultDataSourceListener = removeDefaultDataSourceListener;
  103. this._removeDataSourceCollectionListener = removeDataSourceCollectionListener;
  104. this._ready = false;
  105. }
  106. const ExtraVisualizers = [];
  107. /**
  108. * Add the provided Visualizer to the default visualizers callback if not already included
  109. * @private
  110. * @param {Visualizer} visualizer Visualizer class to add
  111. */
  112. DataSourceDisplay.registerVisualizer = function (visualizer) {
  113. if (!ExtraVisualizers.includes(visualizer)) {
  114. ExtraVisualizers.push(visualizer);
  115. }
  116. };
  117. /**
  118. * Remove the provided Visualizer from the default visualizers callback if it's already included
  119. * @private
  120. * @param {Visualizer} visualizer Visualizer class to remove
  121. */
  122. DataSourceDisplay.unregisterVisualizer = function (visualizer) {
  123. if (ExtraVisualizers.includes(visualizer)) {
  124. const index = ExtraVisualizers.indexOf(visualizer);
  125. ExtraVisualizers.splice(index, 1);
  126. }
  127. };
  128. /**
  129. * Gets or sets the default function which creates an array of visualizers used for visualization.
  130. * By default, this function uses all standard visualizers.
  131. *
  132. * @type {DataSourceDisplay.VisualizersCallback}
  133. */
  134. DataSourceDisplay.defaultVisualizersCallback = function (
  135. scene,
  136. entityCluster,
  137. dataSource,
  138. ) {
  139. const entities = dataSource.entities;
  140. return [
  141. new BillboardVisualizer(entityCluster, entities),
  142. new GeometryVisualizer(
  143. scene,
  144. entities,
  145. dataSource._primitives,
  146. dataSource._groundPrimitives,
  147. ),
  148. new LabelVisualizer(entityCluster, entities),
  149. new ModelVisualizer(scene, entities),
  150. new Cesium3DTilesetVisualizer(scene, entities),
  151. new PointVisualizer(entityCluster, entities),
  152. new PathVisualizer(scene, entities),
  153. new PolylineVisualizer(
  154. scene,
  155. entities,
  156. dataSource._primitives,
  157. dataSource._groundPrimitives,
  158. ),
  159. ...ExtraVisualizers.map(
  160. (VisualizerClass) => new VisualizerClass(scene, entities),
  161. ),
  162. ];
  163. };
  164. Object.defineProperties(DataSourceDisplay.prototype, {
  165. /**
  166. * Gets the scene associated with this display.
  167. * @memberof DataSourceDisplay.prototype
  168. * @type {Scene}
  169. */
  170. scene: {
  171. get: function () {
  172. return this._scene;
  173. },
  174. },
  175. /**
  176. * Gets the collection of data sources to display.
  177. * @memberof DataSourceDisplay.prototype
  178. * @type {DataSourceCollection}
  179. */
  180. dataSources: {
  181. get: function () {
  182. return this._dataSourceCollection;
  183. },
  184. },
  185. /**
  186. * Gets the default data source instance which can be used to
  187. * manually create and visualize entities not tied to
  188. * a specific data source. This instance is always available
  189. * and does not appear in the list dataSources collection.
  190. * @memberof DataSourceDisplay.prototype
  191. * @type {CustomDataSource}
  192. */
  193. defaultDataSource: {
  194. get: function () {
  195. return this._defaultDataSource;
  196. },
  197. },
  198. /**
  199. * Gets a value indicating whether or not all entities in the data source are ready
  200. * @memberof DataSourceDisplay.prototype
  201. * @type {boolean}
  202. * @readonly
  203. */
  204. ready: {
  205. get: function () {
  206. return this._ready;
  207. },
  208. },
  209. });
  210. /**
  211. * Returns true if this object was destroyed; otherwise, false.
  212. * <br /><br />
  213. * If this object was destroyed, it should not be used; calling any function other than
  214. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
  215. *
  216. * @returns {boolean} True if this object was destroyed; otherwise, false.
  217. *
  218. * @see DataSourceDisplay#destroy
  219. */
  220. DataSourceDisplay.prototype.isDestroyed = function () {
  221. return false;
  222. };
  223. /**
  224. * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
  225. * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
  226. * <br /><br />
  227. * Once an object is destroyed, it should not be used; calling any function other than
  228. * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
  229. * assign the return value (<code>undefined</code>) to the object as done in the example.
  230. *
  231. * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
  232. *
  233. *
  234. * @example
  235. * dataSourceDisplay = dataSourceDisplay.destroy();
  236. *
  237. * @see DataSourceDisplay#isDestroyed
  238. */
  239. DataSourceDisplay.prototype.destroy = function () {
  240. this._eventHelper.removeAll();
  241. const dataSourceCollection = this._dataSourceCollection;
  242. for (let i = 0, length = dataSourceCollection.length; i < length; ++i) {
  243. this._onDataSourceRemoved(
  244. this._dataSourceCollection,
  245. dataSourceCollection.get(i),
  246. );
  247. }
  248. this._onDataSourceRemoved(undefined, this._defaultDataSource);
  249. if (defined(this._removeDefaultDataSourceListener)) {
  250. this._removeDefaultDataSourceListener();
  251. this._removeDataSourceCollectionListener();
  252. } else {
  253. this._scene.primitives.remove(this._primitives);
  254. this._scene.groundPrimitives.remove(this._groundPrimitives);
  255. }
  256. return destroyObject(this);
  257. };
  258. /**
  259. * Updates the display to the provided time.
  260. *
  261. * @param {JulianDate} time The simulation time.
  262. * @returns {boolean} True if all data sources are ready to be displayed, false otherwise.
  263. */
  264. DataSourceDisplay.prototype.update = function (time) {
  265. //>>includeStart('debug', pragmas.debug);
  266. Check.defined("time", time);
  267. //>>includeEnd('debug');
  268. if (!ApproximateTerrainHeights.initialized) {
  269. this._ready = false;
  270. return false;
  271. }
  272. let result = true;
  273. let i;
  274. let x;
  275. let visualizers;
  276. let vLength;
  277. const dataSources = this._dataSourceCollection;
  278. const length = dataSources.length;
  279. for (i = 0; i < length; i++) {
  280. const dataSource = dataSources.get(i);
  281. if (defined(dataSource.update)) {
  282. result = dataSource.update(time) && result;
  283. }
  284. visualizers = dataSource._visualizers;
  285. vLength = visualizers.length;
  286. for (x = 0; x < vLength; x++) {
  287. result = visualizers[x].update(time) && result;
  288. }
  289. }
  290. visualizers = this._defaultDataSource._visualizers;
  291. vLength = visualizers.length;
  292. for (x = 0; x < vLength; x++) {
  293. result = visualizers[x].update(time) && result;
  294. }
  295. // Request a rendering of the scene when the data source
  296. // becomes 'ready' for the first time
  297. if (!this._ready && result) {
  298. this._scene.requestRender();
  299. }
  300. // once the DataSourceDisplay is ready it should stay ready to prevent
  301. // entities from breaking updates when they become "un-ready"
  302. this._ready = this._ready || result;
  303. return result;
  304. };
  305. DataSourceDisplay.prototype._postRender = function () {
  306. // Adds credits for all datasources
  307. const frameState = this._scene.frameState;
  308. const dataSources = this._dataSourceCollection;
  309. const length = dataSources.length;
  310. for (let i = 0; i < length; i++) {
  311. const dataSource = dataSources.get(i);
  312. const credit = dataSource.credit;
  313. if (defined(credit)) {
  314. frameState.creditDisplay.addCreditToNextFrame(credit);
  315. }
  316. // Credits from the resource that the user can't remove
  317. const credits = dataSource._resourceCredits;
  318. if (defined(credits)) {
  319. const creditCount = credits.length;
  320. for (let c = 0; c < creditCount; c++) {
  321. frameState.creditDisplay.addCreditToNextFrame(credits[c]);
  322. }
  323. }
  324. }
  325. };
  326. const getBoundingSphereArrayScratch = [];
  327. const getBoundingSphereBoundingSphereScratch = new BoundingSphere();
  328. /**
  329. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  330. * The bounding sphere is in the fixed frame of the scene's globe.
  331. *
  332. * @param {Entity} entity The entity whose bounding sphere to compute.
  333. * @param {boolean} allowPartial If true, pending bounding spheres are ignored and an answer will be returned from the currently available data.
  334. * If false, the the function will halt and return pending if any of the bounding spheres are pending.
  335. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  336. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  337. * BoundingSphereState.PENDING if the result is still being computed, or
  338. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  339. * @private
  340. */
  341. DataSourceDisplay.prototype.getBoundingSphere = function (
  342. entity,
  343. allowPartial,
  344. result,
  345. ) {
  346. //>>includeStart('debug', pragmas.debug);
  347. Check.defined("entity", entity);
  348. Check.typeOf.bool("allowPartial", allowPartial);
  349. Check.defined("result", result);
  350. //>>includeEnd('debug');
  351. if (!this._ready) {
  352. return BoundingSphereState.PENDING;
  353. }
  354. let i;
  355. let length;
  356. let dataSource = this._defaultDataSource;
  357. if (!dataSource.entities.contains(entity)) {
  358. dataSource = undefined;
  359. const dataSources = this._dataSourceCollection;
  360. length = dataSources.length;
  361. for (i = 0; i < length; i++) {
  362. const d = dataSources.get(i);
  363. if (d.entities.contains(entity)) {
  364. dataSource = d;
  365. break;
  366. }
  367. }
  368. }
  369. if (!defined(dataSource)) {
  370. return BoundingSphereState.FAILED;
  371. }
  372. const boundingSpheres = getBoundingSphereArrayScratch;
  373. const tmp = getBoundingSphereBoundingSphereScratch;
  374. let count = 0;
  375. let state = BoundingSphereState.DONE;
  376. const visualizers = dataSource._visualizers;
  377. const visualizersLength = visualizers.length;
  378. for (i = 0; i < visualizersLength; i++) {
  379. const visualizer = visualizers[i];
  380. if (defined(visualizer.getBoundingSphere)) {
  381. state = visualizers[i].getBoundingSphere(entity, tmp);
  382. if (!allowPartial && state === BoundingSphereState.PENDING) {
  383. return BoundingSphereState.PENDING;
  384. } else if (state === BoundingSphereState.DONE) {
  385. boundingSpheres[count] = BoundingSphere.clone(
  386. tmp,
  387. boundingSpheres[count],
  388. );
  389. count++;
  390. }
  391. }
  392. }
  393. if (count === 0) {
  394. return BoundingSphereState.FAILED;
  395. }
  396. boundingSpheres.length = count;
  397. BoundingSphere.fromBoundingSpheres(boundingSpheres, result);
  398. return BoundingSphereState.DONE;
  399. };
  400. DataSourceDisplay.prototype._onDataSourceAdded = function (
  401. dataSourceCollection,
  402. dataSource,
  403. ) {
  404. const scene = this._scene;
  405. const displayPrimitives = this._primitives;
  406. const displayGroundPrimitives = this._groundPrimitives;
  407. const primitives = displayPrimitives.add(new PrimitiveCollection());
  408. const groundPrimitives = displayGroundPrimitives.add(
  409. new OrderedGroundPrimitiveCollection(),
  410. );
  411. dataSource._primitives = primitives;
  412. dataSource._groundPrimitives = groundPrimitives;
  413. const entityCluster = dataSource.clustering;
  414. entityCluster._initialize(scene);
  415. primitives.add(entityCluster);
  416. dataSource._visualizers = this._visualizersCallback(
  417. scene,
  418. entityCluster,
  419. dataSource,
  420. );
  421. };
  422. DataSourceDisplay.prototype._onDataSourceRemoved = function (
  423. dataSourceCollection,
  424. dataSource,
  425. ) {
  426. const displayPrimitives = this._primitives;
  427. const displayGroundPrimitives = this._groundPrimitives;
  428. const primitives = dataSource._primitives;
  429. const groundPrimitives = dataSource._groundPrimitives;
  430. const entityCluster = dataSource.clustering;
  431. primitives.remove(entityCluster);
  432. const visualizers = dataSource._visualizers;
  433. const length = visualizers.length;
  434. for (let i = 0; i < length; i++) {
  435. visualizers[i].destroy();
  436. }
  437. displayPrimitives.remove(primitives);
  438. displayGroundPrimitives.remove(groundPrimitives);
  439. dataSource._visualizers = undefined;
  440. };
  441. DataSourceDisplay.prototype._onDataSourceMoved = function (
  442. dataSource,
  443. newIndex,
  444. oldIndex,
  445. ) {
  446. const displayPrimitives = this._primitives;
  447. const displayGroundPrimitives = this._groundPrimitives;
  448. const primitives = dataSource._primitives;
  449. const groundPrimitives = dataSource._groundPrimitives;
  450. if (newIndex === oldIndex + 1) {
  451. displayPrimitives.raise(primitives);
  452. displayGroundPrimitives.raise(groundPrimitives);
  453. } else if (newIndex === oldIndex - 1) {
  454. displayPrimitives.lower(primitives);
  455. displayGroundPrimitives.lower(groundPrimitives);
  456. } else if (newIndex === 0) {
  457. displayPrimitives.lowerToBottom(primitives);
  458. displayGroundPrimitives.lowerToBottom(groundPrimitives);
  459. displayPrimitives.raise(primitives); // keep defaultDataSource primitives at index 0 since it's not in the collection
  460. displayGroundPrimitives.raise(groundPrimitives);
  461. } else {
  462. displayPrimitives.raiseToTop(primitives);
  463. displayGroundPrimitives.raiseToTop(groundPrimitives);
  464. }
  465. };
  466. /**
  467. * A function which creates an array of visualizers used for visualization.
  468. * @callback DataSourceDisplay.VisualizersCallback
  469. *
  470. * @param {Scene} scene The scene to create visualizers for.
  471. * @param {EntityCluster} entityCluster The entity cluster to create visualizers for.
  472. * @param {DataSource} dataSource The data source to create visualizers for.
  473. * @returns {Visualizer[]} An array of visualizers used for visualization.
  474. *
  475. * @example
  476. * function createVisualizers(scene, entityCluster, dataSource) {
  477. * return [new Cesium.BillboardVisualizer(entityCluster, dataSource.entities)];
  478. * }
  479. */
  480. export default DataSourceDisplay;