123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- /*global define*/
- define([
- '../Core/AssociativeArray',
- '../Core/Cartesian3',
- '../Core/defined',
- '../Core/destroyObject',
- '../Core/DeveloperError',
- '../Core/JulianDate',
- '../Core/Matrix3',
- '../Core/Matrix4',
- '../Core/ReferenceFrame',
- '../Core/TimeInterval',
- '../Core/Transforms',
- '../Scene/PolylineCollection',
- '../Scene/SceneMode',
- './CompositePositionProperty',
- './ConstantPositionProperty',
- './MaterialProperty',
- './Property',
- './ReferenceProperty',
- './SampledPositionProperty',
- './TimeIntervalCollectionPositionProperty'
- ], function(
- AssociativeArray,
- Cartesian3,
- defined,
- destroyObject,
- DeveloperError,
- JulianDate,
- Matrix3,
- Matrix4,
- ReferenceFrame,
- TimeInterval,
- Transforms,
- PolylineCollection,
- SceneMode,
- CompositePositionProperty,
- ConstantPositionProperty,
- MaterialProperty,
- Property,
- ReferenceProperty,
- SampledPositionProperty,
- TimeIntervalCollectionPositionProperty) {
- "use strict";
- var defaultResolution = 60.0;
- var defaultWidth = 1.0;
- var scratchTimeInterval = new TimeInterval();
- var subSampleCompositePropertyScratch = new TimeInterval();
- var subSampleIntervalPropertyScratch = new TimeInterval();
- var EntityData = function(entity) {
- this.entity = entity;
- this.polyline = undefined;
- this.index = undefined;
- this.updater = undefined;
- };
- function subSampleSampledProperty(property, start, stop, updateTime, referenceFrame, maximumStep, startingIndex, result) {
- var times = property._property._times;
- var r = startingIndex;
- //Always step exactly on start (but only use it if it exists.)
- var tmp;
- tmp = property.getValueInReferenceFrame(start, referenceFrame, result[r]);
- if (defined(tmp)) {
- result[r++] = tmp;
- }
- var steppedOnNow = !defined(updateTime) || JulianDate.lessThanOrEquals(updateTime, start) || JulianDate.greaterThanOrEquals(updateTime, stop);
- //Iterate over all interval times and add the ones that fall in our
- //time range. Note that times can contain data outside of
- //the intervals range. This is by design for use with interpolation.
- var t = 0;
- var len = times.length;
- var current = times[t];
- var loopStop = stop;
- var sampling = false;
- var sampleStepsToTake;
- var sampleStepsTaken;
- var sampleStepSize;
- while (t < len) {
- if (!steppedOnNow && JulianDate.greaterThanOrEquals(current, updateTime)) {
- tmp = property.getValueInReferenceFrame(updateTime, referenceFrame, result[r]);
- if (defined(tmp)) {
- result[r++] = tmp;
- }
- steppedOnNow = true;
- }
- if (JulianDate.greaterThan(current, start) && JulianDate.lessThan(current, loopStop) && !current.equals(updateTime)) {
- tmp = property.getValueInReferenceFrame(current, referenceFrame, result[r]);
- if (defined(tmp)) {
- result[r++] = tmp;
- }
- }
- if (t < (len - 1)) {
- if (maximumStep > 0 && !sampling) {
- var next = times[t + 1];
- var secondsUntilNext = JulianDate.secondsDifference(next, current);
- sampling = secondsUntilNext > maximumStep;
- if (sampling) {
- sampleStepsToTake = Math.ceil(secondsUntilNext / maximumStep);
- sampleStepsTaken = 0;
- sampleStepSize = secondsUntilNext / Math.max(sampleStepsToTake, 2);
- sampleStepsToTake = Math.max(sampleStepsToTake - 1, 1);
- }
- }
- if (sampling && sampleStepsTaken < sampleStepsToTake) {
- current = JulianDate.addSeconds(current, sampleStepSize, new JulianDate());
- sampleStepsTaken++;
- continue;
- }
- }
- sampling = false;
- t++;
- current = times[t];
- }
- //Always step exactly on stop (but only use it if it exists.)
- tmp = property.getValueInReferenceFrame(stop, referenceFrame, result[r]);
- if (defined(tmp)) {
- result[r++] = tmp;
- }
- return r;
- }
- function subSampleGenericProperty(property, start, stop, updateTime, referenceFrame, maximumStep, startingIndex, result) {
- var tmp;
- var i = 0;
- var index = startingIndex;
- var time = start;
- var stepSize = Math.max(maximumStep, 60);
- var steppedOnNow = !defined(updateTime) || JulianDate.lessThanOrEquals(updateTime, start) || JulianDate.greaterThanOrEquals(updateTime, stop);
- while (JulianDate.lessThan(time, stop)) {
- if (!steppedOnNow && JulianDate.greaterThanOrEquals(time, updateTime)) {
- steppedOnNow = true;
- tmp = property.getValueInReferenceFrame(updateTime, referenceFrame, result[index]);
- if (defined(tmp)) {
- result[index] = tmp;
- index++;
- }
- }
- tmp = property.getValueInReferenceFrame(time, referenceFrame, result[index]);
- if (defined(tmp)) {
- result[index] = tmp;
- index++;
- }
- i++;
- time = JulianDate.addSeconds(start, stepSize * i, new JulianDate());
- }
- //Always sample stop.
- tmp = property.getValueInReferenceFrame(stop, referenceFrame, result[index]);
- if (defined(tmp)) {
- result[index] = tmp;
- index++;
- }
- return index;
- }
- function subSampleIntervalProperty(property, start, stop, updateTime, referenceFrame, maximumStep, startingIndex, result) {
- subSampleIntervalPropertyScratch.start = start;
- subSampleIntervalPropertyScratch.stop = stop;
- var index = startingIndex;
- var intervals = property.intervals;
- for (var i = 0; i < intervals.length; i++) {
- var interval = intervals.get(i);
- if (!TimeInterval.intersect(interval, subSampleIntervalPropertyScratch, scratchTimeInterval).isEmpty) {
- var time = interval.start;
- if (!interval.isStartIncluded) {
- if (interval.isStopIncluded) {
- time = interval.stop;
- } else {
- time = JulianDate.addSeconds(interval.start, JulianDate.secondsDifference(interval.stop, interval.start) / 2, new JulianDate());
- }
- }
- var tmp = property.getValueInReferenceFrame(time, referenceFrame, result[index]);
- if (defined(tmp)) {
- result[index] = tmp;
- index++;
- }
- }
- }
- return index;
- }
- function subSampleConstantProperty(property, start, stop, updateTime, referenceFrame, maximumStep, startingIndex, result) {
- var tmp = property.getValueInReferenceFrame(start, referenceFrame, result[startingIndex]);
- if (defined(tmp)) {
- result[startingIndex++] = tmp;
- }
- return startingIndex;
- }
- function subSampleCompositeProperty(property, start, stop, updateTime, referenceFrame, maximumStep, startingIndex, result) {
- subSampleCompositePropertyScratch.start = start;
- subSampleCompositePropertyScratch.stop = stop;
- var index = startingIndex;
- var intervals = property.intervals;
- for (var i = 0; i < intervals.length; i++) {
- var interval = intervals.get(i);
- if (!TimeInterval.intersect(interval, subSampleCompositePropertyScratch, scratchTimeInterval).isEmpty) {
- var intervalStart = interval.start;
- var intervalStop = interval.stop;
- var sampleStart = start;
- if (JulianDate.greaterThan(intervalStart, sampleStart)) {
- sampleStart = intervalStart;
- }
- var sampleStop = stop;
- if (JulianDate.lessThan(intervalStop, sampleStop)) {
- sampleStop = intervalStop;
- }
- var intervalProperty = interval.data;
- if (intervalProperty instanceof ReferenceProperty) {
- intervalProperty = intervalProperty.resolvedProperty;
- }
- if (intervalProperty instanceof SampledPositionProperty) {
- index = subSampleSampledProperty(intervalProperty, sampleStart, sampleStop, updateTime, referenceFrame, maximumStep, index, result);
- } else if (intervalProperty instanceof CompositePositionProperty) {
- index = subSampleCompositeProperty(intervalProperty, sampleStart, sampleStop, updateTime, referenceFrame, maximumStep, index, result);
- } else if (intervalProperty instanceof TimeIntervalCollectionPositionProperty) {
- index = subSampleIntervalProperty(intervalProperty, sampleStart, sampleStop, updateTime, referenceFrame, maximumStep, index, result);
- } else if (intervalProperty instanceof ConstantPositionProperty) {
- index = subSampleConstantProperty(intervalProperty, sampleStart, sampleStop, updateTime, referenceFrame, maximumStep, index, result);
- } else {
- //Fallback to generic sampling.
- index = subSampleGenericProperty(intervalProperty, sampleStart, sampleStop, updateTime, referenceFrame, maximumStep, index, result);
- }
- }
- }
- return index;
- }
- function subSample(property, start, stop, updateTime, referenceFrame, maximumStep, result) {
- if (!defined(result)) {
- result = [];
- }
- if (property instanceof ReferenceProperty) {
- property = property.resolvedProperty;
- }
- var length = 0;
- if (property instanceof SampledPositionProperty) {
- length = subSampleSampledProperty(property, start, stop, updateTime, referenceFrame, maximumStep, 0, result);
- } else if (property instanceof CompositePositionProperty) {
- length = subSampleCompositeProperty(property, start, stop, updateTime, referenceFrame, maximumStep, 0, result);
- } else if (property instanceof TimeIntervalCollectionPositionProperty) {
- length = subSampleIntervalProperty(property, start, stop, updateTime, referenceFrame, maximumStep, 0, result);
- } else if (property instanceof ConstantPositionProperty) {
- length = subSampleConstantProperty(property, start, stop, updateTime, referenceFrame, maximumStep, 0, result);
- } else {
- //Fallback to generic sampling.
- length = subSampleGenericProperty(property, start, stop, updateTime, referenceFrame, maximumStep, 0, result);
- }
- result.length = length;
- return result;
- }
- var toFixedScratch = new Matrix3();
- var PolylineUpdater = function(scene, referenceFrame) {
- this._unusedIndexes = [];
- this._polylineCollection = new PolylineCollection();
- this._scene = scene;
- this._referenceFrame = referenceFrame;
- scene.primitives.add(this._polylineCollection);
- };
- PolylineUpdater.prototype.update = function(time) {
- if (this._referenceFrame === ReferenceFrame.INERTIAL) {
- var toFixed = Transforms.computeIcrfToFixedMatrix(time, toFixedScratch);
- if (!defined(toFixed)) {
- toFixed = Transforms.computeTemeToPseudoFixedMatrix(time, toFixedScratch);
- }
- Matrix4.fromRotationTranslation(toFixed, Cartesian3.ZERO, this._polylineCollection.modelMatrix);
- }
- };
- PolylineUpdater.prototype.updateObject = function(time, item) {
- var entity = item.entity;
- var pathGraphics = entity._path;
- var positionProperty = entity._position;
- var sampleStart;
- var sampleStop;
- var showProperty = pathGraphics._show;
- var polyline = item.polyline;
- var show = !defined(showProperty) || showProperty.getValue(time);
- //While we want to show the path, there may not actually be anything to show
- //depending on lead/trail settings. Compute the interval of the path to
- //show and check against actual availability.
- if (show) {
- var leadTime = Property.getValueOrUndefined(pathGraphics._leadTime, time);
- var trailTime = Property.getValueOrUndefined(pathGraphics._trailTime, time);
- var availability = entity._availability;
- var hasAvailability = defined(availability);
- var hasLeadTime = defined(leadTime);
- var hasTrailTime = defined(trailTime);
- //Objects need to have either defined availability or both a lead and trail time in order to
- //draw a path (since we can't draw "infinite" paths.
- show = hasAvailability || (hasLeadTime && hasTrailTime);
- //The final step is to compute the actual start/stop times of the path to show.
- //If current time is outside of the availability interval, there's a chance that
- //we won't have to draw anything anyway.
- if (show) {
- if (hasTrailTime) {
- sampleStart = JulianDate.addSeconds(time, -trailTime, new JulianDate());
- }
- if (hasLeadTime) {
- sampleStop = JulianDate.addSeconds(time, leadTime, new JulianDate());
- }
- if (hasAvailability) {
- var start = availability.start;
- var stop = availability.stop;
- if (!hasTrailTime || JulianDate.greaterThan(start, sampleStart)) {
- sampleStart = start;
- }
- if (!hasLeadTime || JulianDate.lessThan(stop, sampleStop)) {
- sampleStop = stop;
- }
- }
- show = JulianDate.lessThan(sampleStart, sampleStop);
- }
- }
- if (!show) {
- //don't bother creating or updating anything else
- if (defined(polyline)) {
- this._unusedIndexes.push(item.index);
- item.polyline = undefined;
- polyline.show = false;
- item.index = undefined;
- }
- return;
- }
- if (!defined(polyline)) {
- var unusedIndexes = this._unusedIndexes;
- var length = unusedIndexes.length;
- if (length > 0) {
- var index = unusedIndexes.pop();
- polyline = this._polylineCollection.get(index);
- item.index = index;
- } else {
- item.index = this._polylineCollection.length;
- polyline = this._polylineCollection.add();
- }
- polyline.id = entity;
- item.polyline = polyline;
- }
- var resolution = Property.getValueOrDefault(pathGraphics._resolution, time, defaultResolution);
- polyline.show = true;
- polyline.positions = subSample(positionProperty, sampleStart, sampleStop, time, this._referenceFrame, resolution, polyline.positions);
- polyline.material = MaterialProperty.getValue(time, pathGraphics._material, polyline.material);
- polyline.width = Property.getValueOrDefault(pathGraphics._width, time, defaultWidth);
- };
- PolylineUpdater.prototype.removeObject = function(item) {
- var polyline = item.polyline;
- if (defined(polyline)) {
- this._unusedIndexes.push(item.index);
- item.polyline = undefined;
- polyline.show = false;
- item.index = undefined;
- }
- };
- PolylineUpdater.prototype.destroy = function() {
- this._scene.primitives.remove(this._polylineCollection);
- return destroyObject(this);
- };
- /**
- * A {@link Visualizer} which maps {@link Entity#path} to a {@link Polyline}.
- * @alias PathVisualizer
- * @constructor
- *
- * @param {Scene} scene The scene the primitives will be rendered in.
- * @param {EntityCollection} entityCollection The entityCollection to visualize.
- */
- var PathVisualizer = function(scene, entityCollection) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(scene)) {
- throw new DeveloperError('scene is required.');
- }
- if (!defined(entityCollection)) {
- throw new DeveloperError('entityCollection is required.');
- }
- //>>includeEnd('debug');
- entityCollection.collectionChanged.addEventListener(PathVisualizer.prototype._onCollectionChanged, this);
- this._scene = scene;
- this._updaters = {};
- this._entityCollection = entityCollection;
- this._items = new AssociativeArray();
- this._onCollectionChanged(entityCollection, entityCollection.entities, [], []);
- };
- /**
- * 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} This function always returns true.
- */
- PathVisualizer.prototype.update = function(time) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(time)) {
- throw new DeveloperError('time is required.');
- }
- //>>includeEnd('debug');
- var updaters = this._updaters;
- for ( var key in updaters) {
- if (updaters.hasOwnProperty(key)) {
- updaters[key].update(time);
- }
- }
- var items = this._items.values;
- for (var i = 0, len = items.length; i < len; i++) {
- var item = items[i];
- var entity = item.entity;
- var positionProperty = entity._position;
- var lastUpdater = entity._pathUpdater;
- var frameToVisualize = ReferenceFrame.FIXED;
- if (this._scene.mode === SceneMode.SCENE3D) {
- frameToVisualize = positionProperty.referenceFrame;
- }
- var currentUpdater = this._updaters[frameToVisualize];
- if ((lastUpdater === currentUpdater) && (defined(currentUpdater))) {
- currentUpdater.updateObject(time, item);
- continue;
- }
- if (defined(lastUpdater)) {
- lastUpdater.removeObject(item);
- }
- if (!defined(currentUpdater)) {
- currentUpdater = new PolylineUpdater(this._scene, frameToVisualize);
- currentUpdater.update(time);
- this._updaters[frameToVisualize] = currentUpdater;
- }
- item.updater = currentUpdater;
- if (defined(currentUpdater)) {
- currentUpdater.updateObject(time, item);
- }
- }
- return true;
- };
- /**
- * Returns true if this object was destroyed; otherwise, false.
- *
- * @returns {Boolean} True if this object was destroyed; otherwise, false.
- */
- PathVisualizer.prototype.isDestroyed = function() {
- return false;
- };
- /**
- * Removes and destroys all primitives created by this instance.
- */
- PathVisualizer.prototype.destroy = function() {
- this._entityCollection.collectionChanged.removeEventListener(PathVisualizer.prototype._onCollectionChanged, this);
- var updaters = this._updaters;
- for ( var key in updaters) {
- if (updaters.hasOwnProperty(key)) {
- updaters[key].destroy();
- }
- }
- return destroyObject(this);
- };
- PathVisualizer.prototype._onCollectionChanged = function(entityCollection, added, removed, changed) {
- var i;
- var entity;
- var item;
- var items = this._items;
- for (i = added.length - 1; i > -1; i--) {
- entity = added[i];
- if (defined(entity._path) && defined(entity._position)) {
- items.set(entity.id, new EntityData(entity));
- }
- }
- for (i = changed.length - 1; i > -1; i--) {
- entity = changed[i];
- if (defined(entity._path) && defined(entity._position)) {
- if (!items.contains(entity.id)) {
- items.set(entity.id, new EntityData(entity));
- }
- } else {
- item = items.get(entity.id);
- if (defined(item)) {
- item.updater.removeObject(item);
- items.remove(entity.id);
- }
- }
- }
- for (i = removed.length - 1; i > -1; i--) {
- entity = removed[i];
- item = items.get(entity.id);
- if (defined(item)) {
- item.updater.removeObject(item);
- items.remove(entity.id);
- }
- }
- };
- //for testing
- PathVisualizer._subSample = subSample;
- return PathVisualizer;
- });
|