转载:Cesium的Property机制总结
转自:https://www.jianshu.com/p/f0b47997224c
前言
Cesium官方教程中有一篇叫《空间数据可视化》(Visualizing Spatial Data)。该文文末简单提到了Cesium的Property机制,然后话锋一转,宣告此教程的第二部分将重点讲解Property机制。但是呢,第二部分还没有写好,说在等待的过程中,可以先看下Cesium对影像和地形的支持。。
可以看官方教程中的说法,如下图所示:

于是,我苦等了一年啦。。官方教程的第二部分还是没能看到。。毕竟这是Cesium官方推荐使用的Entity API中最重要的部分之一。。居然这么久了也不给更新下。。
我想还是自己总结一下得好。。
为什么要用Property?
还是举个例子来说吧。
比如我想在地球上的某个位置加一个盒子,可以这样写代码:
// 创建盒子
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,
outline: true,
}
});
最终的效果如图所示:

但是呢,如果我想让这个盒子逐渐变长,该怎么操作呢?如下图所示:

方法是有的,就是可以不停地去修改blueBox.position,类似这样:setInterval(function(){ blueBox.box.dimensions = xxx; }, 3000);
如果场景中有很多物体,在不同的时间段要发生各种走走停停地运动时,这样操作可能会很累人。那么Cesium就提供一种机制,让dimensions可以随时间自动发生变化,自动赋予不同的数值(位置)。这也就是property的作用了。以下代码的加入,就可以让盒子如上图所示做线性运动了。
var property = new Cesium.SampledProperty(Cesium.Cartesian3);
property.addSample(Cesium.JulianDate.fromIso8601('2019-01-01T00:00:00.00Z'),
new Cesium.Cartesian3(400000.0, 300000.0, 200000.0));
property.addSample(Cesium.JulianDate.fromIso8601('2019-01-03T00:00:00.00Z'),
new Cesium.Cartesian3(400000.0, 300000.0, 700000.0));
blueBox.box.dimensions = property;
以上代码的意思就是在两个不同的时间点分别赋予不同的位置,用SampledProperty包装成一个property,最后赋给blueBox.box.dimensions。
由此可见,Property最大的特点是和时间相互关联,在不同的时间可以动态地返回不同的属性值。而Entity则可以感知这些Property的变化,在不同的时间驱动物体进行动态展示。
Cesium宣称自己是数据驱动和time-dynamic visualization,这些可都是仰仗Property系统来实现的。
当然,Property可不只是这么简单,以下再详细论述。
Property的分类
Cesium的Property不止有刚才示例代码中的SampleProperty,还有很多其他的类型。如果搜索一下Cesium的API文档,会有很多。。如下图所示:

我们简单分类一下

Property虚基类
Property是所有Property类型的虚基类。它定义了以下接口。

getValue 是一个方法,用来获取某个时间点的特定属性值。它有两个参数:第一个是time,用来传递一个时间点;第二个是result,用来存储属性值,当然也可以是undefined。这个result是Cesium的scratch机制,主要是用来避免频繁创建和销毁对象而导致内存碎片。Cesium就是通过调用getValue类似的一些函数来感知Property的变化的,当然这个方法我们在外部也是可以使用的。
isConstant 用来判断该属性是否会随时间变化,是一个布尔值。Cesium会通过这个变量来决定是否需要在场景更新的每一帧中都获取该属性的数值,从而来更新三维场景中的物体。如果isConstant为true,则只会获取一次数值,除非definitionChanged事件被触发。
definitionChanged 是一个事件,可以通过该事件,来监听该Property自身所发生的变化,比如数值发生修改。
equals 是一个方法,用来检测属性值是否相等。
基本Property类型
SampleProperty
我们最早在上述示例中使用的就是它,用来通过给定多个不同时间点的Sample,然后在每两个时间点之间进行线性插值的一种Property。代码写法如下:
var property = new Cesium.SampledProperty(Cesium.Cartesian3);
property.addSample(Cesium.JulianDate.fromIso8601('2019-01-01T00:00:00.00Z'),
new Cesium.Cartesian3(400000.0, 300000.0, 200000.0));
property.addSample(Cesium.JulianDate.fromIso8601('2019-01-03T00:00:00.00Z'),
new Cesium.Cartesian3(400000.0, 300000.0, 700000.0));
blueBox.box.dimensions = property;
效果如下所示:

TimeIntervalCollectionProperty
该Property用来指定各个具体的时间段的属性值,每个时间段内的属性值是恒定的,并不会发生变化,除非已经进入到下一个时间段。拿创建的盒子示例来说,表现出来的特点就是盒子尺寸的变化时跳跃式的。效果如下:

代码如下:
var property = new Cesium.TimeIntervalCollectionProperty(Cesium.Cartesian3);
property.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
iso8601 : '2019-01-01T00:00:00.00Z/2019-01-01T12:00:00.00Z',
isStartIncluded : true,
isStopIncluded : false,
data : new Cesium.Cartesian3(400000.0, 300000.0, 200000.0)
}));
property.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
iso8601 : '2019-01-01T12:00:01.00Z/2019-01-02T00:00:00.00Z',
isStartIncluded : true,
isStopIncluded : false,
data : new Cesium.Cartesian3(400000.0, 300000.0, 400000.0)
}));
property.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
iso8601 : '2019-01-02T00:00:01.00Z/2019-01-02T12:00:00.00Z',
isStartIncluded : true,
isStopIncluded : false,
data : new Cesium.Cartesian3(400000.0, 300000.0, 500000.0)
}));
property.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
iso8601 : '2019-01-02T12:00:01.00Z/2019-01-03T00:00:00.00Z',
isStartIncluded : true,
isStopIncluded : true,
data : new Cesium.Cartesian3(400000.0, 300000.0, 700000.0)
}));
blueBox.box.dimensions = property;
ConstantProperty
通过对TimeIntervalCollectionProperty和SampleProperty的描述,读者应该基本了解Property的特点。我们回过头来说下ConstantProperty,其实这才是最常用的Property。
示例代码如下:
blueBox.box.dimensions = new Cesium.Cartesian3(400000.0, 300000.0, 200000.0);
以上代码貌似没有使用ConstantProperty,实际上他是等同于:
blueBox.box.dimensions = new ConstantProperty(new Cesium.Cartesian3(400000.0, 300000.0, 200000.0));
也就是Entity的box.dimensions类型并不是Cartesian3,而是一个Property。虽然我们赋值了一个Cartesian3,但是Cesium内部会隐晦地转化成了一个ConstantProperty。注意只会隐晦地转化成ConstantProperty,而不是SampleProperty,更不是TimeIntervalCollectionProperty。
虽然叫ConstantProperty,但是,这里Constant的意思并不是说这个Property不可改变,而是说它不会随时间发生变化。
举个例子,我们可以通过 property.getValue(viewer.clock.currentTime) 方法来获取某个时间点property的属性值。如果property是SampleProperty或者TimeIntervalCollectionProperty的话,不同的时间点,可能getValue出不同的数值。但是如果这个property是ConstantProperty,那么无论什么时间(getValue的第一个参数不起作用),最后返回的数值都是一样的。
但是不会随时间变化,并不代表不可改变。ConstantProperty还有一个setValue的方法,开发者可以通过调用它,来在适当的时候改变property的值。
比如,我可以通过点击按钮来修改ConstantProperty,代码如下:
blueBox.box.dimensions.setValue(new Cesium.Cartesian3(400000.0, 300000.0, 700000.0));
需要注意的是,虽然最终效果一样,但是以下两种写法的意义是不一样的。
blueBox.box.dimensions = new Cesium.Cartesian3(400000.0, 300000.0, 200000.0);
blueBox.box.dimensions.setValue(new Cesium.Cartesian3(400000.0, 300000.0, 700000.0));
前者会创建一个新的ConstantProperty,后者则会修改原有的ConstantProperty的值。
CompositeProperty
CompositeProperty的意思是组合的Property,可以把多种不同类型的ConstantProperty、SampleProperty、TimeIntervalCollectionProperty等Property组合在一起来操作。比如前一个时间段需要线性运动,后一段时间再跳跃式运动。则可以使用类似下面这段代码来实现。
// 1 sampledProperty
var sampledProperty = new Cesium.SampledProperty(Cesium.Cartesian3);
sampledProperty.addSample(Cesium.JulianDate.fromIso8601('2019-01-01T00:00:00.00Z'),
new Cesium.Cartesian3(400000.0, 300000.0, 200000.0));
sampledProperty.addSample(Cesium.JulianDate.fromIso8601('2019-01-02T00:00:00.00Z'),
new Cesium.Cartesian3(400000.0, 300000.0, 400000.0));
// 2 ticProperty
var ticProperty = new Cesium.TimeIntervalCollectionProperty();
ticProperty.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
iso8601 : '2019-01-02T00:00:00.00Z/2019-01-02T06:00:00.00Z',
isStartIncluded : true,
isStopIncluded : false,
data : new Cesium.Cartesian3(400000.0, 300000.0, 400000.0)
}));
ticProperty.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
iso8601 : '2019-01-02T06:00:00.00Z/2019-01-02T12:00:00.00Z',
isStartIncluded : true,
isStopIncluded : false,
data : new Cesium.Cartesian3(400000.0, 300000.0, 500000.0)
}));
ticProperty.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
iso8601 : '2019-01-02T12:00:00.00Z/2019-01-02T18:00:00.00Z',
isStartIncluded : true,
isStopIncluded : false,
data : new Cesium.Cartesian3(400000.0, 300000.0, 600000.0)
}));
ticProperty.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
iso8601 : '2019-01-02T18:00:00.00Z/2019-01-03T23:00:00.00Z',
isStartIncluded : true,
isStopIncluded : true,
data : new Cesium.Cartesian3(400000.0, 300000.0, 700000.0)
}));
// 3 compositeProperty
var compositeProperty = new Cesium.CompositeProperty();
compositeProperty.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
iso8601 : '2019-01-01T00:00:00.00Z/2019-01-02T00:00:00.00Z',
data : sampledProperty
}));
compositeProperty.intervals.addInterval(Cesium.TimeInterval.fromIso8601({
iso8601 : '2019-01-02T00:00:00.00Z/2019-01-03T00:00:00.00Z',
isStartIncluded : false,
isStopIncluded : false,
data : ticProperty
}));
// 4 设置position
blueBox.box.dimensions = compositeProperty;
最终实现的效果如下:

PositionProperty
以上示例可以看到,我们一直在用SampledProperty、ConstantProperty等来修改Entity的box.dimensions属性。基本上可以得出结论:大部分Property都是可以赋值给Entity的box.dimensions的。
PositionProperty和Property一样,是一个虚类,并不能直接实例化,他扩展了Property的接口,增加了referenceFrame,同时只能用来表示position。

referenceFrame是用来表示position的参考架。目前Cesium有以下两种参考架。

我们常用的是FIXED这种默认类型,它相当于以地球的中心作为坐标系的原点,x轴正向指向赤道和本初子午线的交点。(可能描述不准确。。)这样我们给定一个笛卡尔坐标(x, y, z),它在地球上的位置是固定的。
而INERTIAL这种类型,则相当于以太阳系的质心为原点的坐标架偏移到地球的中心来,如果给定一个笛卡尔坐标(x, y, z),那么它在不同的时间表示的是地球上的不同位置。。(我的理解,可能有误。。)
一般情况下,我们用不上INERTIAL。但是如果真的给定了INERTIAL下的坐标点,Cesium内部会通过PositionProperty,把它转成同一个FIXED下的坐标点来使用,这些不需要我们操作。
但是,因为普通的Property是没有办法进行这种参考架的自动转换的,所以Cesium派生了一批PositionProperty类型。
基于PositionProperty的类型有以下几种:
CompositePositionProperty
ConstantPositionProperty
PositionProperty
PositionPropertyArray
SampledPositionProperty
TimeIntervalCollectionPositionProperty
稍加留意,就会发现,和普通的Property相比,只是多了一个Position,所以用法上也大同小异,只不过他们是用来专门表示位置的。
SampledPositionProperty
SampledPositionProperty的用法,不多解释,直接看代码吧:
var property = new Cesium.SampledPositionProperty();
property.addSample(Cesium.JulianDate.fromIso8601('2019-01-01T00:00:00.00Z'),
Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0));
property.addSample(Cesium.JulianDate.fromIso8601('2019-01-03T00:00:00.00Z'),
Cesium.Cartesian3.fromDegrees(-114.0, 45.0, 300000.0));
blueBox.position = property;
效果如下:

SampleProperty和SampledPositionProperty有一个特有的方法:setInterpolationOptions,用来修改不同的插值方式。以下是以Cesium的Interpolation示例中的截图来说明他们的不同之处。
线性插值

代码写法如下:
entity.position.setInterpolationOptions({
interpolationDegree : 1,
interpolationAlgorithm : Cesium.LinearApproximation
});
Lagrange插值

entity.position.setInterpolationOptions({
interpolationDegree : 5,
interpolationAlgorithm : Cesium.LagrangePolynomialApproximation
});
Hermite插值

entity.position.setInterpolationOptions({
interpolationDegree : 2,
interpolationAlgorithm : Cesium.HermitePolynomialApproximation
});
MaterialProperty
MaterialProperty是用来专门表示材质的Property,它对Property进行了扩展,增加了getType方法,用来获取材质类型。

MaterialProperty也是一个虚基类,派生类有:
CheckerboardMaterialProperty
ColorMaterialProperty
CompositeMaterialProperty
GridMaterialProperty
ImageMaterialProperty
MaterialProperty
PolylineArrowMaterialProperty
PolylineDashMaterialProperty
PolylineGlowMaterialProperty
PolylineOutlineMaterialProperty
StripeMaterialProperty
使用上大同小异,我们以ColorMaterialProperty来说明一下。
ColorMaterialProperty
blueBox.box.material = new Cesium.ColorMaterialProperty(new Cesium.Color(0, 1, 0));
// 以上代码等同于
// blueBox.box.material = new Cesium.Color(0, 1, 0);
效果如下:

ColorMaterialProperty的动态变化
如果希望Color动起来的话,也是可以的。ColorMaterialProperty的内部有一个color属性,可以赋予一个SampledProperty来实现动态效果。
var colorProperty = new Cesium.SampledProperty(Cesium.Color);
colorProperty.addSample(Cesium.JulianDate.fromIso8601('2019-01-01T00:00:00.00Z'),
new Cesium.Color(0, 1, 0));
colorProperty.addSample(Cesium.JulianDate.fromIso8601('2019-01-03T00:00:00.00Z'),
new Cesium.Color(0, 0, 1));
blueBox.box.material = new Cesium.ColorMaterialProperty(colorProperty);
效果如下:

其他类型的Property
CallbackProperty
CallbackProperty是自由度最高的一种Property,让用户通过自定义,回调函数,来返回需要的值。回调函数中,用户可以使用time来给定value,也可以以自己的方式给给定。
以下代码就是不通过time,自己手动调整dimension的示例。
var l = 200000.0;
var property = new Cesium.CallbackProperty(function (time, result) {
result = result || new Cesium.Cartesian3(0, 0, 0);
l += 10000.0;
if (l > 700000.0) {
l = 200000.0;
}
result.x = 400000.0;
result.y = 300000.0;
result.z = l;
return result;
}, false);
blueBox.box.dimensions = property;
效果如下:

ReferenceProperty
该Property可以直接链接到别的对象的Property上,相当于引用,省得自己构建了。比如这里我创建了一个红色的盒子redBox,希望它和之前的蓝色盒子一起变大。那么可以使用以下代码:
var collection = viewer.entities;
redBox.box.dimensions = new Cesium.ReferenceProperty(collection, blueBox.id, ['box', 'dimensions']);
效果如下:


ReferenceProperty构造函数的参数有三个。第一个参数用来指定需要引用的对象所属的collection,如果没有自己专门创建EntityCollection的话,可以直接使用viewer.entities。第二个参数传递所指对象的id。第三个参数指定属性的位置的数组,如果是有层级的属性,可以依次写入。比如 ['billboard', 'scale']
指定的是entity.billboard.scale 属性。当然还有其他设置方式,可以参见Cesium的api文档。
PropertyBag
PropertyBag虽然不是以Property结尾,但实际上也是一个Property。它的特点是可以包装一个对象(JS中的对象概念),该对象的每一个属性(JS中的属性概念),都可以作为一个动态的Property。
比如之前修改dimensions的话,dimensions是作为一个Cartesian3类型变量整体封装到Property中去的,如果我们只想修改dimensions的x。则可以使用PropertyBag来实现,代码如下:
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
});

效果和sampleProperty类似,但是修改的只是dimensions的x。
PropertyArray
PropertyArray和上述的PropertyBag类似,只是其内部封装了一个数组而已。这里不再赘述。
VelocityOrientationProperty
该Property用来Entity的position的位置变化,来计算出移动的方向,最后把速度方向输出成Orientation。Cesium自带的示例中有一个Interpolation中有其用法,不再赘述。
VelocityVectorProperty
与上面的Property类似,把速度方向转成Vector。使用示例如下:
blueBox.box.show = false;
blueBox.billboard = {
scale: 0.05,
image : 'https://upload-images.jianshu.io/upload_images/80648-5dfe8a3ea2c250be.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/540/format/webp',
alignedAxis : new Cesium.VelocityVectorProperty(blueBox.position, true) // alignedAxis must be a unit vector
};
可见图像的摆放方向和位置移动的方向保持一致。效果如下:

附录
转载:Cesium的Property机制总结的更多相关文章
- Cesium的Property机制总结[转]
https://www.jianshu.com/p/f0b47997224c 前言 Cesium官方教程中有一篇叫<空间数据可视化>(Visualizing Spatial Data).该 ...
- Cesium的Property机制总结
前言 Cesium官方教程中有一篇叫<空间数据可视化>(Visualizing Spatial Data).该文文末简单提到了Cesium的Property机制,然后话锋一转,宣告此教程的 ...
- 深入讲解Android Property机制
深入讲解Android Property机制 侯亮 1 概述 Android系统(本文以Android 4.4为准)的属性(Property)机制有点儿类似Windows系统的注册表,其中的 ...
- 转载 C++实现的委托机制
转载 C++实现的委托机制 1.引言 下面的委托实现使用的MyGUI里面的委托实现,MyGUI是一款强大的GUI库,想理解更多的MyGUI信息,猛击这里http://mygui.info/ 最终的代码 ...
- 转载:Java Lock机制解读
Java Lock机制解读 欢迎转载: https://blog.csdn.net/chengyuqiang/article/details/79181229 1.synchronized synch ...
- [转载]Python使用@property装饰器--getter和setter方法变成属性
原贴:为什么Python不需要getter和setter getter 和 setter在java中被广泛使用.一个好的java编程准则为:将所有属性设置为私有的,同时为属性写getter和sette ...
- [转载]深入JVM锁机制-synchronized
转自:http://blog.csdn.net/chen77716/article/details/6618779,并加上少量自己的理解 目前在Java中存在两种锁机制:synchronized和Lo ...
- [转载]Cookie/Session的机制与安全
Cookie和Session是为了在无状态的HTTP协议之上维护会话状态,使得服务器可以知道当前是和哪个客户在打交道.本文来详细讨论Cookie和Session的实现机制,以及其中涉及的安全问题. 因 ...
- JavaScript—从数组的indexOf方法深入——Object的Property机制。
在js中,可以说万物皆对象(object),一个数组也是一个对象(array). 很多对象都有很多很方便的方法 比如数组的push,concat,slice等等,但是如果一些对象,它没有实现这些方法, ...
随机推荐
- Oracle 基表 X$KSMLRU
Oracle 基表 X$KSMLRU 该表是Oracle的一个内部表.当SQL或者PL/SQL块向shared pool中请求一个大的连续的空间时,如果shared pool中连续的可用空间 不足,就 ...
- JDBC接口核心的API
java.sql.* 和 javax.sql.* Driver接口: 表示java驱动程序接口.所有的具体的数据库厂商要来实现此接口. |- connect(url, properties): ...
- vs install 安装时自动添加注册表
思路:使用自定义 解决方案添加类库项目 添加安装程序类 随后右键查看代码 在构造函数添加事件 同时完成这个事件,在此事件中根据需要添加我们需要的内容,此处为添加注册表,并根据安装目录添加url pro ...
- linux系统安装zint
背景: 今天代码拉下了发现启动时报错,一看原来是同事用了zint的gem,我又没安,然后花了点时间解决,但其中踩了几次坑,所以打算记录下: 一.zint开源库的介绍 zint 是一个开源的条码编码库, ...
- 阶段3 3.SpringMVC·_05.文件上传_5 文件上传之跨服务器上传分析和搭建环境
使用这个jar包来跨服务器上传 搞两个tomcat.一个springmvc一个fileupload 选中tomcat server点击左边的加号 需要改端口和JMX pport这个端口 部署文件上传的 ...
- 如何解决使用 JMeter 时遇到的问题
这是对 JMeter 官方网站上一篇文章的翻译.点击这里可以访问原文JMeterTroubleShooting. • check the log file. This is normally in t ...
- visual studio 2019不能在vue文件中直接识别less语法
试了好多方法,不象vs code那样能直接在template vue文件中就识别less语法下边这种分离的方式是可以的,在项目中也比较实用,将来你代码量大了,样式/脚本也还是要和template代码分 ...
- Eureka 2.0 闭源--选择Consul???[转]
原文链接: https://www.cnblogs.com/williamjie/p/9369800.html 在上个月我们知道 Eureka 2.0 闭源了,但其实对国内的用户影响甚小,一方面国内大 ...
- git 提交项目到远程仓库,简单实现忽略 node_modules文件
在项目根目录中创建 .gitignore文件 在文件中添加你要忽略的文件 .DS_Store node_modules /dist # local env files .env.local .env. ...
- 【科普杂谈】一文看懂大数据的技术生态圈,Hadoop,hive,spark都有了
大数据本身是个很宽泛的概念,Hadoop生态圈(或者泛生态圈)基本上都是为了处理超过单机尺度的数据处理而诞生的.你可以把它比作一个厨房所以需要的各种工具.锅碗瓢盆,各有各的用处,互相之间又有重合.你可 ...