PolylineVisualizer.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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) { // Also checks for support
  33. var classificationType = updater.classificationTypeProperty.getValue(time);
  34. that._groundBatches[classificationType].add(time, updater);
  35. return;
  36. }
  37. var shadows;
  38. if (updater.fillEnabled) {
  39. shadows = updater.shadowsProperty.getValue(time);
  40. }
  41. var multiplier = 0;
  42. if (defined(updater.depthFailMaterialProperty)) {
  43. multiplier = updater.depthFailMaterialProperty instanceof ColorMaterialProperty ? 1 : 2;
  44. }
  45. var index;
  46. if (defined(shadows)) {
  47. index = shadows + multiplier * ShadowMode.NUMBER_OF_SHADOW_MODES;
  48. }
  49. if (updater.fillEnabled) {
  50. if (updater.fillMaterialProperty instanceof ColorMaterialProperty) {
  51. that._colorBatches[index].add(time, updater);
  52. } else {
  53. that._materialBatches[index].add(time, updater);
  54. }
  55. }
  56. }
  57. /**
  58. * A visualizer for polylines represented by {@link Primitive} instances.
  59. * @alias PolylineVisualizer
  60. * @constructor
  61. *
  62. * @param {Scene} scene The scene the primitives will be rendered in.
  63. * @param {EntityCollection} entityCollection The entityCollection to visualize.
  64. * @param {PrimitiveCollection} [primitives=scene.primitives] A collection to add primitives related to the entities
  65. * @param {PrimitiveCollection} [groundPrimitives=scene.groundPrimitives] A collection to add ground primitives related to the entities
  66. */
  67. function PolylineVisualizer(scene, entityCollection, primitives, groundPrimitives) {
  68. //>>includeStart('debug', pragmas.debug);
  69. Check.defined('scene', scene);
  70. Check.defined('entityCollection', entityCollection);
  71. //>>includeEnd('debug');
  72. groundPrimitives = defaultValue(groundPrimitives, scene.groundPrimitives);
  73. primitives = defaultValue(primitives, scene.primitives);
  74. this._scene = scene;
  75. this._primitives = primitives;
  76. this._entityCollection = undefined;
  77. this._addedObjects = new AssociativeArray();
  78. this._removedObjects = new AssociativeArray();
  79. this._changedObjects = new AssociativeArray();
  80. var i;
  81. var numberOfShadowModes = ShadowMode.NUMBER_OF_SHADOW_MODES;
  82. this._colorBatches = new Array(numberOfShadowModes * 3);
  83. this._materialBatches = new Array(numberOfShadowModes * 3);
  84. for (i = 0; i < numberOfShadowModes; ++i) {
  85. this._colorBatches[i] = new StaticGeometryColorBatch(primitives, PolylineColorAppearance, undefined, false, i); // no depth fail appearance
  86. this._materialBatches[i] = new StaticGeometryPerMaterialBatch(primitives, PolylineMaterialAppearance, undefined, false, i);
  87. this._colorBatches[i + numberOfShadowModes] = new StaticGeometryColorBatch(primitives, PolylineColorAppearance, PolylineColorAppearance, false, i); //depth fail appearance variations
  88. this._materialBatches[i + numberOfShadowModes] = new StaticGeometryPerMaterialBatch(primitives, PolylineMaterialAppearance, PolylineColorAppearance, false, i);
  89. this._colorBatches[i + numberOfShadowModes * 2] = new StaticGeometryColorBatch(primitives, PolylineColorAppearance, PolylineMaterialAppearance, false, i);
  90. this._materialBatches[i + numberOfShadowModes * 2] = new StaticGeometryPerMaterialBatch(primitives, PolylineMaterialAppearance, PolylineMaterialAppearance, false, i);
  91. }
  92. this._dynamicBatch = new DynamicGeometryBatch(primitives, groundPrimitives);
  93. var numberOfClassificationTypes = ClassificationType.NUMBER_OF_CLASSIFICATION_TYPES;
  94. this._groundBatches = new Array(numberOfClassificationTypes);
  95. for (i = 0; i < numberOfClassificationTypes; ++i) {
  96. this._groundBatches[i] = new StaticGroundPolylinePerMaterialBatch(groundPrimitives, i);
  97. }
  98. this._batches = this._colorBatches.concat(this._materialBatches, this._dynamicBatch, this._groundBatches);
  99. this._subscriptions = new AssociativeArray();
  100. this._updaters = new AssociativeArray();
  101. this._entityCollection = entityCollection;
  102. entityCollection.collectionChanged.addEventListener(PolylineVisualizer.prototype._onCollectionChanged, this);
  103. this._onCollectionChanged(entityCollection, entityCollection.values, emptyArray);
  104. }
  105. /**
  106. * Updates all of the primitives created by this visualizer to match their
  107. * Entity counterpart at the given time.
  108. *
  109. * @param {JulianDate} time The time to update to.
  110. * @returns {Boolean} True if the visualizer successfully updated to the provided time,
  111. * false if the visualizer is waiting for asynchronous primitives to be created.
  112. */
  113. PolylineVisualizer.prototype.update = function(time) {
  114. //>>includeStart('debug', pragmas.debug);
  115. Check.defined('time', time);
  116. //>>includeEnd('debug');
  117. var addedObjects = this._addedObjects;
  118. var added = addedObjects.values;
  119. var removedObjects = this._removedObjects;
  120. var removed = removedObjects.values;
  121. var changedObjects = this._changedObjects;
  122. var changed = changedObjects.values;
  123. var i;
  124. var entity;
  125. var id;
  126. var updater;
  127. for (i = changed.length - 1; i > -1; i--) {
  128. entity = changed[i];
  129. id = entity.id;
  130. updater = this._updaters.get(id);
  131. //If in a single update, an entity gets removed and a new instance
  132. //re-added with the same id, the updater no longer tracks the
  133. //correct entity, we need to both remove the old one and
  134. //add the new one, which is done by pushing the entity
  135. //onto the removed/added lists.
  136. if (updater.entity === entity) {
  137. removeUpdater(this, updater);
  138. insertUpdaterIntoBatch(this, time, updater);
  139. } else {
  140. removed.push(entity);
  141. added.push(entity);
  142. }
  143. }
  144. for (i = removed.length - 1; i > -1; i--) {
  145. entity = removed[i];
  146. id = entity.id;
  147. updater = this._updaters.get(id);
  148. removeUpdater(this, updater);
  149. updater.destroy();
  150. this._updaters.remove(id);
  151. this._subscriptions.get(id)();
  152. this._subscriptions.remove(id);
  153. }
  154. for (i = added.length - 1; i > -1; i--) {
  155. entity = added[i];
  156. id = entity.id;
  157. updater = new PolylineGeometryUpdater(entity, this._scene);
  158. this._updaters.set(id, updater);
  159. insertUpdaterIntoBatch(this, time, updater);
  160. this._subscriptions.set(id, updater.geometryChanged.addEventListener(PolylineVisualizer._onGeometryChanged, this));
  161. }
  162. addedObjects.removeAll();
  163. removedObjects.removeAll();
  164. changedObjects.removeAll();
  165. var isUpdated = true;
  166. var batches = this._batches;
  167. var length = batches.length;
  168. for (i = 0; i < length; i++) {
  169. isUpdated = batches[i].update(time) && isUpdated;
  170. }
  171. return isUpdated;
  172. };
  173. var getBoundingSphereArrayScratch = [];
  174. var getBoundingSphereBoundingSphereScratch = new BoundingSphere();
  175. /**
  176. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  177. * The bounding sphere is in the fixed frame of the scene's globe.
  178. *
  179. * @param {Entity} entity The entity whose bounding sphere to compute.
  180. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  181. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  182. * BoundingSphereState.PENDING if the result is still being computed, or
  183. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  184. * @private
  185. */
  186. PolylineVisualizer.prototype.getBoundingSphere = function(entity, result) {
  187. //>>includeStart('debug', pragmas.debug);
  188. Check.defined('entity', entity);
  189. Check.defined('result', result);
  190. //>>includeEnd('debug');
  191. var boundingSpheres = getBoundingSphereArrayScratch;
  192. var tmp = getBoundingSphereBoundingSphereScratch;
  193. var count = 0;
  194. var state = BoundingSphereState.DONE;
  195. var batches = this._batches;
  196. var batchesLength = batches.length;
  197. var updater = this._updaters.get(entity.id);
  198. for (var i = 0; i < batchesLength; i++) {
  199. state = batches[i].getBoundingSphere(updater, tmp);
  200. if (state === BoundingSphereState.PENDING) {
  201. return BoundingSphereState.PENDING;
  202. } else if (state === BoundingSphereState.DONE) {
  203. boundingSpheres[count] = BoundingSphere.clone(tmp, boundingSpheres[count]);
  204. count++;
  205. }
  206. }
  207. if (count === 0) {
  208. return BoundingSphereState.FAILED;
  209. }
  210. boundingSpheres.length = count;
  211. BoundingSphere.fromBoundingSpheres(boundingSpheres, result);
  212. return BoundingSphereState.DONE;
  213. };
  214. /**
  215. * Returns true if this object was destroyed; otherwise, false.
  216. *
  217. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  218. */
  219. PolylineVisualizer.prototype.isDestroyed = function() {
  220. return false;
  221. };
  222. /**
  223. * Removes and destroys all primitives created by this instance.
  224. */
  225. PolylineVisualizer.prototype.destroy = function() {
  226. this._entityCollection.collectionChanged.removeEventListener(PolylineVisualizer.prototype._onCollectionChanged, this);
  227. this._addedObjects.removeAll();
  228. this._removedObjects.removeAll();
  229. var i;
  230. var batches = this._batches;
  231. var length = batches.length;
  232. for (i = 0; i < length; i++) {
  233. batches[i].removeAllPrimitives();
  234. }
  235. var subscriptions = this._subscriptions.values;
  236. length = subscriptions.length;
  237. for (i = 0; i < length; i++) {
  238. subscriptions[i]();
  239. }
  240. this._subscriptions.removeAll();
  241. return destroyObject(this);
  242. };
  243. /**
  244. * @private
  245. */
  246. PolylineVisualizer._onGeometryChanged = function(updater) {
  247. var removedObjects = this._removedObjects;
  248. var changedObjects = this._changedObjects;
  249. var entity = updater.entity;
  250. var id = entity.id;
  251. if (!defined(removedObjects.get(id)) && !defined(changedObjects.get(id))) {
  252. changedObjects.set(id, entity);
  253. }
  254. };
  255. /**
  256. * @private
  257. */
  258. PolylineVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed) {
  259. var addedObjects = this._addedObjects;
  260. var removedObjects = this._removedObjects;
  261. var changedObjects = this._changedObjects;
  262. var i;
  263. var id;
  264. var entity;
  265. for (i = removed.length - 1; i > -1; i--) {
  266. entity = removed[i];
  267. id = entity.id;
  268. if (!addedObjects.remove(id)) {
  269. removedObjects.set(id, entity);
  270. changedObjects.remove(id);
  271. }
  272. }
  273. for (i = added.length - 1; i > -1; i--) {
  274. entity = added[i];
  275. id = entity.id;
  276. if (removedObjects.remove(id)) {
  277. changedObjects.set(id, entity);
  278. } else {
  279. addedObjects.set(id, entity);
  280. }
  281. }
  282. };
  283. export default PolylineVisualizer;