Skip to content

Commit 03b0a86

Browse files
committed
Add CZML velocity vector orientation support.
* Improve handling of existing alignedAxis velocity support. We now distinguish properties which must produce a unit cartesian (currently only alignedAxis). For those properties, we always normalize on the client to avoid later errors. * Fix velocityReference use from within an interval. Fixes #5738 * Fix promise handling in CzmlDataSourceSpec. Many tests were calling .load without using the resulting promise. This meant that any exceptions during CZML load would be silently ignored.
1 parent baa0890 commit 03b0a86

File tree

3 files changed

+1298
-1076
lines changed

3 files changed

+1298
-1076
lines changed

CHANGES.md

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Change Log
1010
* `Scene/PerspectiveOffCenterFrustum` has been removed. Use `Core/PerspectiveOffCenterFrustum`.
1111
* Added ability to add an animation to `ModelAnimationCollection` by its index. [#5815](https://github.com/AnalyticalGraphicsInc/cesium/pull/5815)
1212
* Fixed a bug in `ModelAnimationCollection` that caused adding an animation by its name to throw an error. [#5815](https://github.com/AnalyticalGraphicsInc/cesium/pull/5815)
13+
* Added support in CZML for expressing `orientation` as the velocity vector of an entity, using `velocityReference` syntax. [#5807](https://github.com/AnalyticalGraphicsInc/cesium/pull/5807)
14+
* Fixed CZML processing of `velocityReference` within an interval. [#5738](https://github.com/AnalyticalGraphicsInc/cesium/issues/5738)
1315
* Zoom about mouse now maintains camera heading, pitch, and roll [#4639](https://github.com/AnalyticalGraphicsInc/cesium/pull/5603)
1416

1517
### 1.37 - 2017-09-01

Source/DataSources/CzmlDataSource.js

+107-53
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ define([
8484
'./StripeOrientation',
8585
'./TimeIntervalCollectionPositionProperty',
8686
'./TimeIntervalCollectionProperty',
87+
'./VelocityOrientationProperty',
8788
'./VelocityVectorProperty',
8889
'./WallGraphics'
8990
], function(
@@ -172,23 +173,53 @@ define([
172173
StripeOrientation,
173174
TimeIntervalCollectionPositionProperty,
174175
TimeIntervalCollectionProperty,
176+
VelocityOrientationProperty,
175177
VelocityVectorProperty,
176178
WallGraphics) {
177179
'use strict';
178180

181+
// A marker type to distinguish CZML properties where we need to end up with a unit vector.
182+
// The data is still loaded into Cartesian3 objects but they are normalized.
183+
function UnitCartesian3() {}
184+
UnitCartesian3.packedLength = Cartesian3.packedLength;
185+
UnitCartesian3.unpack = Cartesian3.unpack;
186+
UnitCartesian3.pack = Cartesian3.pack;
187+
188+
// As a side note, for the purposes of CZML, Quaternion always indicates a unit quaternion.
189+
179190
var currentId;
180191

181-
function makeReference(collection, referenceString) {
192+
function createReferenceProperty(entityCollection, referenceString) {
182193
if (referenceString[0] === '#') {
183194
referenceString = currentId + referenceString;
184195
}
185-
return ReferenceProperty.fromString(collection, referenceString);
196+
return ReferenceProperty.fromString(entityCollection, referenceString);
197+
}
198+
199+
function createSpecializedProperty(type, entityCollection, packetData) {
200+
if (defined(packetData.reference)) {
201+
return createReferenceProperty(entityCollection, packetData.reference);
202+
}
203+
204+
if (defined(packetData.velocityReference)) {
205+
var referenceProperty = createReferenceProperty(entityCollection, packetData.velocityReference);
206+
switch (type) {
207+
case Cartesian3:
208+
case UnitCartesian3:
209+
return new VelocityVectorProperty(referenceProperty, type === UnitCartesian3);
210+
case Quaternion:
211+
return new VelocityOrientationProperty(referenceProperty);
212+
}
213+
}
214+
215+
throw new RuntimeError(JSON.stringify(packetData) + ' is not valid CZML.');
186216
}
187217

188218
var scratchCartesian = new Cartesian3();
189219
var scratchSpherical = new Spherical();
190220
var scratchCartographic = new Cartographic();
191221
var scratchTimeInterval = new TimeInterval();
222+
var scratchQuaternion = new Quaternion();
192223

193224
function unwrapColorInterval(czmlInterval) {
194225
var rgbaf = czmlInterval.rgbaf;
@@ -398,17 +429,30 @@ define([
398429
throw new RuntimeError(JSON.stringify(czmlInterval) + ' is not a valid CZML interval.');
399430
}
400431

432+
function normalizePackedCartesianArray(array, startingIndex) {
433+
Cartesian3.unpack(array, startingIndex, scratchCartesian);
434+
Cartesian3.normalize(scratchCartesian, scratchCartesian);
435+
Cartesian3.pack(scratchCartesian, array, startingIndex);
436+
}
437+
438+
function unwrapUnitCartesianInterval(czmlInterval) {
439+
var cartesian = unwrapCartesianInterval(czmlInterval);
440+
if (cartesian.length === 3) {
441+
normalizePackedCartesianArray(cartesian, 0);
442+
return cartesian;
443+
}
444+
445+
for (var i = 1; i < cartesian.length; i += 4) {
446+
normalizePackedCartesianArray(cartesian, i);
447+
}
448+
449+
return cartesian;
450+
}
451+
401452
function normalizePackedQuaternionArray(array, startingIndex) {
402-
var x = array[startingIndex];
403-
var y = array[startingIndex + 1];
404-
var z = array[startingIndex + 2];
405-
var w = array[startingIndex + 3];
406-
407-
var inverseMagnitude = 1.0 / Math.sqrt(x * x + y * y + z * z + w * w);
408-
array[startingIndex] = x * inverseMagnitude;
409-
array[startingIndex + 1] = y * inverseMagnitude;
410-
array[startingIndex + 2] = z * inverseMagnitude;
411-
array[startingIndex + 3] = w * inverseMagnitude;
453+
Quaternion.unpack(array, startingIndex, scratchQuaternion);
454+
Quaternion.normalize(scratchQuaternion, scratchQuaternion);
455+
Quaternion.pack(scratchQuaternion, array, startingIndex);
412456
}
413457

414458
function unwrapQuaternionInterval(czmlInterval) {
@@ -452,12 +496,13 @@ define([
452496
} else if (czmlInterval.hasOwnProperty('cartesian2')) {
453497
return Cartesian2;
454498
} else if (czmlInterval.hasOwnProperty('cartesian') ||
455-
czmlInterval.hasOwnProperty('unitCartesian') ||
456-
czmlInterval.hasOwnProperty('unitSpherical') ||
457499
czmlInterval.hasOwnProperty('spherical') ||
458500
czmlInterval.hasOwnProperty('cartographicRadians') ||
459501
czmlInterval.hasOwnProperty('cartographicDegrees')) {
460502
return Cartesian3;
503+
} else if (czmlInterval.hasOwnProperty('unitCartesian') ||
504+
czmlInterval.hasOwnProperty('unitSpherical')) {
505+
return UnitCartesian3;
461506
} else if (czmlInterval.hasOwnProperty('rgba') ||
462507
czmlInterval.hasOwnProperty('rgbaf')) {
463508
return Color;
@@ -514,6 +559,8 @@ define([
514559
return czmlInterval.cartesian2;
515560
case Cartesian3:
516561
return unwrapCartesianInterval(czmlInterval);
562+
case UnitCartesian3:
563+
return unwrapUnitCartesianInterval(czmlInterval);
517564
case Color:
518565
return unwrapColorInterval(czmlInterval);
519566
case ColorBlendMode:
@@ -614,10 +661,17 @@ define([
614661
var isSampled;
615662
var unwrappedInterval;
616663
var unwrappedIntervalLength;
617-
var isReference = defined(packetData.reference);
664+
665+
// CZML properties can be defined in many ways. Most ways represent a structure for
666+
// encoding a single value (number, string, cartesian, etc.) Regardless of the value type,
667+
// if it encodes a single value it will get loaded into a ConstantProperty eventually.
668+
// Alternatively, there are ways of defining a property that require specialized
669+
// client-side representation. Currently, these are ReferenceProperty,
670+
// and client-side velocity computation properties such as VelocityVectorProperty.
671+
var isValue = !defined(packetData.reference) && !defined(packetData.velocityReference);
618672
var hasInterval = defined(combinedInterval) && !combinedInterval.equals(Iso8601.MAXIMUM_INTERVAL);
619673

620-
if (!isReference) {
674+
if (isValue) {
621675
unwrappedInterval = unwrapInterval(type, packetData, sourceUri, query);
622676
packedLength = defaultValue(type.packedLength, 1);
623677
unwrappedIntervalLength = defaultValue(unwrappedInterval.length, 1);
@@ -630,12 +684,10 @@ define([
630684

631685
//Any time a constant value is assigned, it completely blows away anything else.
632686
if (!isSampled && !hasInterval) {
633-
if (isReference) {
634-
object[propertyName] = makeReference(entityCollection, packetData.reference);
635-
} else if (needsUnpacking) {
636-
object[propertyName] = new ConstantProperty(type.unpack(unwrappedInterval, 0));
687+
if (isValue) {
688+
object[propertyName] = new ConstantProperty(needsUnpacking ? type.unpack(unwrappedInterval, 0) : unwrappedInterval);
637689
} else {
638-
object[propertyName] = new ConstantProperty(unwrappedInterval);
690+
object[propertyName] = createSpecializedProperty(type, entityCollection, packetData);
639691
}
640692
return;
641693
}
@@ -668,30 +720,30 @@ define([
668720
if (!isSampled && hasInterval) {
669721
//Create a new interval for the constant value.
670722
combinedInterval = combinedInterval.clone();
671-
if (isReference) {
672-
combinedInterval.data = makeReference(entityCollection, packetData.reference);
673-
} else if (needsUnpacking) {
674-
combinedInterval.data = type.unpack(unwrappedInterval, 0);
723+
if (isValue) {
724+
combinedInterval.data = needsUnpacking ? type.unpack(unwrappedInterval, 0) : unwrappedInterval;
675725
} else {
676-
combinedInterval.data = unwrappedInterval;
726+
combinedInterval.data = createSpecializedProperty(type, entityCollection, packetData);
677727
}
678728

679729
//If no property exists, simply use a new interval collection
680730
if (!defined(property)) {
681-
if (isReference) {
682-
property = new CompositeProperty();
683-
} else {
731+
if (isValue) {
684732
property = new TimeIntervalCollectionProperty();
733+
} else {
734+
property = new CompositeProperty();
685735
}
686736
object[propertyName] = property;
687737
}
688738

689-
if (!isReference && property instanceof TimeIntervalCollectionProperty) {
739+
if (isValue && property instanceof TimeIntervalCollectionProperty) {
690740
//If we create a collection, or it already existed, use it.
691741
property.intervals.addInterval(combinedInterval);
692742
} else if (property instanceof CompositeProperty) {
693743
//If the collection was already a CompositeProperty, use it.
694-
combinedInterval.data = isReference ? combinedInterval.data : new ConstantProperty(combinedInterval.data);
744+
if (isValue) {
745+
combinedInterval.data = new ConstantProperty(combinedInterval.data);
746+
}
695747
property.intervals.addInterval(combinedInterval);
696748
} else {
697749
//Otherwise, create a CompositeProperty but preserve the existing data.
@@ -708,7 +760,9 @@ define([
708760
property.intervals.addInterval(interval);
709761

710762
//Change the new data to a ConstantProperty and add it.
711-
combinedInterval.data = isReference ? combinedInterval.data : new ConstantProperty(combinedInterval.data);
763+
if (isValue) {
764+
combinedInterval.data = new ConstantProperty(combinedInterval.data);
765+
}
712766
property.intervals.addInterval(combinedInterval);
713767
}
714768

@@ -781,10 +835,10 @@ define([
781835
var unwrappedIntervalLength;
782836
var numberOfDerivatives = defined(packetData.cartesianVelocity) ? 1 : 0;
783837
var packedLength = Cartesian3.packedLength * (numberOfDerivatives + 1);
784-
var isReference = defined(packetData.reference);
838+
var isValue = !defined(packetData.reference);
785839
var hasInterval = defined(combinedInterval) && !combinedInterval.equals(Iso8601.MAXIMUM_INTERVAL);
786840

787-
if (!isReference) {
841+
if (isValue) {
788842
if (defined(packetData.referenceFrame)) {
789843
referenceFrame = ReferenceFrame[packetData.referenceFrame];
790844
}
@@ -796,10 +850,10 @@ define([
796850

797851
//Any time a constant value is assigned, it completely blows away anything else.
798852
if (!isSampled && !hasInterval) {
799-
if (isReference) {
800-
object[propertyName] = makeReference(entityCollection, packetData.reference);
801-
} else {
853+
if (isValue) {
802854
object[propertyName] = new ConstantPositionProperty(Cartesian3.unpack(unwrappedInterval), referenceFrame);
855+
} else {
856+
object[propertyName] = createReferenceProperty(entityCollection, packetData.reference);
803857
}
804858
return;
805859
}
@@ -832,28 +886,30 @@ define([
832886
if (!isSampled && hasInterval) {
833887
//Create a new interval for the constant value.
834888
combinedInterval = combinedInterval.clone();
835-
if (isReference) {
836-
combinedInterval.data = makeReference(entityCollection, packetData.reference);
837-
} else {
889+
if (isValue) {
838890
combinedInterval.data = Cartesian3.unpack(unwrappedInterval);
891+
} else {
892+
combinedInterval.data = createReferenceProperty(entityCollection, packetData.reference);
839893
}
840894

841895
//If no property exists, simply use a new interval collection
842896
if (!defined(property)) {
843-
if (isReference) {
844-
property = new CompositePositionProperty(referenceFrame);
845-
} else {
897+
if (isValue) {
846898
property = new TimeIntervalCollectionPositionProperty(referenceFrame);
899+
} else {
900+
property = new CompositePositionProperty(referenceFrame);
847901
}
848902
object[propertyName] = property;
849903
}
850904

851-
if (!isReference && property instanceof TimeIntervalCollectionPositionProperty && (defined(referenceFrame) && property.referenceFrame === referenceFrame)) {
905+
if (isValue && property instanceof TimeIntervalCollectionPositionProperty && (defined(referenceFrame) && property.referenceFrame === referenceFrame)) {
852906
//If we create a collection, or it already existed, use it.
853907
property.intervals.addInterval(combinedInterval);
854908
} else if (property instanceof CompositePositionProperty) {
855909
//If the collection was already a CompositePositionProperty, use it.
856-
combinedInterval.data = isReference ? combinedInterval.data : new ConstantPositionProperty(combinedInterval.data, referenceFrame);
910+
if (isValue) {
911+
combinedInterval.data = new ConstantPositionProperty(combinedInterval.data, referenceFrame);
912+
}
857913
property.intervals.addInterval(combinedInterval);
858914
} else {
859915
//Otherwise, create a CompositePositionProperty but preserve the existing data.
@@ -870,7 +926,9 @@ define([
870926
property.intervals.addInterval(interval);
871927

872928
//Change the new data to a ConstantPositionProperty and add it.
873-
combinedInterval.data = isReference ? combinedInterval.data : new ConstantPositionProperty(combinedInterval.data, referenceFrame);
929+
if (isValue) {
930+
combinedInterval.data = new ConstantPositionProperty(combinedInterval.data, referenceFrame);
931+
}
874932
property.intervals.addInterval(combinedInterval);
875933
}
876934

@@ -1117,7 +1175,7 @@ define([
11171175
var references = packetData.references;
11181176
if (defined(references)) {
11191177
var properties = references.map(function(reference) {
1120-
return makeReference(entityCollection, reference);
1178+
return createReferenceProperty(entityCollection, reference);
11211179
});
11221180

11231181
var iso8601Interval = packetData.interval;
@@ -1154,7 +1212,7 @@ define([
11541212
function processPositionsPacketData(object, propertyName, positionsData, entityCollection) {
11551213
if (defined(positionsData.references)) {
11561214
var properties = positionsData.references.map(function(reference) {
1157-
return makeReference(entityCollection, reference);
1215+
return createReferenceProperty(entityCollection, reference);
11581216
});
11591217

11601218
var iso8601Interval = positionsData.interval;
@@ -1230,11 +1288,7 @@ define([
12301288
return;
12311289
}
12321290

1233-
if (defined(packetData.velocityReference)) {
1234-
billboard.alignedAxis = new VelocityVectorProperty(makeReference(entityCollection, packetData.velocityReference), true);
1235-
} else {
1236-
processPacketData(Cartesian3, billboard, 'alignedAxis', packetData, interval, sourceUri, entityCollection, query);
1237-
}
1291+
processPacketData(UnitCartesian3, billboard, 'alignedAxis', packetData, interval, sourceUri, entityCollection, query);
12381292
}
12391293

12401294
function processBillboard(entity, packet, entityCollection, sourceUri, query) {

0 commit comments

Comments
 (0)