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

GeometryVisualizer.js 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. import AssociativeArray from "../Core/AssociativeArray.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 ClassificationType from "../Scene/ClassificationType.js";
  7. import MaterialAppearance from "../Scene/MaterialAppearance.js";
  8. import PerInstanceColorAppearance from "../Scene/PerInstanceColorAppearance.js";
  9. import ShadowMode from "../Scene/ShadowMode.js";
  10. import BoundingSphereState from "./BoundingSphereState.js";
  11. import ColorMaterialProperty from "./ColorMaterialProperty.js";
  12. import DynamicGeometryBatch from "./DynamicGeometryBatch.js";
  13. import Entity from "./Entity.js";
  14. import GeometryUpdaterSet from "./GeometryUpdaterSet.js";
  15. import StaticGeometryColorBatch from "./StaticGeometryColorBatch.js";
  16. import StaticGeometryPerMaterialBatch from "./StaticGeometryPerMaterialBatch.js";
  17. import StaticGroundGeometryColorBatch from "./StaticGroundGeometryColorBatch.js";
  18. import StaticGroundGeometryPerMaterialBatch from "./StaticGroundGeometryPerMaterialBatch.js";
  19. import StaticOutlineGeometryBatch from "./StaticOutlineGeometryBatch.js";
  20. const emptyArray = [];
  21. /**
  22. * A general purpose visualizer for geometry represented by {@link Primitive} instances.
  23. * @alias GeometryVisualizer
  24. * @constructor
  25. *
  26. * @param {Scene} scene The scene the primitives will be rendered in.
  27. * @param {EntityCollection} entityCollection The entityCollection to visualize.
  28. * @param {PrimitiveCollection} [primitives=scene.primitives] A collection to add primitives related to the entities
  29. * @param {PrimitiveCollection} [groundPrimitives=scene.groundPrimitives] A collection to add ground primitives related to the entities
  30. */
  31. function GeometryVisualizer(
  32. scene,
  33. entityCollection,
  34. primitives,
  35. groundPrimitives,
  36. ) {
  37. //>>includeStart('debug', pragmas.debug);
  38. Check.defined("scene", scene);
  39. Check.defined("entityCollection", entityCollection);
  40. //>>includeEnd('debug');
  41. primitives = primitives ?? scene.primitives;
  42. groundPrimitives = groundPrimitives ?? scene.groundPrimitives;
  43. this._scene = scene;
  44. this._primitives = primitives;
  45. this._groundPrimitives = groundPrimitives;
  46. this._entityCollection = undefined;
  47. this._addedObjects = new AssociativeArray();
  48. this._removedObjects = new AssociativeArray();
  49. this._changedObjects = new AssociativeArray();
  50. const numberOfShadowModes = ShadowMode.NUMBER_OF_SHADOW_MODES;
  51. this._outlineBatches = new Array(numberOfShadowModes * 2);
  52. this._closedColorBatches = new Array(numberOfShadowModes * 2);
  53. this._closedMaterialBatches = new Array(numberOfShadowModes * 2);
  54. this._openColorBatches = new Array(numberOfShadowModes * 2);
  55. this._openMaterialBatches = new Array(numberOfShadowModes * 2);
  56. const supportsMaterialsforEntitiesOnTerrain =
  57. Entity.supportsMaterialsforEntitiesOnTerrain(scene);
  58. this._supportsMaterialsforEntitiesOnTerrain =
  59. supportsMaterialsforEntitiesOnTerrain;
  60. let i;
  61. for (i = 0; i < numberOfShadowModes; ++i) {
  62. this._outlineBatches[i] = new StaticOutlineGeometryBatch(
  63. primitives,
  64. scene,
  65. i,
  66. false,
  67. );
  68. this._outlineBatches[numberOfShadowModes + i] =
  69. new StaticOutlineGeometryBatch(primitives, scene, i, true);
  70. this._closedColorBatches[i] = new StaticGeometryColorBatch(
  71. primitives,
  72. PerInstanceColorAppearance,
  73. undefined,
  74. true,
  75. i,
  76. true,
  77. );
  78. this._closedColorBatches[numberOfShadowModes + i] =
  79. new StaticGeometryColorBatch(
  80. primitives,
  81. PerInstanceColorAppearance,
  82. undefined,
  83. true,
  84. i,
  85. false,
  86. );
  87. this._closedMaterialBatches[i] = new StaticGeometryPerMaterialBatch(
  88. primitives,
  89. MaterialAppearance,
  90. undefined,
  91. true,
  92. i,
  93. true,
  94. );
  95. this._closedMaterialBatches[numberOfShadowModes + i] =
  96. new StaticGeometryPerMaterialBatch(
  97. primitives,
  98. MaterialAppearance,
  99. undefined,
  100. true,
  101. i,
  102. false,
  103. );
  104. this._openColorBatches[i] = new StaticGeometryColorBatch(
  105. primitives,
  106. PerInstanceColorAppearance,
  107. undefined,
  108. false,
  109. i,
  110. true,
  111. );
  112. this._openColorBatches[numberOfShadowModes + i] =
  113. new StaticGeometryColorBatch(
  114. primitives,
  115. PerInstanceColorAppearance,
  116. undefined,
  117. false,
  118. i,
  119. false,
  120. );
  121. this._openMaterialBatches[i] = new StaticGeometryPerMaterialBatch(
  122. primitives,
  123. MaterialAppearance,
  124. undefined,
  125. false,
  126. i,
  127. true,
  128. );
  129. this._openMaterialBatches[numberOfShadowModes + i] =
  130. new StaticGeometryPerMaterialBatch(
  131. primitives,
  132. MaterialAppearance,
  133. undefined,
  134. false,
  135. i,
  136. false,
  137. );
  138. }
  139. const numberOfClassificationTypes =
  140. ClassificationType.NUMBER_OF_CLASSIFICATION_TYPES;
  141. const groundColorBatches = new Array(numberOfClassificationTypes);
  142. const groundMaterialBatches = [];
  143. if (supportsMaterialsforEntitiesOnTerrain) {
  144. for (i = 0; i < numberOfClassificationTypes; ++i) {
  145. groundMaterialBatches.push(
  146. new StaticGroundGeometryPerMaterialBatch(
  147. groundPrimitives,
  148. i,
  149. MaterialAppearance,
  150. ),
  151. );
  152. groundColorBatches[i] = new StaticGroundGeometryColorBatch(
  153. groundPrimitives,
  154. i,
  155. );
  156. }
  157. } else {
  158. for (i = 0; i < numberOfClassificationTypes; ++i) {
  159. groundColorBatches[i] = new StaticGroundGeometryColorBatch(
  160. groundPrimitives,
  161. i,
  162. );
  163. }
  164. }
  165. this._groundColorBatches = groundColorBatches;
  166. this._groundMaterialBatches = groundMaterialBatches;
  167. this._dynamicBatch = new DynamicGeometryBatch(primitives, groundPrimitives);
  168. this._batches = this._outlineBatches.concat(
  169. this._closedColorBatches,
  170. this._closedMaterialBatches,
  171. this._openColorBatches,
  172. this._openMaterialBatches,
  173. this._groundColorBatches,
  174. this._groundMaterialBatches,
  175. this._dynamicBatch,
  176. );
  177. this._subscriptions = new AssociativeArray();
  178. this._updaterSets = new AssociativeArray();
  179. this._entityCollection = entityCollection;
  180. entityCollection.collectionChanged.addEventListener(
  181. GeometryVisualizer.prototype._onCollectionChanged,
  182. this,
  183. );
  184. this._onCollectionChanged(
  185. entityCollection,
  186. entityCollection.values,
  187. emptyArray,
  188. );
  189. }
  190. /**
  191. * Add the provided updater to the default list of updaters if not already included
  192. * @private
  193. * @param {GeometryUpdater} updater
  194. */
  195. GeometryVisualizer.registerUpdater = function (updater) {
  196. GeometryUpdaterSet.registerUpdater(updater);
  197. };
  198. /**
  199. * Remove the provided updater from the default list of updaters if included
  200. * @private
  201. * @param {GeometryUpdater} updater
  202. */
  203. GeometryVisualizer.unregisterUpdater = function (updater) {
  204. GeometryUpdaterSet.unregisterUpdater(updater);
  205. };
  206. /**
  207. * Updates all of the primitives created by this visualizer to match their
  208. * Entity counterpart at the given time.
  209. *
  210. * @param {JulianDate} time The time to update to.
  211. * @returns {boolean} True if the visualizer successfully updated to the provided time,
  212. * false if the visualizer is waiting for asynchronous primitives to be created.
  213. */
  214. GeometryVisualizer.prototype.update = function (time) {
  215. //>>includeStart('debug', pragmas.debug);
  216. Check.defined("time", time);
  217. //>>includeEnd('debug');
  218. const addedObjects = this._addedObjects;
  219. const added = addedObjects.values;
  220. const removedObjects = this._removedObjects;
  221. const removed = removedObjects.values;
  222. const changedObjects = this._changedObjects;
  223. const changed = changedObjects.values;
  224. let i;
  225. let entity;
  226. let id;
  227. let updaterSet;
  228. const that = this;
  229. for (i = changed.length - 1; i > -1; i--) {
  230. entity = changed[i];
  231. id = entity.id;
  232. updaterSet = this._updaterSets.get(id);
  233. //If in a single update, an entity gets removed and a new instance
  234. //re-added with the same id, the updater no longer tracks the
  235. //correct entity, we need to both remove the old one and
  236. //add the new one, which is done by pushing the entity
  237. //onto the removed/added lists.
  238. if (updaterSet.entity === entity) {
  239. updaterSet.forEach(function (updater) {
  240. that._removeUpdater(updater);
  241. that._insertUpdaterIntoBatch(time, updater);
  242. });
  243. } else {
  244. removed.push(entity);
  245. added.push(entity);
  246. }
  247. }
  248. for (i = removed.length - 1; i > -1; i--) {
  249. entity = removed[i];
  250. id = entity.id;
  251. updaterSet = this._updaterSets.get(id);
  252. updaterSet.forEach(this._removeUpdater.bind(this));
  253. updaterSet.destroy();
  254. this._updaterSets.remove(id);
  255. this._subscriptions.get(id)();
  256. this._subscriptions.remove(id);
  257. }
  258. for (i = added.length - 1; i > -1; i--) {
  259. entity = added[i];
  260. id = entity.id;
  261. updaterSet = new GeometryUpdaterSet(entity, this._scene);
  262. this._updaterSets.set(id, updaterSet);
  263. updaterSet.forEach(function (updater) {
  264. that._insertUpdaterIntoBatch(time, updater);
  265. });
  266. this._subscriptions.set(
  267. id,
  268. updaterSet.geometryChanged.addEventListener(
  269. GeometryVisualizer._onGeometryChanged,
  270. this,
  271. ),
  272. );
  273. }
  274. addedObjects.removeAll();
  275. removedObjects.removeAll();
  276. changedObjects.removeAll();
  277. let isUpdated = true;
  278. const batches = this._batches;
  279. const length = batches.length;
  280. for (i = 0; i < length; i++) {
  281. isUpdated = batches[i].update(time) && isUpdated;
  282. }
  283. return isUpdated;
  284. };
  285. const getBoundingSphereArrayScratch = [];
  286. const getBoundingSphereBoundingSphereScratch = new BoundingSphere();
  287. /**
  288. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  289. * The bounding sphere is in the fixed frame of the scene's globe.
  290. *
  291. * @param {Entity} entity The entity whose bounding sphere to compute.
  292. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  293. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  294. * BoundingSphereState.PENDING if the result is still being computed, or
  295. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  296. * @private
  297. */
  298. GeometryVisualizer.prototype.getBoundingSphere = function (entity, result) {
  299. //>>includeStart('debug', pragmas.debug);
  300. Check.defined("entity", entity);
  301. Check.defined("result", result);
  302. //>>includeEnd('debug');
  303. const boundingSpheres = getBoundingSphereArrayScratch;
  304. const tmp = getBoundingSphereBoundingSphereScratch;
  305. let count = 0;
  306. let state = BoundingSphereState.DONE;
  307. const batches = this._batches;
  308. const batchesLength = batches.length;
  309. const id = entity.id;
  310. const updaters = this._updaterSets.get(id).updaters;
  311. for (let j = 0; j < updaters.length; j++) {
  312. const updater = updaters[j];
  313. for (let i = 0; i < batchesLength; i++) {
  314. state = batches[i].getBoundingSphere(updater, tmp);
  315. if (state === BoundingSphereState.PENDING) {
  316. return BoundingSphereState.PENDING;
  317. } else if (state === BoundingSphereState.DONE) {
  318. boundingSpheres[count] = BoundingSphere.clone(
  319. tmp,
  320. boundingSpheres[count],
  321. );
  322. count++;
  323. }
  324. }
  325. }
  326. if (count === 0) {
  327. return BoundingSphereState.FAILED;
  328. }
  329. boundingSpheres.length = count;
  330. BoundingSphere.fromBoundingSpheres(boundingSpheres, result);
  331. return BoundingSphereState.DONE;
  332. };
  333. /**
  334. * Returns true if this object was destroyed; otherwise, false.
  335. *
  336. * @returns {boolean} True if this object was destroyed; otherwise, false.
  337. */
  338. GeometryVisualizer.prototype.isDestroyed = function () {
  339. return false;
  340. };
  341. /**
  342. * Removes and destroys all primitives created by this instance.
  343. */
  344. GeometryVisualizer.prototype.destroy = function () {
  345. this._entityCollection.collectionChanged.removeEventListener(
  346. GeometryVisualizer.prototype._onCollectionChanged,
  347. this,
  348. );
  349. this._addedObjects.removeAll();
  350. this._removedObjects.removeAll();
  351. let i;
  352. const batches = this._batches;
  353. let length = batches.length;
  354. for (i = 0; i < length; i++) {
  355. batches[i].removeAllPrimitives();
  356. }
  357. const subscriptions = this._subscriptions.values;
  358. length = subscriptions.length;
  359. for (i = 0; i < length; i++) {
  360. subscriptions[i]();
  361. }
  362. this._subscriptions.removeAll();
  363. const updaterSets = this._updaterSets.values;
  364. length = updaterSets.length;
  365. for (i = 0; i < length; i++) {
  366. updaterSets[i].destroy();
  367. }
  368. this._updaterSets.removeAll();
  369. return destroyObject(this);
  370. };
  371. /**
  372. * @private
  373. */
  374. GeometryVisualizer.prototype._removeUpdater = function (updater) {
  375. //We don't keep track of which batch an updater is in, so just remove it from all of them.
  376. const batches = this._batches;
  377. const length = batches.length;
  378. for (let i = 0; i < length; i++) {
  379. batches[i].remove(updater);
  380. }
  381. };
  382. /**
  383. * @private
  384. */
  385. GeometryVisualizer.prototype._insertUpdaterIntoBatch = function (
  386. time,
  387. updater,
  388. ) {
  389. if (updater.isDynamic) {
  390. this._dynamicBatch.add(time, updater);
  391. return;
  392. }
  393. let shadows;
  394. if (updater.outlineEnabled || updater.fillEnabled) {
  395. shadows = updater.shadowsProperty.getValue(time);
  396. }
  397. const numberOfShadowModes = ShadowMode.NUMBER_OF_SHADOW_MODES;
  398. if (updater.outlineEnabled) {
  399. if (defined(updater.terrainOffsetProperty)) {
  400. this._outlineBatches[numberOfShadowModes + shadows].add(time, updater);
  401. } else {
  402. this._outlineBatches[shadows].add(time, updater);
  403. }
  404. }
  405. if (updater.fillEnabled) {
  406. if (updater.onTerrain) {
  407. const classificationType =
  408. updater.classificationTypeProperty.getValue(time);
  409. if (updater.fillMaterialProperty instanceof ColorMaterialProperty) {
  410. this._groundColorBatches[classificationType].add(time, updater);
  411. } else {
  412. // If unsupported, updater will not be on terrain.
  413. this._groundMaterialBatches[classificationType].add(time, updater);
  414. }
  415. } else if (updater.isClosed) {
  416. if (updater.fillMaterialProperty instanceof ColorMaterialProperty) {
  417. if (defined(updater.terrainOffsetProperty)) {
  418. this._closedColorBatches[numberOfShadowModes + shadows].add(
  419. time,
  420. updater,
  421. );
  422. } else {
  423. this._closedColorBatches[shadows].add(time, updater);
  424. }
  425. } else if (defined(updater.terrainOffsetProperty)) {
  426. this._closedMaterialBatches[numberOfShadowModes + shadows].add(
  427. time,
  428. updater,
  429. );
  430. } else {
  431. this._closedMaterialBatches[shadows].add(time, updater);
  432. }
  433. } else if (updater.fillMaterialProperty instanceof ColorMaterialProperty) {
  434. if (defined(updater.terrainOffsetProperty)) {
  435. this._openColorBatches[numberOfShadowModes + shadows].add(
  436. time,
  437. updater,
  438. );
  439. } else {
  440. this._openColorBatches[shadows].add(time, updater);
  441. }
  442. } else if (defined(updater.terrainOffsetProperty)) {
  443. this._openMaterialBatches[numberOfShadowModes + shadows].add(
  444. time,
  445. updater,
  446. );
  447. } else {
  448. this._openMaterialBatches[shadows].add(time, updater);
  449. }
  450. }
  451. };
  452. /**
  453. * @private
  454. */
  455. GeometryVisualizer._onGeometryChanged = function (updater) {
  456. const removedObjects = this._removedObjects;
  457. const changedObjects = this._changedObjects;
  458. const entity = updater.entity;
  459. const id = entity.id;
  460. if (!defined(removedObjects.get(id)) && !defined(changedObjects.get(id))) {
  461. changedObjects.set(id, entity);
  462. }
  463. };
  464. /**
  465. * @private
  466. */
  467. GeometryVisualizer.prototype._onCollectionChanged = function (
  468. entityCollection,
  469. added,
  470. removed,
  471. ) {
  472. const addedObjects = this._addedObjects;
  473. const removedObjects = this._removedObjects;
  474. const changedObjects = this._changedObjects;
  475. let i;
  476. let id;
  477. let entity;
  478. for (i = removed.length - 1; i > -1; i--) {
  479. entity = removed[i];
  480. id = entity.id;
  481. if (!addedObjects.remove(id)) {
  482. removedObjects.set(id, entity);
  483. changedObjects.remove(id);
  484. }
  485. }
  486. for (i = added.length - 1; i > -1; i--) {
  487. entity = added[i];
  488. id = entity.id;
  489. if (removedObjects.remove(id)) {
  490. changedObjects.set(id, entity);
  491. } else {
  492. addedObjects.set(id, entity);
  493. }
  494. }
  495. };
  496. export default GeometryVisualizer;