cesium
Version:
CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.
1,064 lines (951 loc) • 121 kB
JavaScript
import ArcType from '../Core/ArcType.js';
import BoundingRectangle from '../Core/BoundingRectangle.js';
import Cartesian2 from '../Core/Cartesian2.js';
import Cartesian3 from '../Core/Cartesian3.js';
import Cartographic from '../Core/Cartographic.js';
import ClockRange from '../Core/ClockRange.js';
import ClockStep from '../Core/ClockStep.js';
import Color from '../Core/Color.js';
import CornerType from '../Core/CornerType.js';
import Credit from '../Core/Credit.js';
import createGuid from '../Core/createGuid.js';
import defaultValue from '../Core/defaultValue.js';
import defined from '../Core/defined.js';
import DeveloperError from '../Core/DeveloperError.js';
import DistanceDisplayCondition from '../Core/DistanceDisplayCondition.js';
import Ellipsoid from '../Core/Ellipsoid.js';
import Event from '../Core/Event.js';
import ExtrapolationType from '../Core/ExtrapolationType.js';
import getFilenameFromUri from '../Core/getFilenameFromUri.js';
import HermitePolynomialApproximation from '../Core/HermitePolynomialApproximation.js';
import Iso8601 from '../Core/Iso8601.js';
import JulianDate from '../Core/JulianDate.js';
import LagrangePolynomialApproximation from '../Core/LagrangePolynomialApproximation.js';
import LinearApproximation from '../Core/LinearApproximation.js';
import CesiumMath from '../Core/Math.js';
import NearFarScalar from '../Core/NearFarScalar.js';
import PolygonHierarchy from '../Core/PolygonHierarchy.js';
import Quaternion from '../Core/Quaternion.js';
import Rectangle from '../Core/Rectangle.js';
import ReferenceFrame from '../Core/ReferenceFrame.js';
import Resource from '../Core/Resource.js';
import RuntimeError from '../Core/RuntimeError.js';
import Spherical from '../Core/Spherical.js';
import TimeInterval from '../Core/TimeInterval.js';
import TimeIntervalCollection from '../Core/TimeIntervalCollection.js';
import ClassificationType from '../Scene/ClassificationType.js';
import ColorBlendMode from '../Scene/ColorBlendMode.js';
import HeightReference from '../Scene/HeightReference.js';
import HorizontalOrigin from '../Scene/HorizontalOrigin.js';
import LabelStyle from '../Scene/LabelStyle.js';
import ShadowMode from '../Scene/ShadowMode.js';
import VerticalOrigin from '../Scene/VerticalOrigin.js';
import Uri from '../ThirdParty/Uri.js';
import when from '../ThirdParty/when.js';
import BillboardGraphics from './BillboardGraphics.js';
import BoxGraphics from './BoxGraphics.js';
import CallbackProperty from './CallbackProperty.js';
import CheckerboardMaterialProperty from './CheckerboardMaterialProperty.js';
import ColorMaterialProperty from './ColorMaterialProperty.js';
import CompositeMaterialProperty from './CompositeMaterialProperty.js';
import CompositePositionProperty from './CompositePositionProperty.js';
import CompositeProperty from './CompositeProperty.js';
import ConstantPositionProperty from './ConstantPositionProperty.js';
import ConstantProperty from './ConstantProperty.js';
import CorridorGraphics from './CorridorGraphics.js';
import CylinderGraphics from './CylinderGraphics.js';
import DataSource from './DataSource.js';
import DataSourceClock from './DataSourceClock.js';
import EllipseGraphics from './EllipseGraphics.js';
import EllipsoidGraphics from './EllipsoidGraphics.js';
import EntityCluster from './EntityCluster.js';
import EntityCollection from './EntityCollection.js';
import GridMaterialProperty from './GridMaterialProperty.js';
import ImageMaterialProperty from './ImageMaterialProperty.js';
import LabelGraphics from './LabelGraphics.js';
import ModelGraphics from './ModelGraphics.js';
import NodeTransformationProperty from './NodeTransformationProperty.js';
import PathGraphics from './PathGraphics.js';
import PointGraphics from './PointGraphics.js';
import PolygonGraphics from './PolygonGraphics.js';
import PolylineArrowMaterialProperty from './PolylineArrowMaterialProperty.js';
import PolylineDashMaterialProperty from './PolylineDashMaterialProperty.js';
import PolylineGlowMaterialProperty from './PolylineGlowMaterialProperty.js';
import PolylineGraphics from './PolylineGraphics.js';
import PolylineOutlineMaterialProperty from './PolylineOutlineMaterialProperty.js';
import PositionPropertyArray from './PositionPropertyArray.js';
import Property from './Property.js';
import PropertyArray from './PropertyArray.js';
import PropertyBag from './PropertyBag.js';
import RectangleGraphics from './RectangleGraphics.js';
import ReferenceProperty from './ReferenceProperty.js';
import Rotation from './Rotation.js';
import SampledPositionProperty from './SampledPositionProperty.js';
import SampledProperty from './SampledProperty.js';
import StripeMaterialProperty from './StripeMaterialProperty.js';
import StripeOrientation from './StripeOrientation.js';
import TimeIntervalCollectionPositionProperty from './TimeIntervalCollectionPositionProperty.js';
import TimeIntervalCollectionProperty from './TimeIntervalCollectionProperty.js';
import VelocityOrientationProperty from './VelocityOrientationProperty.js';
import VelocityVectorProperty from './VelocityVectorProperty.js';
import WallGraphics from './WallGraphics.js';
import Cesium3DTilesetGraphics from './Cesium3DTilesetGraphics.js';
// A marker type to distinguish CZML properties where we need to end up with a unit vector.
// The data is still loaded into Cartesian3 objects but they are normalized.
function UnitCartesian3() {}
UnitCartesian3.packedLength = Cartesian3.packedLength;
UnitCartesian3.unpack = Cartesian3.unpack;
UnitCartesian3.pack = Cartesian3.pack;
// As a side note, for the purposes of CZML, Quaternion always indicates a unit quaternion.
var currentId;
function createReferenceProperty(entityCollection, referenceString) {
if (referenceString[0] === '#') {
referenceString = currentId + referenceString;
}
return ReferenceProperty.fromString(entityCollection, referenceString);
}
function createSpecializedProperty(type, entityCollection, packetData) {
if (defined(packetData.reference)) {
return createReferenceProperty(entityCollection, packetData.reference);
}
if (defined(packetData.velocityReference)) {
var referenceProperty = createReferenceProperty(entityCollection, packetData.velocityReference);
switch (type) {
case Cartesian3:
case UnitCartesian3:
return new VelocityVectorProperty(referenceProperty, type === UnitCartesian3);
case Quaternion:
return new VelocityOrientationProperty(referenceProperty);
}
}
throw new RuntimeError(JSON.stringify(packetData) + ' is not valid CZML.');
}
function createAdapterProperty(property, adapterFunction) {
return new CallbackProperty(function(time, result) {
return adapterFunction(property.getValue(time, result));
}, property.isConstant);
}
var scratchCartesian = new Cartesian3();
var scratchSpherical = new Spherical();
var scratchCartographic = new Cartographic();
var scratchTimeInterval = new TimeInterval();
var scratchQuaternion = new Quaternion();
function unwrapColorInterval(czmlInterval) {
var rgbaf = czmlInterval.rgbaf;
if (defined(rgbaf)) {
return rgbaf;
}
var rgba = czmlInterval.rgba;
if (!defined(rgba)) {
return undefined;
}
var length = rgba.length;
if (length === Color.packedLength) {
return [Color.byteToFloat(rgba[0]), Color.byteToFloat(rgba[1]), Color.byteToFloat(rgba[2]), Color.byteToFloat(rgba[3])];
}
rgbaf = new Array(length);
for (var i = 0; i < length; i += 5) {
rgbaf[i] = rgba[i];
rgbaf[i + 1] = Color.byteToFloat(rgba[i + 1]);
rgbaf[i + 2] = Color.byteToFloat(rgba[i + 2]);
rgbaf[i + 3] = Color.byteToFloat(rgba[i + 3]);
rgbaf[i + 4] = Color.byteToFloat(rgba[i + 4]);
}
return rgbaf;
}
function unwrapUriInterval(czmlInterval, sourceUri) {
var uri = defaultValue(czmlInterval.uri, czmlInterval);
if (defined(sourceUri)) {
return sourceUri.getDerivedResource({
url: uri
});
}
return Resource.createIfNeeded(uri);
}
function unwrapRectangleInterval(czmlInterval) {
var wsen = czmlInterval.wsen;
if (defined(wsen)) {
return wsen;
}
var wsenDegrees = czmlInterval.wsenDegrees;
if (!defined(wsenDegrees)) {
return undefined;
}
var length = wsenDegrees.length;
if (length === Rectangle.packedLength) {
return [CesiumMath.toRadians(wsenDegrees[0]), CesiumMath.toRadians(wsenDegrees[1]), CesiumMath.toRadians(wsenDegrees[2]), CesiumMath.toRadians(wsenDegrees[3])];
}
wsen = new Array(length);
for (var i = 0; i < length; i += 5) {
wsen[i] = wsenDegrees[i];
wsen[i + 1] = CesiumMath.toRadians(wsenDegrees[i + 1]);
wsen[i + 2] = CesiumMath.toRadians(wsenDegrees[i + 2]);
wsen[i + 3] = CesiumMath.toRadians(wsenDegrees[i + 3]);
wsen[i + 4] = CesiumMath.toRadians(wsenDegrees[i + 4]);
}
return wsen;
}
function convertUnitSphericalToCartesian(unitSpherical) {
var length = unitSpherical.length;
scratchSpherical.magnitude = 1.0;
if (length === 2) {
scratchSpherical.clock = unitSpherical[0];
scratchSpherical.cone = unitSpherical[1];
Cartesian3.fromSpherical(scratchSpherical, scratchCartesian);
return [scratchCartesian.x, scratchCartesian.y, scratchCartesian.z];
}
var result = new Array(length / 3 * 4);
for (var i = 0, j = 0; i < length; i += 3, j += 4) {
result[j] = unitSpherical[i];
scratchSpherical.clock = unitSpherical[i + 1];
scratchSpherical.cone = unitSpherical[i + 2];
Cartesian3.fromSpherical(scratchSpherical, scratchCartesian);
result[j + 1] = scratchCartesian.x;
result[j + 2] = scratchCartesian.y;
result[j + 3] = scratchCartesian.z;
}
return result;
}
function convertSphericalToCartesian(spherical) {
var length = spherical.length;
if (length === 3) {
scratchSpherical.clock = spherical[0];
scratchSpherical.cone = spherical[1];
scratchSpherical.magnitude = spherical[2];
Cartesian3.fromSpherical(scratchSpherical, scratchCartesian);
return [scratchCartesian.x, scratchCartesian.y, scratchCartesian.z];
}
var result = new Array(length);
for (var i = 0; i < length; i += 4) {
result[i] = spherical[i];
scratchSpherical.clock = spherical[i + 1];
scratchSpherical.cone = spherical[i + 2];
scratchSpherical.magnitude = spherical[i + 3];
Cartesian3.fromSpherical(scratchSpherical, scratchCartesian);
result[i + 1] = scratchCartesian.x;
result[i + 2] = scratchCartesian.y;
result[i + 3] = scratchCartesian.z;
}
return result;
}
function convertCartographicRadiansToCartesian(cartographicRadians) {
var length = cartographicRadians.length;
if (length === 3) {
scratchCartographic.longitude = cartographicRadians[0];
scratchCartographic.latitude = cartographicRadians[1];
scratchCartographic.height = cartographicRadians[2];
Ellipsoid.WGS84.cartographicToCartesian(scratchCartographic, scratchCartesian);
return [scratchCartesian.x, scratchCartesian.y, scratchCartesian.z];
}
var result = new Array(length);
for (var i = 0; i < length; i += 4) {
result[i] = cartographicRadians[i];
scratchCartographic.longitude = cartographicRadians[i + 1];
scratchCartographic.latitude = cartographicRadians[i + 2];
scratchCartographic.height = cartographicRadians[i + 3];
Ellipsoid.WGS84.cartographicToCartesian(scratchCartographic, scratchCartesian);
result[i + 1] = scratchCartesian.x;
result[i + 2] = scratchCartesian.y;
result[i + 3] = scratchCartesian.z;
}
return result;
}
function convertCartographicDegreesToCartesian(cartographicDegrees) {
var length = cartographicDegrees.length;
if (length === 3) {
scratchCartographic.longitude = CesiumMath.toRadians(cartographicDegrees[0]);
scratchCartographic.latitude = CesiumMath.toRadians(cartographicDegrees[1]);
scratchCartographic.height = cartographicDegrees[2];
Ellipsoid.WGS84.cartographicToCartesian(scratchCartographic, scratchCartesian);
return [scratchCartesian.x, scratchCartesian.y, scratchCartesian.z];
}
var result = new Array(length);
for (var i = 0; i < length; i += 4) {
result[i] = cartographicDegrees[i];
scratchCartographic.longitude = CesiumMath.toRadians(cartographicDegrees[i + 1]);
scratchCartographic.latitude = CesiumMath.toRadians(cartographicDegrees[i + 2]);
scratchCartographic.height = cartographicDegrees[i + 3];
Ellipsoid.WGS84.cartographicToCartesian(scratchCartographic, scratchCartesian);
result[i + 1] = scratchCartesian.x;
result[i + 2] = scratchCartesian.y;
result[i + 3] = scratchCartesian.z;
}
return result;
}
function unwrapCartesianInterval(czmlInterval) {
var cartesian = czmlInterval.cartesian;
if (defined(cartesian)) {
return cartesian;
}
var cartesianVelocity = czmlInterval.cartesianVelocity;
if (defined(cartesianVelocity)) {
return cartesianVelocity;
}
var unitCartesian = czmlInterval.unitCartesian;
if (defined(unitCartesian)) {
return unitCartesian;
}
var unitSpherical = czmlInterval.unitSpherical;
if (defined(unitSpherical)) {
return convertUnitSphericalToCartesian(unitSpherical);
}
var spherical = czmlInterval.spherical;
if (defined(spherical)) {
return convertSphericalToCartesian(spherical);
}
var cartographicRadians = czmlInterval.cartographicRadians;
if (defined(cartographicRadians)) {
return convertCartographicRadiansToCartesian(cartographicRadians);
}
var cartographicDegrees = czmlInterval.cartographicDegrees;
if (defined(cartographicDegrees)) {
return convertCartographicDegreesToCartesian(cartographicDegrees);
}
throw new RuntimeError(JSON.stringify(czmlInterval) + ' is not a valid CZML interval.');
}
function normalizePackedCartesianArray(array, startingIndex) {
Cartesian3.unpack(array, startingIndex, scratchCartesian);
Cartesian3.normalize(scratchCartesian, scratchCartesian);
Cartesian3.pack(scratchCartesian, array, startingIndex);
}
function unwrapUnitCartesianInterval(czmlInterval) {
var cartesian = unwrapCartesianInterval(czmlInterval);
if (cartesian.length === 3) {
normalizePackedCartesianArray(cartesian, 0);
return cartesian;
}
for (var i = 1; i < cartesian.length; i += 4) {
normalizePackedCartesianArray(cartesian, i);
}
return cartesian;
}
function normalizePackedQuaternionArray(array, startingIndex) {
Quaternion.unpack(array, startingIndex, scratchQuaternion);
Quaternion.normalize(scratchQuaternion, scratchQuaternion);
Quaternion.pack(scratchQuaternion, array, startingIndex);
}
function unwrapQuaternionInterval(czmlInterval) {
var unitQuaternion = czmlInterval.unitQuaternion;
if (defined(unitQuaternion)) {
if (unitQuaternion.length === 4) {
normalizePackedQuaternionArray(unitQuaternion, 0);
return unitQuaternion;
}
for (var i = 1; i < unitQuaternion.length; i += 5) {
normalizePackedQuaternionArray(unitQuaternion, i);
}
}
return unitQuaternion;
}
function getPropertyType(czmlInterval) {
// The associations in this function need to be kept in sync with the
// associations in unwrapInterval.
// Intentionally omitted due to conficts in CZML property names:
// * Image (conflicts with Uri)
// * Rotation (conflicts with Number)
//
// cartesianVelocity is also omitted due to incomplete support for
// derivative information in CZML properties.
// (Currently cartesianVelocity is hacked directly into the position processing code)
if (typeof czmlInterval === 'boolean') {
return Boolean;
} else if (typeof czmlInterval === 'number') {
return Number;
} else if (typeof czmlInterval === 'string') {
return String;
} else if (czmlInterval.hasOwnProperty('array')) {
return Array;
} else if (czmlInterval.hasOwnProperty('boolean')) {
return Boolean;
} else if (czmlInterval.hasOwnProperty('boundingRectangle')) {
return BoundingRectangle;
} else if (czmlInterval.hasOwnProperty('cartesian2')) {
return Cartesian2;
} else if (czmlInterval.hasOwnProperty('cartesian') ||
czmlInterval.hasOwnProperty('spherical') ||
czmlInterval.hasOwnProperty('cartographicRadians') ||
czmlInterval.hasOwnProperty('cartographicDegrees')) {
return Cartesian3;
} else if (czmlInterval.hasOwnProperty('unitCartesian') ||
czmlInterval.hasOwnProperty('unitSpherical')) {
return UnitCartesian3;
} else if (czmlInterval.hasOwnProperty('rgba') ||
czmlInterval.hasOwnProperty('rgbaf')) {
return Color;
} else if (czmlInterval.hasOwnProperty('arcType')) {
return ArcType;
} else if (czmlInterval.hasOwnProperty('classificationType')) {
return ClassificationType;
} else if (czmlInterval.hasOwnProperty('colorBlendMode')) {
return ColorBlendMode;
} else if (czmlInterval.hasOwnProperty('cornerType')) {
return CornerType;
} else if (czmlInterval.hasOwnProperty('heightReference')) {
return HeightReference;
} else if (czmlInterval.hasOwnProperty('horizontalOrigin')) {
return HorizontalOrigin;
} else if (czmlInterval.hasOwnProperty('date')) {
return JulianDate;
} else if (czmlInterval.hasOwnProperty('labelStyle')) {
return LabelStyle;
} else if (czmlInterval.hasOwnProperty('number')) {
return Number;
} else if (czmlInterval.hasOwnProperty('nearFarScalar')) {
return NearFarScalar;
} else if (czmlInterval.hasOwnProperty('distanceDisplayCondition')) {
return DistanceDisplayCondition;
} else if (czmlInterval.hasOwnProperty('object') ||
czmlInterval.hasOwnProperty('value')) {
return Object;
} else if (czmlInterval.hasOwnProperty('unitQuaternion')) {
return Quaternion;
} else if (czmlInterval.hasOwnProperty('shadowMode')) {
return ShadowMode;
} else if (czmlInterval.hasOwnProperty('string')) {
return String;
} else if (czmlInterval.hasOwnProperty('stripeOrientation')) {
return StripeOrientation;
} else if (czmlInterval.hasOwnProperty('wsen') ||
czmlInterval.hasOwnProperty('wsenDegrees')) {
return Rectangle;
} else if (czmlInterval.hasOwnProperty('uri')) {
return Uri;
} else if (czmlInterval.hasOwnProperty('verticalOrigin')) {
return VerticalOrigin;
}
// fallback case
return Object;
}
function unwrapInterval(type, czmlInterval, sourceUri) {
// The associations in this function need to be kept in sync with the
// associations in getPropertyType
switch (type) {
case ArcType:
return ArcType[defaultValue(czmlInterval.arcType, czmlInterval)];
case Array:
return czmlInterval.array;
case Boolean:
return defaultValue(czmlInterval['boolean'], czmlInterval);
case BoundingRectangle:
return czmlInterval.boundingRectangle;
case Cartesian2:
return czmlInterval.cartesian2;
case Cartesian3:
return unwrapCartesianInterval(czmlInterval);
case UnitCartesian3:
return unwrapUnitCartesianInterval(czmlInterval);
case Color:
return unwrapColorInterval(czmlInterval);
case ClassificationType:
return ClassificationType[defaultValue(czmlInterval.classificationType, czmlInterval)];
case ColorBlendMode:
return ColorBlendMode[defaultValue(czmlInterval.colorBlendMode, czmlInterval)];
case CornerType:
return CornerType[defaultValue(czmlInterval.cornerType, czmlInterval)];
case HeightReference:
return HeightReference[defaultValue(czmlInterval.heightReference, czmlInterval)];
case HorizontalOrigin:
return HorizontalOrigin[defaultValue(czmlInterval.horizontalOrigin, czmlInterval)];
case Image:
return unwrapUriInterval(czmlInterval, sourceUri);
case JulianDate:
return JulianDate.fromIso8601(defaultValue(czmlInterval.date, czmlInterval));
case LabelStyle:
return LabelStyle[defaultValue(czmlInterval.labelStyle, czmlInterval)];
case Number:
return defaultValue(czmlInterval.number, czmlInterval);
case NearFarScalar:
return czmlInterval.nearFarScalar;
case DistanceDisplayCondition:
return czmlInterval.distanceDisplayCondition;
case Object:
return defaultValue(defaultValue(czmlInterval.object, czmlInterval.value), czmlInterval);
case Quaternion:
return unwrapQuaternionInterval(czmlInterval);
case Rotation:
return defaultValue(czmlInterval.number, czmlInterval);
case ShadowMode:
return ShadowMode[defaultValue(defaultValue(czmlInterval.shadowMode, czmlInterval.shadows), czmlInterval)];
case String:
return defaultValue(czmlInterval.string, czmlInterval);
case StripeOrientation:
return StripeOrientation[defaultValue(czmlInterval.stripeOrientation, czmlInterval)];
case Rectangle:
return unwrapRectangleInterval(czmlInterval);
case Uri:
return unwrapUriInterval(czmlInterval, sourceUri);
case VerticalOrigin:
return VerticalOrigin[defaultValue(czmlInterval.verticalOrigin, czmlInterval)];
default:
throw new RuntimeError(type);
}
}
var interpolators = {
HERMITE : HermitePolynomialApproximation,
LAGRANGE : LagrangePolynomialApproximation,
LINEAR : LinearApproximation
};
function updateInterpolationSettings(packetData, property) {
var interpolationAlgorithm = packetData.interpolationAlgorithm;
var interpolationDegree = packetData.interpolationDegree;
if (defined(interpolationAlgorithm) || defined(interpolationDegree)) {
property.setInterpolationOptions({
interpolationAlgorithm : interpolators[interpolationAlgorithm],
interpolationDegree : interpolationDegree
});
}
var forwardExtrapolationType = packetData.forwardExtrapolationType;
if (defined(forwardExtrapolationType)) {
property.forwardExtrapolationType = ExtrapolationType[forwardExtrapolationType];
}
var forwardExtrapolationDuration = packetData.forwardExtrapolationDuration;
if (defined(forwardExtrapolationDuration)) {
property.forwardExtrapolationDuration = forwardExtrapolationDuration;
}
var backwardExtrapolationType = packetData.backwardExtrapolationType;
if (defined(backwardExtrapolationType)) {
property.backwardExtrapolationType = ExtrapolationType[backwardExtrapolationType];
}
var backwardExtrapolationDuration = packetData.backwardExtrapolationDuration;
if (defined(backwardExtrapolationDuration)) {
property.backwardExtrapolationDuration = backwardExtrapolationDuration;
}
}
var iso8601Scratch = {
iso8601 : undefined
};
function intervalFromString(intervalString) {
if (!defined(intervalString)) {
return undefined;
}
iso8601Scratch.iso8601 = intervalString;
return TimeInterval.fromIso8601(iso8601Scratch);
}
function wrapPropertyInInfiniteInterval(property) {
var interval = Iso8601.MAXIMUM_INTERVAL.clone();
interval.data = property;
return interval;
}
function convertPropertyToComposite(property) {
// Create the composite and add the old property, wrapped in an infinite interval.
var composite = new CompositeProperty();
composite.intervals.addInterval(wrapPropertyInInfiniteInterval(property));
return composite;
}
function convertPositionPropertyToComposite(property) {
// Create the composite and add the old property, wrapped in an infinite interval.
var composite = new CompositePositionProperty(property.referenceFrame);
composite.intervals.addInterval(wrapPropertyInInfiniteInterval(property));
return composite;
}
function processProperty(type, object, propertyName, packetData, constrainedInterval, sourceUri, entityCollection) {
var combinedInterval = intervalFromString(packetData.interval);
if (defined(constrainedInterval)) {
if (defined(combinedInterval)) {
combinedInterval = TimeInterval.intersect(combinedInterval, constrainedInterval, scratchTimeInterval);
} else {
combinedInterval = constrainedInterval;
}
}
var packedLength;
var unwrappedInterval;
var unwrappedIntervalLength;
// CZML properties can be defined in many ways. Most ways represent a structure for
// encoding a single value (number, string, cartesian, etc.) Regardless of the value type,
// if it encodes a single value it will get loaded into a ConstantProperty eventually.
// Alternatively, there are ways of defining a property that require specialized
// client-side representation. Currently, these are ReferenceProperty,
// and client-side velocity computation properties such as VelocityVectorProperty.
var isValue = !defined(packetData.reference) && !defined(packetData.velocityReference);
var hasInterval = defined(combinedInterval) && !combinedInterval.equals(Iso8601.MAXIMUM_INTERVAL);
if (packetData.delete === true) {
// If deleting this property for all time, we can simply set to undefined and return.
if (!hasInterval) {
object[propertyName] = undefined;
return;
}
// Deleting depends on the type of property we have.
return removePropertyData(object[propertyName], combinedInterval);
}
var isSampled = false;
if (isValue) {
unwrappedInterval = unwrapInterval(type, packetData, sourceUri);
if (!defined(unwrappedInterval)) {
// not a known value type, bail
return;
}
packedLength = defaultValue(type.packedLength, 1);
unwrappedIntervalLength = defaultValue(unwrappedInterval.length, 1);
isSampled = !defined(packetData.array) && (typeof unwrappedInterval !== 'string') && (unwrappedIntervalLength > packedLength) && (type !== Object);
}
// Rotation is a special case because it represents a native type (Number)
// and therefore does not need to be unpacked when loaded as a constant value.
var needsUnpacking = typeof type.unpack === 'function' && type !== Rotation;
// Any time a constant value is assigned, it completely blows away anything else.
if (!isSampled && !hasInterval) {
if (isValue) {
object[propertyName] = new ConstantProperty(needsUnpacking ? type.unpack(unwrappedInterval, 0) : unwrappedInterval);
} else {
object[propertyName] = createSpecializedProperty(type, entityCollection, packetData);
}
return;
}
var property = object[propertyName];
var epoch;
var packetEpoch = packetData.epoch;
if (defined(packetEpoch)) {
epoch = JulianDate.fromIso8601(packetEpoch);
}
// Without an interval, any sampled value is infinite, meaning it completely
// replaces any non-sampled property that may exist.
if (isSampled && !hasInterval) {
if (!(property instanceof SampledProperty)) {
object[propertyName] = property = new SampledProperty(type);
}
property.addSamplesPackedArray(unwrappedInterval, epoch);
updateInterpolationSettings(packetData, property);
return;
}
var interval;
// A constant value with an interval is normally part of a TimeIntervalCollection,
// However, if the current property is not a time-interval collection, we need
// to turn it into a Composite, preserving the old data with the new interval.
if (!isSampled && hasInterval) {
// Create a new interval for the constant value.
combinedInterval = combinedInterval.clone();
if (isValue) {
combinedInterval.data = needsUnpacking ? type.unpack(unwrappedInterval, 0) : unwrappedInterval;
} else {
combinedInterval.data = createSpecializedProperty(type, entityCollection, packetData);
}
// If no property exists, simply use a new interval collection
if (!defined(property)) {
object[propertyName] = property = isValue ? new TimeIntervalCollectionProperty() : new CompositeProperty();
}
if (isValue && property instanceof TimeIntervalCollectionProperty) {
// If we created a collection, or it already was one, use it.
property.intervals.addInterval(combinedInterval);
} else if (property instanceof CompositeProperty) {
// If the collection was already a CompositeProperty, use it.
if (isValue) {
combinedInterval.data = new ConstantProperty(combinedInterval.data);
}
property.intervals.addInterval(combinedInterval);
} else {
// Otherwise, create a CompositeProperty but preserve the existing data.
object[propertyName] = property = convertPropertyToComposite(property);
// Change the new data to a ConstantProperty and add it.
if (isValue) {
combinedInterval.data = new ConstantProperty(combinedInterval.data);
}
property.intervals.addInterval(combinedInterval);
}
return;
}
// isSampled && hasInterval
if (!defined(property)) {
object[propertyName] = property = new CompositeProperty();
}
// Create a CompositeProperty but preserve the existing data.
if (!(property instanceof CompositeProperty)) {
object[propertyName] = property = convertPropertyToComposite(property);
}
// Check if the interval already exists in the composite.
var intervals = property.intervals;
interval = intervals.findInterval(combinedInterval);
if (!defined(interval) || !(interval.data instanceof SampledProperty)) {
// If not, create a SampledProperty for it.
interval = combinedInterval.clone();
interval.data = new SampledProperty(type);
intervals.addInterval(interval);
}
interval.data.addSamplesPackedArray(unwrappedInterval, epoch);
updateInterpolationSettings(packetData, interval.data);
}
function removePropertyData(property, interval) {
if (property instanceof SampledProperty) {
property.removeSamples(interval);
return;
} else if (property instanceof TimeIntervalCollectionProperty) {
property.intervals.removeInterval(interval);
return;
} else if (property instanceof CompositeProperty) {
var intervals = property.intervals;
for (var i = 0; i < intervals.length; ++i) {
var intersection = TimeInterval.intersect(intervals.get(i), interval, scratchTimeInterval);
if (!intersection.isEmpty) {
// remove data from the contained properties
removePropertyData(intersection.data, interval);
}
}
// remove the intervals from the composite
intervals.removeInterval(interval);
return;
}
}
function processPacketData(type, object, propertyName, packetData, interval, sourceUri, entityCollection) {
if (!defined(packetData)) {
return;
}
if (Array.isArray(packetData)) {
for (var i = 0, len = packetData.length; i < len; ++i) {
processProperty(type, object, propertyName, packetData[i], interval, sourceUri, entityCollection);
}
} else {
processProperty(type, object, propertyName, packetData, interval, sourceUri, entityCollection);
}
}
function processPositionProperty(object, propertyName, packetData, constrainedInterval, sourceUri, entityCollection) {
var combinedInterval = intervalFromString(packetData.interval);
if (defined(constrainedInterval)) {
if (defined(combinedInterval)) {
combinedInterval = TimeInterval.intersect(combinedInterval, constrainedInterval, scratchTimeInterval);
} else {
combinedInterval = constrainedInterval;
}
}
var numberOfDerivatives = defined(packetData.cartesianVelocity) ? 1 : 0;
var packedLength = Cartesian3.packedLength * (numberOfDerivatives + 1);
var unwrappedInterval;
var unwrappedIntervalLength;
var isValue = !defined(packetData.reference);
var hasInterval = defined(combinedInterval) && !combinedInterval.equals(Iso8601.MAXIMUM_INTERVAL);
if (packetData.delete === true) {
// If deleting this property for all time, we can simply set to undefined and return.
if (!hasInterval) {
object[propertyName] = undefined;
return;
}
// Deleting depends on the type of property we have.
return removePositionPropertyData(object[propertyName], combinedInterval);
}
var referenceFrame;
var isSampled = false;
if (isValue) {
if (defined(packetData.referenceFrame)) {
referenceFrame = ReferenceFrame[packetData.referenceFrame];
}
referenceFrame = defaultValue(referenceFrame, ReferenceFrame.FIXED);
unwrappedInterval = unwrapCartesianInterval(packetData);
unwrappedIntervalLength = defaultValue(unwrappedInterval.length, 1);
isSampled = unwrappedIntervalLength > packedLength;
}
// Any time a constant value is assigned, it completely blows away anything else.
if (!isSampled && !hasInterval) {
if (isValue) {
object[propertyName] = new ConstantPositionProperty(Cartesian3.unpack(unwrappedInterval), referenceFrame);
} else {
object[propertyName] = createReferenceProperty(entityCollection, packetData.reference);
}
return;
}
var property = object[propertyName];
var epoch;
var packetEpoch = packetData.epoch;
if (defined(packetEpoch)) {
epoch = JulianDate.fromIso8601(packetEpoch);
}
// Without an interval, any sampled value is infinite, meaning it completely
// replaces any non-sampled property that may exist.
if (isSampled && !hasInterval) {
if (!(property instanceof SampledPositionProperty) || (defined(referenceFrame) && property.referenceFrame !== referenceFrame)) {
object[propertyName] = property = new SampledPositionProperty(referenceFrame, numberOfDerivatives);
}
property.addSamplesPackedArray(unwrappedInterval, epoch);
updateInterpolationSettings(packetData, property);
return;
}
var interval;
// A constant value with an interval is normally part of a TimeIntervalCollection,
// However, if the current property is not a time-interval collection, we need
// to turn it into a Composite, preserving the old data with the new interval.
if (!isSampled && hasInterval) {
// Create a new interval for the constant value.
combinedInterval = combinedInterval.clone();
if (isValue) {
combinedInterval.data = Cartesian3.unpack(unwrappedInterval);
} else {
combinedInterval.data = createReferenceProperty(entityCollection, packetData.reference);
}
// If no property exists, simply use a new interval collection
if (!defined(property)) {
if (isValue) {
property = new TimeIntervalCollectionPositionProperty(referenceFrame);
} else {
property = new CompositePositionProperty(referenceFrame);
}
object[propertyName] = property;
}
if (isValue && property instanceof TimeIntervalCollectionPositionProperty && (defined(referenceFrame) && property.referenceFrame === referenceFrame)) {
// If we create a collection, or it already existed, use it.
property.intervals.addInterval(combinedInterval);
} else if (property instanceof CompositePositionProperty) {
// If the collection was already a CompositePositionProperty, use it.
if (isValue) {
combinedInterval.data = new ConstantPositionProperty(combinedInterval.data, referenceFrame);
}
property.intervals.addInterval(combinedInterval);
} else {
// Otherwise, create a CompositePositionProperty but preserve the existing data.
object[propertyName] = property = convertPositionPropertyToComposite(property);
// Change the new data to a ConstantPositionProperty and add it.
if (isValue) {
combinedInterval.data = new ConstantPositionProperty(combinedInterval.data, referenceFrame);
}
property.intervals.addInterval(combinedInterval);
}
return;
}
// isSampled && hasInterval
if (!defined(property)) {
object[propertyName] = property = new CompositePositionProperty(referenceFrame);
} else if (!(property instanceof CompositePositionProperty)) {
// Create a CompositeProperty but preserve the existing data.
object[propertyName] = property = convertPositionPropertyToComposite(property);
}
// Check if the interval already exists in the composite.
var intervals = property.intervals;
interval = intervals.findInterval(combinedInterval);
if (!defined(interval) || !(interval.data instanceof SampledPositionProperty) || (defined(referenceFrame) && interval.data.referenceFrame !== referenceFrame)) {
// If not, create a SampledPositionProperty for it.
interval = combinedInterval.clone();
interval.data = new SampledPositionProperty(referenceFrame, numberOfDerivatives);
intervals.addInterval(interval);
}
interval.data.addSamplesPackedArray(unwrappedInterval, epoch);
updateInterpolationSettings(packetData, interval.data);
}
function removePositionPropertyData(property, interval) {
if (property instanceof SampledPositionProperty) {
property.removeSamples(interval);
return;
} else if (property instanceof TimeIntervalCollectionPositionProperty) {
property.intervals.removeInterval(interval);
return;
} else if (property instanceof CompositePositionProperty) {
var intervals = property.intervals;
for (var i = 0; i < intervals.length; ++i) {
var intersection = TimeInterval.intersect(intervals.get(i), interval, scratchTimeInterval);
if (!intersection.isEmpty) {
// remove data from the contained properties
removePositionPropertyData(intersection.data, interval);
}
}
// remove the intervals from the composite
intervals.removeInterval(interval);
return;
}
}
function processPositionPacketData(object, propertyName, packetData, interval, sourceUri, entityCollection) {
if (!defined(packetData)) {
return;
}
if (Array.isArray(packetData)) {
for (var i = 0, len = packetData.length; i < len; ++i) {
processPositionProperty(object, propertyName, packetData[i], interval, sourceUri, entityCollection);
}
} else {
processPositionProperty(object, propertyName, packetData, interval, sourceUri, entityCollection);
}
}
function processMaterialProperty(object, propertyName, packetData, constrainedInterval, sourceUri, entityCollection) {
var combinedInterval = intervalFromString(packetData.interval);
if (defined(constrainedInterval)) {
if (defined(combinedInterval)) {
combinedInterval = TimeInterval.intersect(combinedInterval, constrainedInterval, scratchTimeInterval);
} else {
combinedInterval = constrainedInterval;
}
}
var property = object[propertyName];
var existingMaterial;
var existingInterval;
if (defined(combinedInterval)) {
if (!(property instanceof CompositeMaterialProperty)) {
property = new CompositeMaterialProperty();
object[propertyName] = property;
}
//See if we already have data at that interval.
var thisIntervals = property.intervals;
existingInterval = thisIntervals.findInterval({
start : combinedInterval.start,
stop : combinedInterval.stop
});
if (defined(existingInterval)) {
//We have an interval, but we need to make sure the
//new data is the same type of material as the old data.
existingMaterial = existingInterval.data;
} else {
//If not, create it.
existingInterval = combinedInterval.clone();
thisIntervals.addInterval(existingInterval);
}
} else {
existingMaterial = property;
}
var materialData;
if (defined(packetData.solidColor)) {
if (!(existingMaterial instanceof ColorMaterialProperty)) {
existingMaterial = new ColorMaterialProperty();
}
materialData = packetData.solidColor;
processPacketData(Color, existingMaterial, 'color', materialData.color, undefined, undefined, entityCollection);
} else if (defined(packetData.grid)) {
if (!(existingMaterial instanceof GridMaterialProperty)) {
existingMaterial = new GridMaterialProperty();
}
materialData = packetData.grid;
processPacketData(Color, existingMaterial, 'color', materialData.color, undefined, sourceUri, entityCollection);
processPacketData(Number, existingMaterial, 'cellAlpha', materialData.cellAlpha, undefined, sourceUri, entityCollection);
processPacketData(Cartesian2, existingMaterial, 'lineCount', materialData.lineCount, undefined, sourceUri, entityCollection);
processPacketData(Cartesian2, existingMaterial, 'lineThickness', materialData.lineThickness, undefined, sourceUri, entityCollection);
processPacketData(Cartesian2, existingMaterial, 'lineOffset', materialData.lineOffset, undefined, sourceUri, entityCollection);
} else if (defined(packetData.image)) {
if (!(existingMaterial instanceof ImageMaterialProperty)) {
existingMaterial = new ImageMaterialProperty();
}
materialData = packetData.image;
processPacketData(Image, existingMaterial, 'image', materialData.image, undefined, sourceUri, entityCollection);
processPacketData(Cartesian2, existingMaterial, 'repeat', materialData.repeat, undefined, sourceUri, entityCollection);
processPacketData(Color, existingMaterial, 'color', materialData.color, undefined, sourceUri, entityCollection);
processPacketData(Boolean, existingMaterial, 'transparent', materialData.transparent, undefined, sourceUri, entityCollection);
} else if (defined(packetData.stripe)) {
if (!(existingMaterial instanceof StripeMaterialProperty)) {
existingMaterial = new StripeMaterialProperty();
}
materialData = packetData.stripe;
processPacketData(StripeOrientation, existingMaterial, 'orientation', materialData.orientation, undefined, sourceUri, entityCollection);
processPacketData(Color, existingMaterial, 'evenColor', materialData.evenColor, undefined, sourceUri, entityCollection);
processPacketData(Color, existingMaterial, 'oddColor', materialData.oddColor, undefined, sourceUri, entityCollection);
processPacketData(Number, existingMaterial, 'offset', materialData.offset, undefined, sourceUri, entityCollection);
processPacketData(Number, existingMaterial, 'repeat', materialData.repeat, undefined, sourceUri, entityCollection);
} else if (defined(packetData.polylineOutline)) {
if (!(existingMaterial instanceof PolylineOutlineMaterialProperty)) {
existingMaterial = new PolylineOutlineMaterialProperty();
}
materialData = packetData.polylineOutline;
processPacketData(Color, existingMaterial, 'color', materialData.color, undefined, sourceUri, entityCollection);
processPacketData(Color, existingMaterial, 'outlineColor', materialData.outlineColor, undefined, sourceUri, entityCollection);
processPacketData(Number, existingMaterial, 'outlineWidth', materialData.outlineWidth, undefined, sourceUri, entityCollection);
} else if (defined(packetData.polylineGlow)) {
if (!(existingMaterial instanceof PolylineGlowMaterialProperty)) {
existingMaterial = new PolylineGlowMaterialProperty();
}
materialData = packetData.polylineGlow;
processPacketData(Color, existingMaterial, 'color', materialData.color, undefined, sourceUri, entityCollection);
processPacketData(Number, existingMaterial, 'glowPower', materialData.glowPower, undefined, sourceUri, entityCollection);
processPacketData(Number, existingMaterial, 'taperPower', materialData.taperPower, undefined, sourceUri, entityCollection);
} else if (defined(packetData.polylineArrow)) {
if (!(existingMaterial instanceof PolylineArrowMaterialProperty)) {
existingMaterial = new PolylineArrowMaterialProperty();
}
materialData = packetData.polylineArrow;
processPacketData(Color, existingMaterial, 'color', materialData.color, undefined, undefined, entityCollection);
} else if (defined(packetData.polylineDash)) {
if (!(existingMaterial instanceof PolylineDashMaterialProperty)) {
existingMaterial = new PolylineDashMaterialProperty();
}
materialData = packetData.polylineDash;
processPacketData(Color, existingMaterial, 'color', materialData.color, undefined, undefined, entityCollection);
processPacketData(Color, existingMaterial, 'gapColor', materialData.gapColor, undefined, undefined, entityCollection);
processPacketData(Number, existingMaterial, 'dashLength', materialData.dashLength, unde