BillboardVisualizer.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import AssociativeArray from '../Core/AssociativeArray.js';
  2. import BoundingRectangle from '../Core/BoundingRectangle.js';
  3. import Cartesian2 from '../Core/Cartesian2.js';
  4. import Cartesian3 from '../Core/Cartesian3.js';
  5. import Color from '../Core/Color.js';
  6. import defined from '../Core/defined.js';
  7. import destroyObject from '../Core/destroyObject.js';
  8. import DeveloperError from '../Core/DeveloperError.js';
  9. import DistanceDisplayCondition from '../Core/DistanceDisplayCondition.js';
  10. import NearFarScalar from '../Core/NearFarScalar.js';
  11. import HeightReference from '../Scene/HeightReference.js';
  12. import HorizontalOrigin from '../Scene/HorizontalOrigin.js';
  13. import VerticalOrigin from '../Scene/VerticalOrigin.js';
  14. import BoundingSphereState from './BoundingSphereState.js';
  15. import Property from './Property.js';
  16. var defaultColor = Color.WHITE;
  17. var defaultEyeOffset = Cartesian3.ZERO;
  18. var defaultHeightReference = HeightReference.NONE;
  19. var defaultPixelOffset = Cartesian2.ZERO;
  20. var defaultScale = 1.0;
  21. var defaultRotation = 0.0;
  22. var defaultAlignedAxis = Cartesian3.ZERO;
  23. var defaultHorizontalOrigin = HorizontalOrigin.CENTER;
  24. var defaultVerticalOrigin = VerticalOrigin.CENTER;
  25. var defaultSizeInMeters = false;
  26. var positionScratch = new Cartesian3();
  27. var colorScratch = new Color();
  28. var eyeOffsetScratch = new Cartesian3();
  29. var pixelOffsetScratch = new Cartesian2();
  30. var scaleByDistanceScratch = new NearFarScalar();
  31. var translucencyByDistanceScratch = new NearFarScalar();
  32. var pixelOffsetScaleByDistanceScratch = new NearFarScalar();
  33. var boundingRectangleScratch = new BoundingRectangle();
  34. var distanceDisplayConditionScratch = new DistanceDisplayCondition();
  35. function EntityData(entity) {
  36. this.entity = entity;
  37. this.billboard = undefined;
  38. this.textureValue = undefined;
  39. }
  40. /**
  41. * A {@link Visualizer} which maps {@link Entity#billboard} to a {@link Billboard}.
  42. * @alias BillboardVisualizer
  43. * @constructor
  44. *
  45. * @param {EntityCluster} entityCluster The entity cluster to manage the collection of billboards and optionally cluster with other entities.
  46. * @param {EntityCollection} entityCollection The entityCollection to visualize.
  47. */
  48. function BillboardVisualizer(entityCluster, entityCollection) {
  49. //>>includeStart('debug', pragmas.debug);
  50. if (!defined(entityCluster)) {
  51. throw new DeveloperError('entityCluster is required.');
  52. }
  53. if (!defined(entityCollection)) {
  54. throw new DeveloperError('entityCollection is required.');
  55. }
  56. //>>includeEnd('debug');
  57. entityCollection.collectionChanged.addEventListener(BillboardVisualizer.prototype._onCollectionChanged, this);
  58. this._cluster = entityCluster;
  59. this._entityCollection = entityCollection;
  60. this._items = new AssociativeArray();
  61. this._onCollectionChanged(entityCollection, entityCollection.values, [], []);
  62. }
  63. /**
  64. * Updates the primitives created by this visualizer to match their
  65. * Entity counterpart at the given time.
  66. *
  67. * @param {JulianDate} time The time to update to.
  68. * @returns {Boolean} This function always returns true.
  69. */
  70. BillboardVisualizer.prototype.update = function(time) {
  71. //>>includeStart('debug', pragmas.debug);
  72. if (!defined(time)) {
  73. throw new DeveloperError('time is required.');
  74. }
  75. //>>includeEnd('debug');
  76. var items = this._items.values;
  77. var cluster = this._cluster;
  78. for (var i = 0, len = items.length; i < len; i++) {
  79. var item = items[i];
  80. var entity = item.entity;
  81. var billboardGraphics = entity._billboard;
  82. var textureValue;
  83. var billboard = item.billboard;
  84. var show = entity.isShowing && entity.isAvailable(time) && Property.getValueOrDefault(billboardGraphics._show, time, true);
  85. var position;
  86. if (show) {
  87. position = Property.getValueOrUndefined(entity._position, time, positionScratch);
  88. textureValue = Property.getValueOrUndefined(billboardGraphics._image, time);
  89. show = defined(position) && defined(textureValue);
  90. }
  91. if (!show) {
  92. //don't bother creating or updating anything else
  93. returnPrimitive(item, entity, cluster);
  94. continue;
  95. }
  96. if (!Property.isConstant(entity._position)) {
  97. cluster._clusterDirty = true;
  98. }
  99. if (!defined(billboard)) {
  100. billboard = cluster.getBillboard(entity);
  101. billboard.id = entity;
  102. billboard.image = undefined;
  103. item.billboard = billboard;
  104. }
  105. billboard.show = show;
  106. if (!defined(billboard.image) || item.textureValue !== textureValue) {
  107. billboard.image = textureValue;
  108. item.textureValue = textureValue;
  109. }
  110. billboard.position = position;
  111. billboard.color = Property.getValueOrDefault(billboardGraphics._color, time, defaultColor, colorScratch);
  112. billboard.eyeOffset = Property.getValueOrDefault(billboardGraphics._eyeOffset, time, defaultEyeOffset, eyeOffsetScratch);
  113. billboard.heightReference = Property.getValueOrDefault(billboardGraphics._heightReference, time, defaultHeightReference);
  114. billboard.pixelOffset = Property.getValueOrDefault(billboardGraphics._pixelOffset, time, defaultPixelOffset, pixelOffsetScratch);
  115. billboard.scale = Property.getValueOrDefault(billboardGraphics._scale, time, defaultScale);
  116. billboard.rotation = Property.getValueOrDefault(billboardGraphics._rotation, time, defaultRotation);
  117. billboard.alignedAxis = Property.getValueOrDefault(billboardGraphics._alignedAxis, time, defaultAlignedAxis);
  118. billboard.horizontalOrigin = Property.getValueOrDefault(billboardGraphics._horizontalOrigin, time, defaultHorizontalOrigin);
  119. billboard.verticalOrigin = Property.getValueOrDefault(billboardGraphics._verticalOrigin, time, defaultVerticalOrigin);
  120. billboard.width = Property.getValueOrUndefined(billboardGraphics._width, time);
  121. billboard.height = Property.getValueOrUndefined(billboardGraphics._height, time);
  122. billboard.scaleByDistance = Property.getValueOrUndefined(billboardGraphics._scaleByDistance, time, scaleByDistanceScratch);
  123. billboard.translucencyByDistance = Property.getValueOrUndefined(billboardGraphics._translucencyByDistance, time, translucencyByDistanceScratch);
  124. billboard.pixelOffsetScaleByDistance = Property.getValueOrUndefined(billboardGraphics._pixelOffsetScaleByDistance, time, pixelOffsetScaleByDistanceScratch);
  125. billboard.sizeInMeters = Property.getValueOrDefault(billboardGraphics._sizeInMeters, time, defaultSizeInMeters);
  126. billboard.distanceDisplayCondition = Property.getValueOrUndefined(billboardGraphics._distanceDisplayCondition, time, distanceDisplayConditionScratch);
  127. billboard.disableDepthTestDistance = Property.getValueOrUndefined(billboardGraphics._disableDepthTestDistance, time);
  128. var subRegion = Property.getValueOrUndefined(billboardGraphics._imageSubRegion, time, boundingRectangleScratch);
  129. if (defined(subRegion)) {
  130. billboard.setImageSubRegion(billboard._imageId, subRegion);
  131. }
  132. }
  133. return true;
  134. };
  135. /**
  136. * Computes a bounding sphere which encloses the visualization produced for the specified entity.
  137. * The bounding sphere is in the fixed frame of the scene's globe.
  138. *
  139. * @param {Entity} entity The entity whose bounding sphere to compute.
  140. * @param {BoundingSphere} result The bounding sphere onto which to store the result.
  141. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere,
  142. * BoundingSphereState.PENDING if the result is still being computed, or
  143. * BoundingSphereState.FAILED if the entity has no visualization in the current scene.
  144. * @private
  145. */
  146. BillboardVisualizer.prototype.getBoundingSphere = function(entity, result) {
  147. //>>includeStart('debug', pragmas.debug);
  148. if (!defined(entity)) {
  149. throw new DeveloperError('entity is required.');
  150. }
  151. if (!defined(result)) {
  152. throw new DeveloperError('result is required.');
  153. }
  154. //>>includeEnd('debug');
  155. var item = this._items.get(entity.id);
  156. if (!defined(item) || !defined(item.billboard)) {
  157. return BoundingSphereState.FAILED;
  158. }
  159. var billboard = item.billboard;
  160. if (billboard.heightReference === HeightReference.NONE) {
  161. result.center = Cartesian3.clone(billboard.position, result.center);
  162. } else {
  163. if (!defined(billboard._clampedPosition)) {
  164. return BoundingSphereState.PENDING;
  165. }
  166. result.center = Cartesian3.clone(billboard._clampedPosition, result.center);
  167. }
  168. result.radius = 0;
  169. return BoundingSphereState.DONE;
  170. };
  171. /**
  172. * Returns true if this object was destroyed; otherwise, false.
  173. *
  174. * @returns {Boolean} True if this object was destroyed; otherwise, false.
  175. */
  176. BillboardVisualizer.prototype.isDestroyed = function() {
  177. return false;
  178. };
  179. /**
  180. * Removes and destroys all primitives created by this instance.
  181. */
  182. BillboardVisualizer.prototype.destroy = function() {
  183. this._entityCollection.collectionChanged.removeEventListener(BillboardVisualizer.prototype._onCollectionChanged, this);
  184. var entities = this._entityCollection.values;
  185. for (var i = 0; i < entities.length; i++) {
  186. this._cluster.removeBillboard(entities[i]);
  187. }
  188. return destroyObject(this);
  189. };
  190. BillboardVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) {
  191. var i;
  192. var entity;
  193. var items = this._items;
  194. var cluster = this._cluster;
  195. for (i = added.length - 1; i > -1; i--) {
  196. entity = added[i];
  197. if (defined(entity._billboard) && defined(entity._position)) {
  198. items.set(entity.id, new EntityData(entity));
  199. }
  200. }
  201. for (i = changed.length - 1; i > -1; i--) {
  202. entity = changed[i];
  203. if (defined(entity._billboard) && defined(entity._position)) {
  204. if (!items.contains(entity.id)) {
  205. items.set(entity.id, new EntityData(entity));
  206. }
  207. } else {
  208. returnPrimitive(items.get(entity.id), entity, cluster);
  209. items.remove(entity.id);
  210. }
  211. }
  212. for (i = removed.length - 1; i > -1; i--) {
  213. entity = removed[i];
  214. returnPrimitive(items.get(entity.id), entity, cluster);
  215. items.remove(entity.id);
  216. }
  217. };
  218. function returnPrimitive(item, entity, cluster) {
  219. if (defined(item)) {
  220. item.billboard = undefined;
  221. cluster.removeBillboard(entity);
  222. }
  223. }
  224. export default BillboardVisualizer;