PolylineVisualizer.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. import AssociativeArray from "../Core/AssociativeArray.js";
  2. import BoundingSphere from "../Core/BoundingSphere.js";
  3. import Check from "../Core/Check.js";
  4. import defaultValue from "../Core/defaultValue.js";
  5. import defined from "../Core/defined.js";
  6. import destroyObject from "../Core/destroyObject.js";
  7. import ClassificationType from "../Scene/ClassificationType.js";
  8. import PolylineColorAppearance from "../Scene/PolylineColorAppearance.js";
  9. import PolylineMaterialAppearance from "../Scene/PolylineMaterialAppearance.js";
  10. import ShadowMode from "../Scene/ShadowMode.js";
  11. import BoundingSphereState from "./BoundingSphereState.js";
  12. import ColorMaterialProperty from "./ColorMaterialProperty.js";
  13. import DynamicGeometryBatch from "./DynamicGeometryBatch.js";
  14. import PolylineGeometryUpdater from "./PolylineGeometryUpdater.js";
  15. import StaticGeometryColorBatch from "./StaticGeometryColorBatch.js";
  16. import StaticGeometryPerMaterialBatch from "./StaticGeometryPerMaterialBatch.js";
  17. import StaticGroundPolylinePerMaterialBatch from "./StaticGroundPolylinePerMaterialBatch.js";
  18. var emptyArray = [];
  19. function removeUpdater(that, updater) {
  20. //We don't keep track of which batch an updater is in, so just remove it from all of them.
  21. var batches = that._batches;
  22. var length = batches.length;
  23. for (var i = 0; i < length; i++) {
  24. batches[i].remove(updater);
  25. }
  26. }
  27. function insertUpdaterIntoBatch(that, time, updater) {
  28. if (updater.isDynamic) {
  29. that._dynamicBatch.add(time, updater);
  30. return;
  31. }
  32. if (updater.clampToGround && updater.fillEnabled) {
  33. // Also checks for support
  34. var classificationType = updater.classificationTypeProperty.getValue(time);
  35. that._groundBatches[classificationType].add(time, updater);
  36. return;
  37. }
  38. var shadows;
  39. if (updater.fillEnabled) {
  40. shadows = updater.shadowsProperty.getValue(time);
  41. }
  42. var multiplier = 0;
  43. if (defined(updater.depthFailMaterialProperty)) {
  44. multiplier =
  45. updater.depthFailMaterialProperty instanceof ColorMaterialProperty
  46. ? 1
  47. : 2;
  48. }
  49. var index;
  50. if (defined(shadows)) {
  51. index = shadows + multiplier * ShadowMode.NUMBER_OF_SHADOW_MODES;
  52. }
  53. if (updater.fillEnabled) {
  54. if (updater.fillMaterialProperty instanceof ColorMaterialProperty) {
  55. that._colorBatches[index].add(time, updater);
  56. } else {
  57. that._materialBatches[index].add(time, updater);
  58. }
  59. }
  60. }
  61. /**
  62. * A visualizer for polylines represented by {@link Primitive} instances.
  63. * @alias PolylineVisualizer
  64. * @constructor
  65. *
  66. * @param {Scene} scene The scene the primitives will be rendered in.
  67. * @param {EntityCollection} entityCollection The entityCollection to visualize.
  68. * @param {PrimitiveCollection} [primitives=scene.primitives] A collection to add primitives related to the entities
  69. * @param {PrimitiveCollection} [groundPrimitives=scene.groundPrimitives] A collection to add ground primitives related to the entities
  70. */
  71. function PolylineVisualizer(
  72. scene,
  73. entityCollection,
  74. primitives,
  75. groundPrimitives
  76. ) {
  77. //>>includeStart('debug', pragmas.debug);
  78. Check.defined("scene", scene);
  79. Check.defined("entityCollection", entityCollection);
  80. //>>includeEnd('debug');
  81. groundPrimitives = defaultValue(groundPrimitives, scene.groundPrimitives);
  82. primitives = defaultValue(primitives, scene.primitives);
  83. this._scene = scene;
  84. this._primitives = primitives;
  85. this._entityCollection = undefined;
  86. this._addedObjects = new AssociativeArray();
  87. this._removedObjects = new AssociativeArray();
  88. this._changedObjects = new AssociativeArray();
  89. var i;
  90. var numberOfShadowModes = ShadowMode.NUMBER_OF_SHADOW_MODES;
  91. this._colorBatches = new Array(numberOfShadowModes * 3);
  92. this._materialBatches = new Array(numberOfShadowModes * 3);
  93. for (i = 0; i < numberOfShadowModes; ++i) {
  94. this._colorBatches[i] = new StaticGeometryColorBatch(
  95. primitives,
  96. PolylineColorAppearance,
  97. undefined,
  98. false,
  99. i
  100. ); // no depth fail appearance
  101. this._materialBatches[i] = new StaticGeometryPerMaterialBatch(
  102. primitives,
  103. PolylineMaterialAppearance,
  104. undefined,
  105. false,
  106. i
  107. );
  108. this._colorBatches[i + numberOfShadowModes] = new StaticGeometryColorBatch(
  109. primitives,
  110. PolylineColorAppearance,
  111. PolylineColorAppearance,
  112. false,
  113. i
  114. ); //depth fail appearance variations
  115. this._materialBatches[
  116. i + numberOfShadowModes
  117. ] = new StaticGeometryPerMaterialBatch(
  118. primitives,
  119. PolylineMaterialAppearance,
  120. PolylineColorAppearance,
  121. false,
  122. i
  123. );
  124. this._colorBatches[
  125. i + numberOfShadowModes * 2
  126. ] = new StaticGeometryColorBatch(
  127. primitives,
  128. PolylineColorAppearance,
  129. PolylineMaterialAppearance,
  130. false,
  131. i
  132. );
  133. this._materialBatches[
  134. i + numberOfShadowModes * 2
  135. ] = new StaticGeometryPerMaterialBatch(
  136. primitives,
  137. PolylineMaterialAppearance,
  138. PolylineMaterialAppearance,
  139. false,
  140. i
  141. );
  142. }
  143. this._dynamicBatch = new DynamicGeometryBatch(primitives, groundPrimitives);
  144. var numberOfClassificationTypes =
  145. ClassificationType.NUMBER_OF_CLASSIFICATION_TYPES;
  146. this._groundBatches = new Array(numberOfClassificationTypes);
  147. for (i = 0; i < numberOfClassificationTypes; ++i) {
  148. this._groundBatches[i] = new StaticGroundPolylinePerMaterialBatch(
  149. groundPrimitives,
  150. i
  151. );
  152. }
  153. this._batches = this._colorBatches.concat(
  154. this._materialBatches,
  155. this._dynamicBatch,
  156. this._groundBatches
  157. );
  158. this._subscriptions = new AssociativeArray();
  159. this._updaters = new AssociativeArray();
  160. this._entityCollection = entityCollection;
  161. entityCollection.collectionChanged.addEventListener(
  162. PolylineVisualizer.prototype._onCollectionChanged,
  163. this
  164. );
  165. this._onCollectionChanged(
  166. entityCollection,
  167. entityCollection.values,
  168. emptyArray
  169. );
  170. }
  171. /**
  172. * Updates all of the primitives created by this visualizer to match their
  173. * Entity counterpart at the given time.
  174. *
  175. * @param {JulianDate} time The time to update to.
  176. * @returns {Boolean} True if the visualizer successfully updated to the provided time,
  177. * false if the visualizer is waiting for asynchronous primitives to be created.
  178. */
  179. PolylineVisualizer.prototype.update = function (time) {
  180. //>>includeStart('debug', pragmas.debug);
  181. Check.defined("time", time);
  182. //>>includeEnd('debug');
  183. var addedObjects = this._addedObjects;
  184. var added = addedObjects.values;
  185. var removedObjects = this._removedObjects;
  186. var removed = removedObjects.values;
  187. var changedObjects = this._changedObjects;
  188. var changed = changedObjects.values;
  189. var i;
  190. var entity;
  191. var id;
  192. var updater;
  193. for (i = changed.length - 1; i > -1; i--) {
  194. entity = changed[i];
  195. id = entity.id;
  196. updater = this._updaters.get(id);
  197. //If in a single update, an entity gets removed and a new instance
  198. //re-added with the same id, the updater no longer tracks the
  199. //correct entity, we need to both remove the old one and
  200. //add the new one, which is done by pushing the entity
  201. //onto the removed/added lists.
  202. if (updater.entity === entity) {
  203. removeUpdater(this, updater);
  204. insertUpdaterIntoBatch(this, time, updater);
  205. } else {
  206. removed.push(entity);
  207. added.push(entity);
  208. }
  209. }
  210. for (i = removed.length - 1; i > -1; i--) {
  211. entity = removed[i];
  212. id = entity.id;
  213. updater = this._updaters.get(id);
  214. removeUpdater(this, updater);
  215. updater.destroy();
  216. this._updaters.remove(id);
  217. this._subscriptions.get(id)();
  218. this._subscriptions.remove(id);
  219. }
  220. for (i = added.length - 1; i > -1; i--) {
  221. entity = added[i];
  222. id = entity.id;
  223. updater = new PolylineGeometryUpdater(entity, this._scene);
  224. this._updaters.set(id, updater);
  225. insertUpdaterIntoBatch(this, time, updater);
  226. this._subscriptions.set(
  227. id,
  228. updater.geometryChanged.addEventListener(
  229. PolylineVisualizer._onGeometryChanged,
  230. this
  231. )
  232. );
  233. }
  234. addedObjects.removeAll();
  235. removedObjects.removeAll();
  236. changedObjects.removeAll();
  237. var isUpdated = true;
  238. var batches = this._batches;
  239. var length = batches.length;
  240. for (i = 0; i < length; i++) {
  241. isUpdated = batches[i].update(time) && isUpdated;
  242. }
  243. return isUpdated;
  244. };
  245. var getBoundingSphereArrayScratch = [];
  246. var getBoundingSphereBoundingSphereScratch = new BoundingSphere();
  247. /**
  248. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  249. * The bounding sphere is in the fixed frame of the scene's globe.
  250. *
  251. * @param {Entity} entity The entity whose bounding sphere to compute.
  252. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  253. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  254. * BoundingSphereState.PENDING if the result is still being computed, or
  255. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  256. * @private
  257. */
  258. PolylineVisualizer.prototype.getBoundingSphere = function (entity, result) {
  259. //>>includeStart('debug', pragmas.debug);
  260. Check.defined("entity", entity);
  261. Check.defined("result", result);
  262. //>>includeEnd('debug');
  263. var boundingSpheres = getBoundingSphereArrayScratch;
  264. var tmp = getBoundingSphereBoundingSphereScratch;
  265. var count = 0;
  266. var state = BoundingSphereState.DONE;
  267. var batches = this._batches;
  268. var batchesLength = batches.length;
  269. var updater = this._updaters.get(entity.id);
  270. for (var i = 0; i < batchesLength; i++) {
  271. state = batches[i].getBoundingSphere(updater, tmp);
  272. if (state === BoundingSphereState.PENDING) {
  273. return BoundingSphereState.PENDING;
  274. } else if (state === BoundingSphereState.DONE) {
  275. boundingSpheres[count] = BoundingSphere.clone(
  276. tmp,
  277. boundingSpheres[count]
  278. );
  279. count++;
  280. }
  281. }
  282. if (count === 0) {
  283. return BoundingSphereState.FAILED;
  284. }
  285. boundingSpheres.length = count;
  286. BoundingSphere.fromBoundingSpheres(boundingSpheres, result);
  287. return BoundingSphereState.DONE;
  288. };
  289. /**
  290. * Returns true if this object was destroyed; otherwise, false.
  291. *
  292. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  293. */
  294. PolylineVisualizer.prototype.isDestroyed = function () {
  295. return false;
  296. };
  297. /**
  298. * Removes and destroys all primitives created by this instance.
  299. */
  300. PolylineVisualizer.prototype.destroy = function () {
  301. this._entityCollection.collectionChanged.removeEventListener(
  302. PolylineVisualizer.prototype._onCollectionChanged,
  303. this
  304. );
  305. this._addedObjects.removeAll();
  306. this._removedObjects.removeAll();
  307. var i;
  308. var batches = this._batches;
  309. var length = batches.length;
  310. for (i = 0; i < length; i++) {
  311. batches[i].removeAllPrimitives();
  312. }
  313. var subscriptions = this._subscriptions.values;
  314. length = subscriptions.length;
  315. for (i = 0; i < length; i++) {
  316. subscriptions[i]();
  317. }
  318. this._subscriptions.removeAll();
  319. return destroyObject(this);
  320. };
  321. /**
  322. * @private
  323. */
  324. PolylineVisualizer._onGeometryChanged = function (updater) {
  325. var removedObjects = this._removedObjects;
  326. var changedObjects = this._changedObjects;
  327. var entity = updater.entity;
  328. var id = entity.id;
  329. if (!defined(removedObjects.get(id)) && !defined(changedObjects.get(id))) {
  330. changedObjects.set(id, entity);
  331. }
  332. };
  333. /**
  334. * @private
  335. */
  336. PolylineVisualizer.prototype._onCollectionChanged = function (
  337. entityCollection,
  338. added,
  339. removed
  340. ) {
  341. var addedObjects = this._addedObjects;
  342. var removedObjects = this._removedObjects;
  343. var changedObjects = this._changedObjects;
  344. var i;
  345. var id;
  346. var entity;
  347. for (i = removed.length - 1; i > -1; i--) {
  348. entity = removed[i];
  349. id = entity.id;
  350. if (!addedObjects.remove(id)) {
  351. removedObjects.set(id, entity);
  352. changedObjects.remove(id);
  353. }
  354. }
  355. for (i = added.length - 1; i > -1; i--) {
  356. entity = added[i];
  357. id = entity.id;
  358. if (removedObjects.remove(id)) {
  359. changedObjects.set(id, entity);
  360. } else {
  361. addedObjects.set(id, entity);
  362. }
  363. }
  364. };
  365. export default PolylineVisualizer;