Cesium中有关Property的类非常之多,算下来总共有29个,通过Property'关键词搜索结果如下图所示。对于Cesium小白或者对Cesium不太熟悉的人来说,光看搜索结果就已经很懵了,更何况是把他们熟练的用起来。
虽然关于Property类有很多,但仔细看还是有其分类的。首先Property作为基类或抽象类,定义了所有属性的接口规范,不能直接被实例化。其属性和方法如下图所示:
Property最大的特点就是和时间相互关联,它能够在不同的时间可以动态地返回不同的属性值,如空间位置。比如几何体的某一属性随时间动态变化,如高度或长度或位置等。进入Property抽象类的详细文档中,发现里面也有分类,如下图所示:
虽然官方文档没有分的特别清楚,但整体来说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
(1)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,这里就不详细介绍了,实现原理都已一样的。
(2)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赋值给对应的属性,实现点的移动效果。
(3)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实现原来也是类似。
(4)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一样,是一个抽象类,不能直接被实例化。有关MaterialProperty的相关讲解请阅读上一篇文章Cesium开发高级篇 | 02材质设置。
PositionProperty
专门用来表示Position的Property,扩展了Property的接口,增加了用于定义position坐标系原点的参考框架referenceFrame,默认值为FIXED(相当于以地球的中心作为坐标系的原点)。和Property一样,是一个抽象类,不能直接被实例化。因为PositionProperty和普通的Property本质上是一致的,用法上也大同小异,只是多了一个Position,所以对于ConstantPositionProperty、TimeIntervalCollectionPositionProperty、CompositePositionProperty不做过多的讲解,用法都在上面的基本Property中。但SampledPositionProperty在实际的开发中还比较常用,所以我们简单介绍一下它。
(1)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.html
其他Property
除了上述讲到的Property,Cesium还提供了一些其他的Property。
(1)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,
},
});
(2)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
});
(3)PropertyArray
和PropertyBag类似,只不过是将对象换成了数组,使用方法和PropertyBag一样,这里不再赘述。
(4)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);
(5)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)}));
(6)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
}}));
(7)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
);
}