Property最大的特点就是和时间相互关联,它能够在不同的时间可以动态地返回不同的属性值,如空间位置。比如几何体的某一属性随时间动态变化,如高度或长度或位置等。进入Property抽象类的详细文档中,发现里面也有分类

alt 虽然官方文档没有分的特别清楚,但整体来说Cesium的Property可归结为四大类:

  1. 基本Property:包括ConstantProperty、SampledProperty、TimeIntervalCollectionProperty、CompositeProperty;
  2. MaterialProperty:包括ColorMaterialProperty、ImageMaterialProperty、PolylineArrowMaterialProperty等;
  3. PositionProperty:包括ConstantPositionProperty、SampledPositionProperty、TimeIntervalCollectionPositionProperty、CompositePositionProperty;
  4. 其他Property,包括CallbackProperty、NodeTransformationProperty、PropertyBag、PropertyArray、ReferenceProperty、VelocityOrientationProperty、VelocityVectorProperty。

基本Property

ConstantProperty

虽然我们并没有在Cesium的开发中应用到ConstantProperty,但它却是最常用的一个Property,其值不会随时间的变化而变化,Cesium内部会隐晦地将你所定义地属性(包括Property、CompositeProperty、ConstantProperty、SampledProperty、TimeIntervalCollectionProperty、MaterialProperty、PositionProperty、ReferenceProperty这几种类型)转成ConstantProperty,下面我们通过添加一个盒子地示例来说明。 默认实现代码:

 var blueBox = viewer.entities.add({
          name: "Blue box",
          position: Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0),
          box: {
            dimensions: new Cesium.Cartesian3(400000.0, 300000.0, 500000.0),
            material: Cesium.Color.BLUE,
          },
        });
添加ConstantProperty的方式:
        var blueBox = viewer.entities.add({
          name: "Blue box",
          position: new Cesium.ConstantProperty(Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0)),
          box: {
            dimensions: new Cesium.ConstantProperty(new Cesium.Cartesian3(400000.0, 300000.0, 500000.0)),
            material: Cesium.Color.BLUE,
          },
        });

两种实现的本质和最终的效果都是一样的。虽然ConstantProperty的值不会随时间的变化而变化,但并不代表其不可修改,我们可以通过调用setValue方法来修改其属性值。类似的还包括ConstantPositionProperty,这里就不详细介绍了,实现原理都已一样的。

SampledProperty

用来通过给定多个不同时间点的Sample,然后在每两个时间点之间进行插值的一种Property,通常都会使用addSample方法添加不同时间点的值。

//Create a linearly interpolated Cartesian2
var property = new Cesium.SampledProperty(Cesium.Cartesian2);
//Populate it with data
property.addSample(Cesium.JulianDate.fromIso8601('2012-08-01T00:00:00.00Z'), new Cesium.Cartesian2(0, 0));
property.addSample(Cesium.JulianDate.fromIso8601('2012-08-02T00:00:00.00Z'), new Cesium.Cartesian2(4, 7));
//Retrieve an interpolated value
var result = property.getValue(Cesium.JulianDate.fromIso8601('2012-08-01T12:00:00.00Z'));
  • 最终会把property赋值给对应的属性,实现点的移动效果。

TimeIntervalCollectionProperty

和SampledProperty差不多,主要区别就是SampledProperty是按照每一时刻修改Property的,实现效果是平滑的变化;而TimeIntervalCollectionProperty是按照每个时间段来修改Property的,单独每一个时间段内属性值是不变的,实现效果是跳跃式的变化。

//Create a Cartesian2 interval property which contains data on August 1st, 2012
//and uses a different value every 6 hours.
var composite = new Cesium.TimeIntervalCollectionProperty();
composite.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
    iso8601 : '2012-08-01T00:00:00.00Z/2012-08-01T06:00:00.00Z',
    isStartIncluded : true,
    isStopIncluded : false,
    data : new Cesium.Cartesian2(2.0, 3.4)}));
composite.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
    iso8601 : '2012-08-01T06:00:00.00Z/2012-08-01T12:00:00.00Z',
    isStartIncluded : true,
    isStopIncluded : false,
    data : new Cesium.Cartesian2(12.0, 2.7)}));
composite.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
    iso8601 : '2012-08-01T12:00:00.00Z/2012-08-01T18:00:00.00Z',
    isStartIncluded : true,
    isStopIncluded : false,
    data : new Cesium.Cartesian2(5.0, 12.4)}));
composite.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
    iso8601 : '2012-08-01T18:00:00.00Z/2012-08-02T00:00:00.00Z',
    isStartIncluded : true,
    isStopIncluded : true,
    data : new Cesium.Cartesian2(85.0, 4.1)}));

同样TimeIntervalCollectionPositionProperty实现原来也是类似。

CompositeProperty

意思是组合的Property,有的时候单个类型的Property无法满足实际的需求时,这时可以把ConstantProperty、SampleProperty、TimeIntervalCollectionProperty等多种类型的Property组合在一起进行实现。比如一段时间线性运动,一段时间跳跃式运动,一段时间其他方式运动等,简单的示例如下:

var constantProperty = ...;
var sampledProperty = ...;
//Create a composite property from two previously defined properties
//where the property is valid on August 1st, 2012 and uses a constant
//property for the first half of the day and a sampled property for the remaining half.
var composite = new Cesium.CompositeProperty();
composite.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
    iso8601 : '2012-08-01T00:00:00.00Z/2012-08-01T12:00:00.00Z',
    data : constantProperty}));
composite.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
    iso8601 : '2012-08-01T12:00:00.00Z/2012-08-02T00:00:00.00Z',
    isStartIncluded : false,
    isStopIncluded : false,
    data : sampledProperty}));

同样还有CompositeMaterialProperty、CompositePositionProperty,是专门针对MaterialProperty、PositionProperty的CompositeProperty,其实现原理也都一样。

MaterialProperty

  • 专门用来表示材质的Property,其中新增了获取材质类型的getType方法。和Property一样,是一个抽象类,不能直接被实例化。

PositionProperty

  • 专门用来表示Position的Property,扩展了Property的接口,增加了用于定义position坐标系原点的参考框架referenceFrame,默认值为FIXED(相当于以地球的中心作为坐标系的原点)。
  • 和Property一样,是一个抽象类,不能直接被实例化。因为PositionProperty和普通的Property本质上是一致的,用法上也大同小异,只是多了一个Position,
  • 所以对于ConstantPositionProperty、TimeIntervalCollectionPositionProperty、CompositePositionProperty不做过多的讲解,用法都在上面的基本Property中。
  • 但SampledPositionProperty在实际的开发中还比较常用 。

SampledPositionProperty

SampledPositionProperty和SampledProperty原理都是一样的,简单使用方式图下:

        //Generate a random circular pattern with varying heights.
        function computeCirclularFlight(lon, lat, radius) {

          var property = new Cesium.SampledPositionProperty();

          for (var i = 0; i <= 360; i += 45) {

            var radians = Cesium.Math.toRadians(i);
            var time = Cesium.JulianDate.addSeconds(
              start,
              i,
              new Cesium.JulianDate()
            );


            var position = Cesium.Cartesian3.fromDegrees(
              lon + radius * 1.5 * Math.cos(radians),
              lat + radius * Math.sin(radians),
              Cesium.Math.nextRandomNumber() * 500 + 1750
            );

            property.addSample(time, position);

            //Also create a point for each sample we generate.
            viewer.entities.add({
              position: position,
              point: {
                pixelSize: 8,
                color: Cesium.Color.TRANSPARENT,
                outlineColor: Cesium.Color.YELLOW,
                outlineWidth: 3,
              },
            });
          }
          return property;
        }
  • 他俩都有一个特有的方法setInterpolationOptions用于修改不同的插值方式,包括线性插值、Lagrange插值和Hermite插值,
  • 分别对应LinearApproximation、LagrangePolynomialApproximation、HermitePolynomialApproximation,
  • 详细的线性插值方式和插值效果请查看Cesium官方示例 https://sandcastle.cesium.com/?src=Interpolation.htmlopen in new window

其他Property 除了上述讲到的Property,Cesium还提供了一些其他的Property。

CallbackProperty

CallbackProperty是自由度最高的一种Property,也是Cesium非常常用的一种Property,开发者可通过自定义回调函数来返回需要的值。其构造函数中包括callback和isConstant两个参数,分别表示回调函数(time和result)和回调函数每一时刻返回的值是否不变。

        var startLatitude = 35;
        var startLongitude = -120;
        var endLongitude;
        var startTime = Cesium.JulianDate.now();

        // Add a polyline to the scene. Positions are dynamic.
        var isConstant = false;
        var redLine = viewer.entities.add({
          polyline: {
            // This callback updates positions each frame.
            positions: new Cesium.CallbackProperty(function (time, result) {
              endLongitude =
                startLongitude +
                0.001 * Cesium.JulianDate.secondsDifference(time, startTime);
              return Cesium.Cartesian3.fromDegreesArray(
                [startLongitude, startLatitude, endLongitude, startLatitude],
                Cesium.Ellipsoid.WGS84,
                result
              );
            }, isConstant),
            width: 5,
            material: Cesium.Color.RED,
          },
        });

PropertyBag

它的值是一个通过key-value组成的对象,其中对象中的每一个属性都是动态的,并且可以单独修改。比如只修改Box的高度,可通过如下方法实现:

    var zp = new Cesium.SampledProperty(Number);
    zp.addSample(Cesium.JulianDate.fromIso8601('2019-01-01T00:00:00.00Z'), 200000.0);
    zp.addSample(Cesium.JulianDate.fromIso8601('2019-01-03T00:00:00.00Z'), 700000.0);

    blueBox.box.dimensions = new Cesium.PropertyBag({
        x: 400000.0,
        y: 300000.0,
        z: zp
    });

PropertyArray

和PropertyBag类似,只不过是将对象换成了数组,使用方法和PropertyBag一样,这里不再赘述。

ReferenceProperty

将新Entity的属性链接到已知对象上,相当于对象属性的引用。类似于几何实例化,几何实例化是引用同一个几何对象,而ReferenceProperty是引用相同的属性,可同时控制多个Enetity的同一个属性信息,可通过如下三种方式使用。

var collection = new Cesium.EntityCollection();
//Create a new entity and assign a billboard scale.var object1 = new Cesium.Entity({id:'object1'});
object1.billboard = new Cesium.BillboardGraphics();
object1.billboard.scale = new Cesium.ConstantProperty(2.0);
collection.add(object1);

//1.Create a second entity and reference the scale from the first one.
var object2 = new Cesium.Entity({id:'object2'});
object2.model = new Cesium.ModelGraphics();
object2.model.scale = new Cesium.ReferenceProperty(collection, 'object1', ['billboard', 'scale']);
collection.add(object2);

//2.Create a third object, but use the fromString helper function.
var object3 = new Cesium.Entity({id:'object3'});
object3.billboard = new Cesium.BillboardGraphics();
object3.billboard.scale = Cesium.ReferenceProperty.fromString(collection, 'object1#billboard.scale');
collection.add(object3);

//3.You can refer to an entity with a # or . in id and property names by escaping them.
var object4 = new Cesium.Entity({id:'#object.4'});
object4.billboard = new Cesium.BillboardGraphics();
object4.billboard.scale = new Cesium.ConstantProperty(2.0);
collection.add(object4);
var object5 = new Cesium.Entity({id:'object5'});
object5.billboard = new Cesium.BillboardGraphics();
object5.billboard.scale = Cesium.ReferenceProperty.fromString(collection, '\\#object\\.4#billboard.scale');
collection.add(object5);

VelocityOrientationProperty

将Entity的postion速度转换成Orientation旋转。使用方法如下:

//Create an entity with position and orientation.
var position = new Cesium.SampledProperty();
position.addSamples(...);var entity = viewer.entities.add({
  position : position,
  orientation : new Cesium.VelocityOrientationProperty(position)
}));

VelocityVectorProperty

和VelocityOrientationProperty类似,将速度转成Cartesian3向量。使用示例如下:

//Create an entity with a billboard rotated to match its velocity.
var position = new Cesium.SampledProperty();
position.addSamples(...);
var entity = viewer.entities.add({
  position : position,
  billboard : {
    image : 'image.png',
  alignedAxis : new Cesium.VelocityVectorProperty(position, true) // alignedAxis must be a unit vector  
}}));

NodeTransformationProperty

专门用于生成 TranslationRotationScale对象的属性,包括平移、旋转、缩放,用于控制模型矩阵变化的。关于此Property,Cesium没有过多的介绍,但可以通过变相方式去使用。

        var emitterModelMatrix = new Cesium.Matrix4();
        var translation = new Cesium.Cartesian3();
        var rotation = new Cesium.Quaternion();
        var hpr = new Cesium.HeadingPitchRoll();
        var trs = new Cesium.TranslationRotationScale();

        function computeEmitterModelMatrix() {
          hpr = Cesium.HeadingPitchRoll.fromDegrees(0.0, 0.0, 0.0, hpr);
          trs.translation = Cesium.Cartesian3.fromElements(
            -4.0,
            0.0,
            1.4,
            translation
          );
          trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, rotation);

          return Cesium.Matrix4.fromTranslationRotationScale(
            trs,
            emitterModelMatrix
          );
        }

// use SampledPositionProperty
            // 动态路径
            const property = new Cesium.SampledPositionProperty();
            const allTime = 86400;
            const stepTime = 86400 / (坐标点数量+1);
            const startTime = viewer.clock.startTime;
            const stopTime = Cesium.JulianDate.addSeconds(startTime, allTime, new Cesium.JulianDate());
            for (let index = 0; index < positionsArr.length; index++) {
                const point = positionsArr[index];
                if (index === 0) {
                    property.addSample(startTime, Cesium.Cartesian3.fromDegrees(起点坐标, 起点坐标, 0));
                }else if (index === positionsArr.length - 1) {
                    property.addSample(stopTime, Cesium.Cartesian3.fromDegrees(终点坐标, 终点坐标, 0));
                }else {
                    property.addSample(Cesium.JulianDate.addSeconds(startTime, (index)*stepTime, new Cesium.JulianDate()),Cesium.Cartesian3.fromDegrees(point[0],point[1],point[2]))
                }
            }