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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. import AssociativeArray from "../Core/AssociativeArray.js";
  2. import Cartesian3 from "../Core/Cartesian3.js";
  3. import Color from "../Core/Color.js";
  4. import defined from "../Core/defined.js";
  5. import destroyObject from "../Core/destroyObject.js";
  6. import DeveloperError from "../Core/DeveloperError.js";
  7. import DistanceDisplayCondition from "../Core/DistanceDisplayCondition.js";
  8. import NearFarScalar from "../Core/NearFarScalar.js";
  9. import createBillboardPointCallback from "../Scene/createBillboardPointCallback.js";
  10. import HeightReference from "../Scene/HeightReference.js";
  11. import BoundingSphereState from "./BoundingSphereState.js";
  12. import Property from "./Property.js";
  13. import SplitDirection from "../Scene/SplitDirection.js";
  14. const defaultColor = Color.WHITE;
  15. const defaultOutlineColor = Color.BLACK;
  16. const defaultOutlineWidth = 0.0;
  17. const defaultPixelSize = 1.0;
  18. const defaultDisableDepthTestDistance = 0.0;
  19. const defaultSplitDirection = SplitDirection.NONE;
  20. const colorScratch = new Color();
  21. const positionScratch = new Cartesian3();
  22. const outlineColorScratch = new Color();
  23. const scaleByDistanceScratch = new NearFarScalar();
  24. const translucencyByDistanceScratch = new NearFarScalar();
  25. const distanceDisplayConditionScratch = new DistanceDisplayCondition();
  26. function EntityData(entity) {
  27. this.entity = entity;
  28. this.pointPrimitive = undefined;
  29. this.billboard = undefined;
  30. this.color = undefined;
  31. this.outlineColor = undefined;
  32. this.pixelSize = undefined;
  33. this.outlineWidth = undefined;
  34. }
  35. /**
  36. * A {@link Visualizer} which maps {@link Entity#point} to a {@link PointPrimitive}.
  37. * @alias PointVisualizer
  38. * @constructor
  39. *
  40. * @param {EntityCluster} entityCluster The entity cluster to manage the collection of billboards and optionally cluster with other entities.
  41. * @param {EntityCollection} entityCollection The entityCollection to visualize.
  42. */
  43. function PointVisualizer(entityCluster, entityCollection) {
  44. //>>includeStart('debug', pragmas.debug);
  45. if (!defined(entityCluster)) {
  46. throw new DeveloperError("entityCluster is required.");
  47. }
  48. if (!defined(entityCollection)) {
  49. throw new DeveloperError("entityCollection is required.");
  50. }
  51. //>>includeEnd('debug');
  52. entityCollection.collectionChanged.addEventListener(
  53. PointVisualizer.prototype._onCollectionChanged,
  54. this,
  55. );
  56. this._cluster = entityCluster;
  57. this._entityCollection = entityCollection;
  58. this._items = new AssociativeArray();
  59. this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
  60. }
  61. /**
  62. * Updates the primitives created by this visualizer to match their
  63. * Entity counterpart at the given time.
  64. *
  65. * @param {JulianDate} time The time to update to.
  66. * @returns {boolean} This function always returns true.
  67. */
  68. PointVisualizer.prototype.update = function (time) {
  69. //>>includeStart('debug', pragmas.debug);
  70. if (!defined(time)) {
  71. throw new DeveloperError("time is required.");
  72. }
  73. //>>includeEnd('debug');
  74. const items = this._items.values;
  75. const cluster = this._cluster;
  76. for (let i = 0, len = items.length; i < len; i++) {
  77. const item = items[i];
  78. const entity = item.entity;
  79. const pointGraphics = entity._point;
  80. let pointPrimitive = item.pointPrimitive;
  81. let billboard = item.billboard;
  82. const heightReference = Property.getValueOrDefault(
  83. pointGraphics._heightReference,
  84. time,
  85. HeightReference.NONE,
  86. );
  87. let show =
  88. entity.isShowing &&
  89. entity.isAvailable(time) &&
  90. Property.getValueOrDefault(pointGraphics._show, time, true);
  91. let position;
  92. if (show) {
  93. position = Property.getValueOrUndefined(
  94. entity._position,
  95. time,
  96. positionScratch,
  97. );
  98. show = defined(position);
  99. }
  100. if (!show) {
  101. returnPrimitive(item, entity, cluster);
  102. continue;
  103. }
  104. if (!Property.isConstant(entity._position)) {
  105. cluster._clusterDirty = true;
  106. }
  107. let needsRedraw = false;
  108. let updateClamping = false;
  109. if (heightReference !== HeightReference.NONE && !defined(billboard)) {
  110. if (defined(pointPrimitive)) {
  111. returnPrimitive(item, entity, cluster);
  112. pointPrimitive = undefined;
  113. }
  114. billboard = cluster.getBillboard(entity);
  115. billboard.id = entity;
  116. billboard.image = undefined;
  117. item.billboard = billboard;
  118. needsRedraw = true;
  119. // If this new billboard happens to have a position and height reference that match our new values,
  120. // billboard._updateClamping will not be called automatically. That's a problem because the clamped
  121. // height may be based on different terrain than is now loaded. So we'll manually call
  122. // _updateClamping below.
  123. updateClamping =
  124. Cartesian3.equals(billboard.position, position) &&
  125. billboard.heightReference === heightReference;
  126. } else if (
  127. heightReference === HeightReference.NONE &&
  128. !defined(pointPrimitive)
  129. ) {
  130. if (defined(billboard)) {
  131. returnPrimitive(item, entity, cluster);
  132. billboard = undefined;
  133. }
  134. pointPrimitive = cluster.getPoint(entity);
  135. pointPrimitive.id = entity;
  136. item.pointPrimitive = pointPrimitive;
  137. }
  138. if (defined(pointPrimitive)) {
  139. pointPrimitive.show = true;
  140. pointPrimitive.position = position;
  141. pointPrimitive.scaleByDistance = Property.getValueOrUndefined(
  142. pointGraphics._scaleByDistance,
  143. time,
  144. scaleByDistanceScratch,
  145. );
  146. pointPrimitive.translucencyByDistance = Property.getValueOrUndefined(
  147. pointGraphics._translucencyByDistance,
  148. time,
  149. translucencyByDistanceScratch,
  150. );
  151. pointPrimitive.color = Property.getValueOrDefault(
  152. pointGraphics._color,
  153. time,
  154. defaultColor,
  155. colorScratch,
  156. );
  157. pointPrimitive.outlineColor = Property.getValueOrDefault(
  158. pointGraphics._outlineColor,
  159. time,
  160. defaultOutlineColor,
  161. outlineColorScratch,
  162. );
  163. pointPrimitive.outlineWidth = Property.getValueOrDefault(
  164. pointGraphics._outlineWidth,
  165. time,
  166. defaultOutlineWidth,
  167. );
  168. pointPrimitive.pixelSize = Property.getValueOrDefault(
  169. pointGraphics._pixelSize,
  170. time,
  171. defaultPixelSize,
  172. );
  173. pointPrimitive.distanceDisplayCondition = Property.getValueOrUndefined(
  174. pointGraphics._distanceDisplayCondition,
  175. time,
  176. distanceDisplayConditionScratch,
  177. );
  178. pointPrimitive.disableDepthTestDistance = Property.getValueOrDefault(
  179. pointGraphics._disableDepthTestDistance,
  180. time,
  181. defaultDisableDepthTestDistance,
  182. );
  183. pointPrimitive.splitDirection = Property.getValueOrDefault(
  184. pointGraphics._splitDirection,
  185. time,
  186. defaultSplitDirection,
  187. );
  188. } else if (defined(billboard)) {
  189. billboard.show = true;
  190. billboard.position = position;
  191. billboard.scaleByDistance = Property.getValueOrUndefined(
  192. pointGraphics._scaleByDistance,
  193. time,
  194. scaleByDistanceScratch,
  195. );
  196. billboard.translucencyByDistance = Property.getValueOrUndefined(
  197. pointGraphics._translucencyByDistance,
  198. time,
  199. translucencyByDistanceScratch,
  200. );
  201. billboard.distanceDisplayCondition = Property.getValueOrUndefined(
  202. pointGraphics._distanceDisplayCondition,
  203. time,
  204. distanceDisplayConditionScratch,
  205. );
  206. billboard.disableDepthTestDistance = Property.getValueOrDefault(
  207. pointGraphics._disableDepthTestDistance,
  208. time,
  209. defaultDisableDepthTestDistance,
  210. );
  211. billboard.splitDirection = Property.getValueOrDefault(
  212. pointGraphics._splitDirection,
  213. time,
  214. defaultSplitDirection,
  215. );
  216. billboard.heightReference = heightReference;
  217. const newColor = Property.getValueOrDefault(
  218. pointGraphics._color,
  219. time,
  220. defaultColor,
  221. colorScratch,
  222. );
  223. const newOutlineColor = Property.getValueOrDefault(
  224. pointGraphics._outlineColor,
  225. time,
  226. defaultOutlineColor,
  227. outlineColorScratch,
  228. );
  229. const newOutlineWidth = Math.round(
  230. Property.getValueOrDefault(
  231. pointGraphics._outlineWidth,
  232. time,
  233. defaultOutlineWidth,
  234. ),
  235. );
  236. let newPixelSize = Math.max(
  237. 1,
  238. Math.round(
  239. Property.getValueOrDefault(
  240. pointGraphics._pixelSize,
  241. time,
  242. defaultPixelSize,
  243. ),
  244. ),
  245. );
  246. if (newOutlineWidth > 0) {
  247. billboard.scale = 1.0;
  248. needsRedraw =
  249. needsRedraw || //
  250. newOutlineWidth !== item.outlineWidth || //
  251. newPixelSize !== item.pixelSize || //
  252. !Color.equals(newColor, item.color) || //
  253. !Color.equals(newOutlineColor, item.outlineColor);
  254. } else {
  255. billboard.scale = newPixelSize / 50.0;
  256. newPixelSize = 50.0;
  257. needsRedraw =
  258. needsRedraw || //
  259. newOutlineWidth !== item.outlineWidth || //
  260. !Color.equals(newColor, item.color) || //
  261. !Color.equals(newOutlineColor, item.outlineColor);
  262. }
  263. if (needsRedraw) {
  264. item.color = Color.clone(newColor, item.color);
  265. item.outlineColor = Color.clone(newOutlineColor, item.outlineColor);
  266. item.pixelSize = newPixelSize;
  267. item.outlineWidth = newOutlineWidth;
  268. const centerAlpha = newColor.alpha;
  269. const cssColor = newColor.toCssColorString();
  270. const cssOutlineColor = newOutlineColor.toCssColorString();
  271. const textureId = JSON.stringify([
  272. cssColor,
  273. newPixelSize,
  274. cssOutlineColor,
  275. newOutlineWidth,
  276. ]);
  277. billboard.setImage(
  278. textureId,
  279. createBillboardPointCallback(
  280. centerAlpha,
  281. cssColor,
  282. cssOutlineColor,
  283. newOutlineWidth,
  284. newPixelSize,
  285. ),
  286. );
  287. }
  288. if (updateClamping) {
  289. billboard._updateClamping();
  290. }
  291. }
  292. }
  293. return true;
  294. };
  295. /**
  296. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  297. * The bounding sphere is in the fixed frame of the scene's globe.
  298. *
  299. * @param {Entity} entity The entity whose bounding sphere to compute.
  300. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  301. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  302. * BoundingSphereState.PENDING if the result is still being computed, or
  303. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  304. * @private
  305. */
  306. PointVisualizer.prototype.getBoundingSphere = function (entity, result) {
  307. //>>includeStart('debug', pragmas.debug);
  308. if (!defined(entity)) {
  309. throw new DeveloperError("entity is required.");
  310. }
  311. if (!defined(result)) {
  312. throw new DeveloperError("result is required.");
  313. }
  314. //>>includeEnd('debug');
  315. const item = this._items.get(entity.id);
  316. if (
  317. !defined(item) ||
  318. !(defined(item.pointPrimitive) || defined(item.billboard))
  319. ) {
  320. return BoundingSphereState.FAILED;
  321. }
  322. if (defined(item.pointPrimitive)) {
  323. result.center = Cartesian3.clone(
  324. item.pointPrimitive.position,
  325. result.center,
  326. );
  327. } else {
  328. const billboard = item.billboard;
  329. if (!defined(billboard._clampedPosition)) {
  330. return BoundingSphereState.PENDING;
  331. }
  332. result.center = Cartesian3.clone(billboard._clampedPosition, result.center);
  333. }
  334. result.radius = 0;
  335. return BoundingSphereState.DONE;
  336. };
  337. /**
  338. * Returns true if this object was destroyed; otherwise, false.
  339. *
  340. * @returns {boolean} True if this object was destroyed; otherwise, false.
  341. */
  342. PointVisualizer.prototype.isDestroyed = function () {
  343. return false;
  344. };
  345. /**
  346. * Removes and destroys all primitives created by this instance.
  347. */
  348. PointVisualizer.prototype.destroy = function () {
  349. this._entityCollection.collectionChanged.removeEventListener(
  350. PointVisualizer.prototype._onCollectionChanged,
  351. this,
  352. );
  353. const entities = this._entityCollection.values;
  354. for (let i = 0; i < entities.length; i++) {
  355. this._cluster.removePoint(entities[i]);
  356. }
  357. return destroyObject(this);
  358. };
  359. PointVisualizer.prototype._onCollectionChanged = function (
  360. entityCollection,
  361. added,
  362. removed,
  363. changed,
  364. ) {
  365. let i;
  366. let entity;
  367. const items = this._items;
  368. const cluster = this._cluster;
  369. for (i = added.length - 1; i > -1; i--) {
  370. entity = added[i];
  371. if (defined(entity._point) && defined(entity._position)) {
  372. items.set(entity.id, new EntityData(entity));
  373. }
  374. }
  375. for (i = changed.length - 1; i > -1; i--) {
  376. entity = changed[i];
  377. if (defined(entity._point) && defined(entity._position)) {
  378. if (!items.contains(entity.id)) {
  379. items.set(entity.id, new EntityData(entity));
  380. }
  381. } else {
  382. returnPrimitive(items.get(entity.id), entity, cluster);
  383. items.remove(entity.id);
  384. }
  385. }
  386. for (i = removed.length - 1; i > -1; i--) {
  387. entity = removed[i];
  388. returnPrimitive(items.get(entity.id), entity, cluster);
  389. items.remove(entity.id);
  390. }
  391. };
  392. function returnPrimitive(item, entity, cluster) {
  393. if (defined(item)) {
  394. const pointPrimitive = item.pointPrimitive;
  395. if (defined(pointPrimitive)) {
  396. item.pointPrimitive = undefined;
  397. cluster.removePoint(entity);
  398. return;
  399. }
  400. const billboard = item.billboard;
  401. if (defined(billboard)) {
  402. item.billboard = undefined;
  403. cluster.removeBillboard(entity);
  404. }
  405. }
  406. }
  407. export default PointVisualizer;