Skip to content

Commit

Permalink
frame changed event, ready promise, and other updates
Browse files Browse the repository at this point in the history
  • Loading branch information
lilleyse committed Jul 10, 2018
1 parent adf8f4e commit 5476619
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 31 deletions.
4 changes: 2 additions & 2 deletions Apps/Sandcastle/gallery/Time Dynamic Point Cloud.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="description" content="Time Dynamic Point Cloud">
<meta name="cesium-sandcastle-labels" content="Showcases, 3D Tiles">
<meta name="description" content="Render a time dynamic point cloud from a set of Point Cloud tiles and timestamps.">
<meta name="cesium-sandcastle-labels" content="Showcases">
<title>Cesium Demo</title>
<script type="text/javascript" src="../Sandcastle-header.js"></script>
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.20/require.js"></script>
Expand Down
Binary file modified Apps/Sandcastle/gallery/Time Dynamic Point Cloud.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 6 additions & 8 deletions Source/Scene/Cesium3DTileset.js
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,12 @@ define([
* <p>
* If there are no event listeners, error messages will be logged to the console.
* </p>
* <p>
* The error object passed to the listener contains two properties:
* <ul>
* <li><code>url</code>: the url of the failed tile.</li>
* <li><code>message</code>: the error message.</li>
* </ul>
*
* @type {Event}
* @default new Event()
Expand Down Expand Up @@ -1839,14 +1845,6 @@ define([

///////////////////////////////////////////////////////////////////////////

/**
* Called when {@link Viewer} or {@link CesiumWidget} render the scene to
* get the draw commands needed to render this primitive.
* <p>
* Do not call this function directly. This is documented just to
* list the exceptions that may be propagated when the scene is rendered:
* </p>
*/
Cesium3DTileset.prototype.update = function(frameState) {
if (frameState.mode === SceneMode.MORPHING) {
return;
Expand Down
19 changes: 17 additions & 2 deletions Source/Scene/PointCloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -475,16 +475,31 @@ define([
var scratchMin = new Cartesian3();
var scratchMax = new Cartesian3();
var scratchPosition = new Cartesian3();
var randomValues;

function getRandomValues(samplesLength) {
// Use same random values across all runs
if (!defined(randomValues)) {
CesiumMath.setRandomNumberSeed(0);
randomValues = new Array(20);
for (var i = 0; i < samplesLength; ++i) {
randomValues[i] = CesiumMath.nextRandomNumber();
}
}
return randomValues;
}

function computeApproximateBoundingSphereFromPositions(positions) {
var maximumSamplesLength = 20;
var pointsLength = positions.length / 3;
var samplesLength = Math.min(pointsLength, 20);
var samplesLength = Math.min(pointsLength, maximumSamplesLength);
var randomValues = getRandomValues(maximumSamplesLength);
var maxValue = Number.MAX_VALUE;
var minValue = -Number.MAX_VALUE;
var min = Cartesian3.fromElements(maxValue, maxValue, maxValue, scratchMin);
var max = Cartesian3.fromElements(minValue, minValue, minValue, scratchMax);
for (var i = 0; i < samplesLength; ++i) {
var index = Math.floor(i * pointsLength / samplesLength);
var index = Math.floor(randomValues[i] * pointsLength);
var position = Cartesian3.unpack(positions, index * 3, scratchPosition);
Cartesian3.minimumByComponent(min, position, min);
Cartesian3.maximumByComponent(max, position, max);
Expand Down
4 changes: 2 additions & 2 deletions Source/Scene/TimeDynamicImagery.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ define([
* @constructor
*
* @param {Object} options Object with the following properties:
* @param {Clock} options.clock A Clock instance that is used when determining the value for the time dimension. Required when options.times is specified.
* @param {TimeIntervalCollection} options.times TimeIntervalCollection with its data property being an object containing time dynamic dimension and their values.
* @param {Clock} options.clock A Clock instance that is used when determining the value for the time dimension. Required when <code>options.times</code> is specified.
* @param {TimeIntervalCollection} options.times TimeIntervalCollection with its <code>data</code> property being an object containing time dynamic dimension and their values.
* @param {Function} options.requestImageFunction A function that will request imagery tiles.
* @param {Function} options.reloadFunction A function that will be called when all imagery tiles need to be reloaded.
*/
Expand Down
65 changes: 55 additions & 10 deletions Source/Scene/TimeDynamicPointCloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ define([
'../Core/Math',
'../Core/Matrix4',
'../Core/Resource',
'../ThirdParty/when',
'./ClippingPlaneCollection',
'./PointCloud',
'./PointCloudEyeDomeLighting',
Expand All @@ -32,6 +33,7 @@ define([
CesiumMath,
Matrix4,
Resource,
when,
ClippingPlaneCollection,
PointCloud,
PointCloudEyeDomeLighting,
Expand Down Expand Up @@ -155,18 +157,39 @@ define([
* <p>
* If there are no event listeners, error messages will be logged to the console.
* </p>
* <p>
* The error object passed to the listener contains two properties:
* <ul>
* <li><code>uri</code>: the uri of the failed frame.</li>
* <li><code>message</code>: the error message.</li>
* </ul>
*
* @type {Event}
* @default new Event()
*
* @example
* pointCloud.frameFailed.addEventListener(function(error) {
* console.log('An error occurred loading frame: ' + error.url);
* console.log('An error occurred loading frame: ' + error.uri);
* console.log('Error: ' + error.message);
* });
*/
this.frameFailed = new Event();

/**
* The event fired to indicate that a new frame was rendered.
* <p>
* The time dynamic point cloud {@link TimeDynamicPointCloud} is passed to the event listener.
* </p>
* @type {Event}
* @default new Event()
*
* @example
* pointCloud.frameChanged.addEventListener(function(timeDynamicPointCloud) {
* viewer.camera.viewBoundingSphere(timeDynamicPointCloud.boundingSphere);
* });
*/
this.frameChanged = new Event();

this._clock = options.clock;
this._intervals = options.intervals;
this._clippingPlanes = undefined;
Expand All @@ -182,6 +205,7 @@ define([
this._nextInterval = undefined;
this._lastRenderedFrame = undefined;
this._clockMultiplier = 0.0;
this._readyPromise = when.defer();

// For calculating average load time of the last N frames
this._runningSum = 0.0;
Expand Down Expand Up @@ -238,6 +262,20 @@ define([
return this._lastRenderedFrame.pointCloud.boundingSphere;
}
}
},

/**
* Gets the promise that will be resolved when the point cloud renders a frame for the first time.
*
* @memberof TimeDynamicPointCloud.prototype
*
* @type {Promise.<TimeDynamicPointCloud>}
* @readonly
*/
readyPromise : {
get : function() {
return this._readyPromise.promise;
}
}
});

Expand Down Expand Up @@ -345,7 +383,7 @@ define([
var message = defined(error.message) ? error.message : error.toString();
if (that.frameFailed.numberOfListeners > 0) {
that.frameFailed.raiseEvent({
url : uri,
uri : uri,
message : message
});
} else {
Expand Down Expand Up @@ -576,14 +614,6 @@ define([
clippingPlanesDirty : false
};

/**
* Called when {@link Viewer} or {@link CesiumWidget} render the scene to
* get the draw commands needed to render this primitive.
* <p>
* Do not call this function directly. This is documented just to
* list the exceptions that may be propagated when the scene is rendered:
* </p>
*/
TimeDynamicPointCloud.prototype.update = function(frameState) {
if (frameState.mode === SceneMode.MORPHING) {
return;
Expand Down Expand Up @@ -681,6 +711,21 @@ define([
loadFrame(this, nextInterval, updateState, frameState);
}

var that = this;
if (defined(frame) && !defined(this._lastRenderedFrame)) {
frameState.afterRender.push(function() {
that._readyPromise.resolve(that);
});
}

if (defined(frame) && (frame !== this._lastRenderedFrame)) {
if (that.frameChanged.numberOfListeners > 0) {
frameState.afterRender.push(function() {
that.frameChanged.raiseEvent(that);
});
}
}

this._previousInterval = previousInterval;
this._nextInterval = nextInterval;
this._lastRenderedFrame = frame;
Expand Down
2 changes: 1 addition & 1 deletion Source/Scene/WebMapTileServiceImageryProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ define([
* @param {String} options.tileMatrixSetID The identifier of the TileMatrixSet to use for WMTS requests.
* @param {Array} [options.tileMatrixLabels] A list of identifiers in the TileMatrix to use for WMTS requests, one per TileMatrix level.
* @param {Clock} [options.clock] A Clock instance that is used when determining the value for the time dimension. Required when options.times is specified.
* @param {TimeIntervalCollection} [options.times] TimeIntervalCollection with its data property being an object containing time dynamic dimension and their values.
* @param {TimeIntervalCollection} [options.times] TimeIntervalCollection with its <code>data</code> property being an object containing time dynamic dimension and their values.
* @param {Object} [options.dimensions] A object containing static dimensions and their values.
* @param {Number} [options.tileWidth=256] The tile width in pixels.
* @param {Number} [options.tileHeight=256] The tile height in pixels.
Expand Down
7 changes: 3 additions & 4 deletions Source/Widgets/Viewer/Viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1938,9 +1938,9 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to

// If zoomTarget was TimeDynamicPointCloud
if (target instanceof TimeDynamicPointCloud) {
boundingSphere = target.boundingSphere;
if (defined(boundingSphere)) {
return target.readyPromise.then(function() {
// If offset was originally undefined then give it base value instead of empty object
var boundingSphere = target.boundingSphere;
if (!defined(zoomOptions.offset)) {
zoomOptions.offset = new HeadingPitchRange(0.0, -0.5, boundingSphere.radius);
}
Expand Down Expand Up @@ -1968,8 +1968,7 @@ Either specify options.terrainProvider instead or set options.baseLayerPicker to
}

clearZoom(viewer);
}
return;
});
}

// If zoomTarget was an ImageryLayer
Expand Down
40 changes: 38 additions & 2 deletions Specs/Scene/TimeDynamicPointCloudSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,15 @@ defineSuite([
});
});

it('resolves ready promise', function() {
var pointCloud = createTimeDynamicPointCloud();
return loadFrame(pointCloud).then(function() {
return pointCloud.readyPromise.then(function(pointCloud) {
expect(pointCloud.boundingSphere).toBeDefined();
});
});
});

it('sets show', function() {
var pointCloud = createTimeDynamicPointCloud();

Expand Down Expand Up @@ -705,7 +714,7 @@ defineSuite([
for (i = 0; i < 5; ++i) {
var arg = spyUpdate.calls.argsFor(i)[0];
expect(arg).toBeDefined();
expect(arg.url).toContain(i + '.pnts');
expect(arg.uri).toContain(i + '.pnts');
expect(arg.message).toBe('404');
}
});
Expand Down Expand Up @@ -735,12 +744,39 @@ defineSuite([
}).then(function() {
var arg = spyUpdate.calls.argsFor(0)[0];
expect(arg).toBeDefined();
expect(arg.url).toContain('1.pnts');
expect(arg.uri).toContain('1.pnts');
expect(arg.message).toBe('my error');
});
});
});

it('raises frame changed event', function() {
var pointCloud = createTimeDynamicPointCloud();
var spyFrameChanged = jasmine.createSpy('listener');
pointCloud.frameChanged.addEventListener(spyFrameChanged);

return loadAllFrames(pointCloud).then(function() {
expect(spyFrameChanged.calls.count()).toBe(5);

// Go to random frame
goToFrame(2);
scene.renderForSpecs();
expect(spyFrameChanged.calls.count()).toBe(6);

// Go out of range. No event raised.
clock.currentTime = JulianDate.addSeconds(dates[0], -10.0, new JulianDate());
scene.renderForSpecs();
expect(spyFrameChanged.calls.count()).toBe(6);

goToFrame(0);
scene.renderForSpecs();
expect(spyFrameChanged.calls.count()).toBe(7);

expect(spyFrameChanged.calls.argsFor(0)[0]).toBe(pointCloud);
});

});

it('destroys', function() {
var pointCloud = createTimeDynamicPointCloud();
return loadAllFrames(pointCloud).then(function() {
Expand Down

0 comments on commit 5476619

Please sign in to comment.