| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620 | import AssociativeArray from "../Core/AssociativeArray.js";import BoundingSphere from "../Core/BoundingSphere.js";import Check from "../Core/Check.js";import defaultValue from "../Core/defaultValue.js";import defined from "../Core/defined.js";import destroyObject from "../Core/destroyObject.js";import Event from "../Core/Event.js";import EventHelper from "../Core/EventHelper.js";import ClassificationType from "../Scene/ClassificationType.js";import MaterialAppearance from "../Scene/MaterialAppearance.js";import PerInstanceColorAppearance from "../Scene/PerInstanceColorAppearance.js";import ShadowMode from "../Scene/ShadowMode.js";import BoundingSphereState from "./BoundingSphereState.js";import BoxGeometryUpdater from "./BoxGeometryUpdater.js";import ColorMaterialProperty from "./ColorMaterialProperty.js";import CorridorGeometryUpdater from "./CorridorGeometryUpdater.js";import CylinderGeometryUpdater from "./CylinderGeometryUpdater.js";import DynamicGeometryBatch from "./DynamicGeometryBatch.js";import EllipseGeometryUpdater from "./EllipseGeometryUpdater.js";import EllipsoidGeometryUpdater from "./EllipsoidGeometryUpdater.js";import Entity from "./Entity.js";import PlaneGeometryUpdater from "./PlaneGeometryUpdater.js";import PolygonGeometryUpdater from "./PolygonGeometryUpdater.js";import PolylineVolumeGeometryUpdater from "./PolylineVolumeGeometryUpdater.js";import RectangleGeometryUpdater from "./RectangleGeometryUpdater.js";import StaticGeometryColorBatch from "./StaticGeometryColorBatch.js";import StaticGeometryPerMaterialBatch from "./StaticGeometryPerMaterialBatch.js";import StaticGroundGeometryColorBatch from "./StaticGroundGeometryColorBatch.js";import StaticGroundGeometryPerMaterialBatch from "./StaticGroundGeometryPerMaterialBatch.js";import StaticOutlineGeometryBatch from "./StaticOutlineGeometryBatch.js";import WallGeometryUpdater from "./WallGeometryUpdater.js";const emptyArray = [];const geometryUpdaters = [  BoxGeometryUpdater,  CylinderGeometryUpdater,  CorridorGeometryUpdater,  EllipseGeometryUpdater,  EllipsoidGeometryUpdater,  PlaneGeometryUpdater,  PolygonGeometryUpdater,  PolylineVolumeGeometryUpdater,  RectangleGeometryUpdater,  WallGeometryUpdater,];function GeometryUpdaterSet(entity, scene) {  this.entity = entity;  this.scene = scene;  const updaters = new Array(geometryUpdaters.length);  const geometryChanged = new Event();  function raiseEvent(geometry) {    geometryChanged.raiseEvent(geometry);  }  const eventHelper = new EventHelper();  for (let i = 0; i < updaters.length; i++) {    const updater = new geometryUpdaters[i](entity, scene);    eventHelper.add(updater.geometryChanged, raiseEvent);    updaters[i] = updater;  }  this.updaters = updaters;  this.geometryChanged = geometryChanged;  this.eventHelper = eventHelper;  this._removeEntitySubscription = entity.definitionChanged.addEventListener(    GeometryUpdaterSet.prototype._onEntityPropertyChanged,    this  );}GeometryUpdaterSet.prototype._onEntityPropertyChanged = function (  entity,  propertyName,  newValue,  oldValue) {  const updaters = this.updaters;  for (let i = 0; i < updaters.length; i++) {    updaters[i]._onEntityPropertyChanged(      entity,      propertyName,      newValue,      oldValue    );  }};GeometryUpdaterSet.prototype.forEach = function (callback) {  const updaters = this.updaters;  for (let i = 0; i < updaters.length; i++) {    callback(updaters[i]);  }};GeometryUpdaterSet.prototype.destroy = function () {  this.eventHelper.removeAll();  const updaters = this.updaters;  for (let i = 0; i < updaters.length; i++) {    updaters[i].destroy();  }  this._removeEntitySubscription();  destroyObject(this);};/** * A general purpose visualizer for geometry represented by {@link Primitive} instances. * @alias GeometryVisualizer * @constructor * * @param {Scene} scene The scene the primitives will be rendered in. * @param {EntityCollection} entityCollection The entityCollection to visualize. * @param {PrimitiveCollection} [primitives=scene.primitives] A collection to add primitives related to the entities * @param {PrimitiveCollection} [groundPrimitives=scene.groundPrimitives] A collection to add ground primitives related to the entities */function GeometryVisualizer(  scene,  entityCollection,  primitives,  groundPrimitives) {  //>>includeStart('debug', pragmas.debug);  Check.defined("scene", scene);  Check.defined("entityCollection", entityCollection);  //>>includeEnd('debug');  primitives = defaultValue(primitives, scene.primitives);  groundPrimitives = defaultValue(groundPrimitives, scene.groundPrimitives);  this._scene = scene;  this._primitives = primitives;  this._groundPrimitives = groundPrimitives;  this._entityCollection = undefined;  this._addedObjects = new AssociativeArray();  this._removedObjects = new AssociativeArray();  this._changedObjects = new AssociativeArray();  const numberOfShadowModes = ShadowMode.NUMBER_OF_SHADOW_MODES;  this._outlineBatches = new Array(numberOfShadowModes * 2);  this._closedColorBatches = new Array(numberOfShadowModes * 2);  this._closedMaterialBatches = new Array(numberOfShadowModes * 2);  this._openColorBatches = new Array(numberOfShadowModes * 2);  this._openMaterialBatches = new Array(numberOfShadowModes * 2);  const supportsMaterialsforEntitiesOnTerrain = Entity.supportsMaterialsforEntitiesOnTerrain(    scene  );  this._supportsMaterialsforEntitiesOnTerrain = supportsMaterialsforEntitiesOnTerrain;  let i;  for (i = 0; i < numberOfShadowModes; ++i) {    this._outlineBatches[i] = new StaticOutlineGeometryBatch(      primitives,      scene,      i,      false    );    this._outlineBatches[      numberOfShadowModes + i    ] = new StaticOutlineGeometryBatch(primitives, scene, i, true);    this._closedColorBatches[i] = new StaticGeometryColorBatch(      primitives,      PerInstanceColorAppearance,      undefined,      true,      i,      true    );    this._closedColorBatches[      numberOfShadowModes + i    ] = new StaticGeometryColorBatch(      primitives,      PerInstanceColorAppearance,      undefined,      true,      i,      false    );    this._closedMaterialBatches[i] = new StaticGeometryPerMaterialBatch(      primitives,      MaterialAppearance,      undefined,      true,      i,      true    );    this._closedMaterialBatches[      numberOfShadowModes + i    ] = new StaticGeometryPerMaterialBatch(      primitives,      MaterialAppearance,      undefined,      true,      i,      false    );    this._openColorBatches[i] = new StaticGeometryColorBatch(      primitives,      PerInstanceColorAppearance,      undefined,      false,      i,      true    );    this._openColorBatches[      numberOfShadowModes + i    ] = new StaticGeometryColorBatch(      primitives,      PerInstanceColorAppearance,      undefined,      false,      i,      false    );    this._openMaterialBatches[i] = new StaticGeometryPerMaterialBatch(      primitives,      MaterialAppearance,      undefined,      false,      i,      true    );    this._openMaterialBatches[      numberOfShadowModes + i    ] = new StaticGeometryPerMaterialBatch(      primitives,      MaterialAppearance,      undefined,      false,      i,      false    );  }  const numberOfClassificationTypes =    ClassificationType.NUMBER_OF_CLASSIFICATION_TYPES;  const groundColorBatches = new Array(numberOfClassificationTypes);  const groundMaterialBatches = [];  if (supportsMaterialsforEntitiesOnTerrain) {    for (i = 0; i < numberOfClassificationTypes; ++i) {      groundMaterialBatches.push(        new StaticGroundGeometryPerMaterialBatch(          groundPrimitives,          i,          MaterialAppearance        )      );      groundColorBatches[i] = new StaticGroundGeometryColorBatch(        groundPrimitives,        i      );    }  } else {    for (i = 0; i < numberOfClassificationTypes; ++i) {      groundColorBatches[i] = new StaticGroundGeometryColorBatch(        groundPrimitives,        i      );    }  }  this._groundColorBatches = groundColorBatches;  this._groundMaterialBatches = groundMaterialBatches;  this._dynamicBatch = new DynamicGeometryBatch(primitives, groundPrimitives);  this._batches = this._outlineBatches.concat(    this._closedColorBatches,    this._closedMaterialBatches,    this._openColorBatches,    this._openMaterialBatches,    this._groundColorBatches,    this._groundMaterialBatches,    this._dynamicBatch  );  this._subscriptions = new AssociativeArray();  this._updaterSets = new AssociativeArray();  this._entityCollection = entityCollection;  entityCollection.collectionChanged.addEventListener(    GeometryVisualizer.prototype._onCollectionChanged,    this  );  this._onCollectionChanged(    entityCollection,    entityCollection.values,    emptyArray  );}/** * Updates all of the primitives created by this visualizer to match their * Entity counterpart at the given time. * * @param {JulianDate} time The time to update to. * @returns {Boolean} True if the visualizer successfully updated to the provided time, * false if the visualizer is waiting for asynchronous primitives to be created. */GeometryVisualizer.prototype.update = function (time) {  //>>includeStart('debug', pragmas.debug);  Check.defined("time", time);  //>>includeEnd('debug');  const addedObjects = this._addedObjects;  const added = addedObjects.values;  const removedObjects = this._removedObjects;  const removed = removedObjects.values;  const changedObjects = this._changedObjects;  const changed = changedObjects.values;  let i;  let entity;  let id;  let updaterSet;  const that = this;  for (i = changed.length - 1; i > -1; i--) {    entity = changed[i];    id = entity.id;    updaterSet = this._updaterSets.get(id);    //If in a single update, an entity gets removed and a new instance    //re-added with the same id, the updater no longer tracks the    //correct entity, we need to both remove the old one and    //add the new one, which is done by pushing the entity    //onto the removed/added lists.    if (updaterSet.entity === entity) {      updaterSet.forEach(function (updater) {        that._removeUpdater(updater);        that._insertUpdaterIntoBatch(time, updater);      });    } else {      removed.push(entity);      added.push(entity);    }  }  for (i = removed.length - 1; i > -1; i--) {    entity = removed[i];    id = entity.id;    updaterSet = this._updaterSets.get(id);    updaterSet.forEach(this._removeUpdater.bind(this));    updaterSet.destroy();    this._updaterSets.remove(id);    this._subscriptions.get(id)();    this._subscriptions.remove(id);  }  for (i = added.length - 1; i > -1; i--) {    entity = added[i];    id = entity.id;    updaterSet = new GeometryUpdaterSet(entity, this._scene);    this._updaterSets.set(id, updaterSet);    updaterSet.forEach(function (updater) {      that._insertUpdaterIntoBatch(time, updater);    });    this._subscriptions.set(      id,      updaterSet.geometryChanged.addEventListener(        GeometryVisualizer._onGeometryChanged,        this      )    );  }  addedObjects.removeAll();  removedObjects.removeAll();  changedObjects.removeAll();  let isUpdated = true;  const batches = this._batches;  const length = batches.length;  for (i = 0; i < length; i++) {    isUpdated = batches[i].update(time) && isUpdated;  }  return isUpdated;};const getBoundingSphereArrayScratch = [];const getBoundingSphereBoundingSphereScratch = new BoundingSphere();/** * Computes a bounding sphere which encloses the visualization produced for the specified entity. * The bounding sphere is in the fixed frame of the scene's globe. * * @param {Entity} entity The entity whose bounding sphere to compute. * @param {BoundingSphere} result The bounding sphere onto which to store the result. * @returns {BoundingSphereState} BoundingSphereState.DONE if the result contains the bounding sphere, *                       BoundingSphereState.PENDING if the result is still being computed, or *                       BoundingSphereState.FAILED if the entity has no visualization in the current scene. * @private */GeometryVisualizer.prototype.getBoundingSphere = function (entity, result) {  //>>includeStart('debug', pragmas.debug);  Check.defined("entity", entity);  Check.defined("result", result);  //>>includeEnd('debug');  const boundingSpheres = getBoundingSphereArrayScratch;  const tmp = getBoundingSphereBoundingSphereScratch;  let count = 0;  let state = BoundingSphereState.DONE;  const batches = this._batches;  const batchesLength = batches.length;  const id = entity.id;  const updaters = this._updaterSets.get(id).updaters;  for (let j = 0; j < updaters.length; j++) {    const updater = updaters[j];    for (let i = 0; i < batchesLength; i++) {      state = batches[i].getBoundingSphere(updater, tmp);      if (state === BoundingSphereState.PENDING) {        return BoundingSphereState.PENDING;      } else if (state === BoundingSphereState.DONE) {        boundingSpheres[count] = BoundingSphere.clone(          tmp,          boundingSpheres[count]        );        count++;      }    }  }  if (count === 0) {    return BoundingSphereState.FAILED;  }  boundingSpheres.length = count;  BoundingSphere.fromBoundingSpheres(boundingSpheres, result);  return BoundingSphereState.DONE;};/** * Returns true if this object was destroyed; otherwise, false. * * @returns {Boolean} True if this object was destroyed; otherwise, false. */GeometryVisualizer.prototype.isDestroyed = function () {  return false;};/** * Removes and destroys all primitives created by this instance. */GeometryVisualizer.prototype.destroy = function () {  this._entityCollection.collectionChanged.removeEventListener(    GeometryVisualizer.prototype._onCollectionChanged,    this  );  this._addedObjects.removeAll();  this._removedObjects.removeAll();  let i;  const batches = this._batches;  let length = batches.length;  for (i = 0; i < length; i++) {    batches[i].removeAllPrimitives();  }  const subscriptions = this._subscriptions.values;  length = subscriptions.length;  for (i = 0; i < length; i++) {    subscriptions[i]();  }  this._subscriptions.removeAll();  const updaterSets = this._updaterSets.values;  length = updaterSets.length;  for (i = 0; i < length; i++) {    updaterSets[i].destroy();  }  this._updaterSets.removeAll();  return destroyObject(this);};/** * @private */GeometryVisualizer.prototype._removeUpdater = function (updater) {  //We don't keep track of which batch an updater is in, so just remove it from all of them.  const batches = this._batches;  const length = batches.length;  for (let i = 0; i < length; i++) {    batches[i].remove(updater);  }};/** * @private */GeometryVisualizer.prototype._insertUpdaterIntoBatch = function (  time,  updater) {  if (updater.isDynamic) {    this._dynamicBatch.add(time, updater);    return;  }  let shadows;  if (updater.outlineEnabled || updater.fillEnabled) {    shadows = updater.shadowsProperty.getValue(time);  }  const numberOfShadowModes = ShadowMode.NUMBER_OF_SHADOW_MODES;  if (updater.outlineEnabled) {    if (defined(updater.terrainOffsetProperty)) {      this._outlineBatches[numberOfShadowModes + shadows].add(time, updater);    } else {      this._outlineBatches[shadows].add(time, updater);    }  }  if (updater.fillEnabled) {    if (updater.onTerrain) {      const classificationType = updater.classificationTypeProperty.getValue(        time      );      if (updater.fillMaterialProperty instanceof ColorMaterialProperty) {        this._groundColorBatches[classificationType].add(time, updater);      } else {        // If unsupported, updater will not be on terrain.        this._groundMaterialBatches[classificationType].add(time, updater);      }    } else if (updater.isClosed) {      if (updater.fillMaterialProperty instanceof ColorMaterialProperty) {        if (defined(updater.terrainOffsetProperty)) {          this._closedColorBatches[numberOfShadowModes + shadows].add(            time,            updater          );        } else {          this._closedColorBatches[shadows].add(time, updater);        }      } else if (defined(updater.terrainOffsetProperty)) {        this._closedMaterialBatches[numberOfShadowModes + shadows].add(          time,          updater        );      } else {        this._closedMaterialBatches[shadows].add(time, updater);      }    } else if (updater.fillMaterialProperty instanceof ColorMaterialProperty) {      if (defined(updater.terrainOffsetProperty)) {        this._openColorBatches[numberOfShadowModes + shadows].add(          time,          updater        );      } else {        this._openColorBatches[shadows].add(time, updater);      }    } else if (defined(updater.terrainOffsetProperty)) {      this._openMaterialBatches[numberOfShadowModes + shadows].add(        time,        updater      );    } else {      this._openMaterialBatches[shadows].add(time, updater);    }  }};/** * @private */GeometryVisualizer._onGeometryChanged = function (updater) {  const removedObjects = this._removedObjects;  const changedObjects = this._changedObjects;  const entity = updater.entity;  const id = entity.id;  if (!defined(removedObjects.get(id)) && !defined(changedObjects.get(id))) {    changedObjects.set(id, entity);  }};/** * @private */GeometryVisualizer.prototype._onCollectionChanged = function (  entityCollection,  added,  removed) {  const addedObjects = this._addedObjects;  const removedObjects = this._removedObjects;  const changedObjects = this._changedObjects;  let i;  let id;  let entity;  for (i = removed.length - 1; i > -1; i--) {    entity = removed[i];    id = entity.id;    if (!addedObjects.remove(id)) {      removedObjects.set(id, entity);      changedObjects.remove(id);    }  }  for (i = added.length - 1; i > -1; i--) {    entity = added[i];    id = entity.id;    if (removedObjects.remove(id)) {      changedObjects.set(id, entity);    } else {      addedObjects.set(id, entity);    }  }};export default GeometryVisualizer;
 |