平台是数据驱动和 time-dynamic visualization,这些可都是仰仗Property属性机制来实现的。

Property最大的特点是和时间相互关联,在不同的时间可以动态地返回不同的属性值。而Entity则可以感知这些Property的变化,在不同的时间驱动物体进行动态展示。

#运行效果

新窗口查看

注:为了方便理解,可以参考示例源码去调试体验进行理解。

#1.为什么要用Property?

还是举个例子来说吧。比如我想在地球上的某个位置加一个盒子,可以这样写代码:

// 创建盒子
var marsBox = new mars3d.graphic.BoxEntity({position: [117.220164, 31.834887, 39.6],style: {dimensions: new Cesium.Cartesian3(400.0, 300.0, 500.0),color: 'rgba(0,255,255,0.8)',outline: true,},
})
graphicLayer.addGraphic(marsBox)

box加在固定位置。 但是呢,如果我想让这个盒子逐渐变长,该怎么操作呢?如下图所示:

盒子逐渐变长 方法是有的,就是可以不停地去修改marsBox.position,类似这样:

setInterval(function(){ marsBox.entityGraphic.dimensions = xxx; }, 200);

如果场景中有很多物体,在不同的时间段要发生各种走走停停地运动时,这样操作可能会很累人。那么Cesium就提供一种机制,让dimensions可以随时间自动发生变化,自动赋予不同的数值(位置)。这也就是property的作用了。以下代码的加入,就可以让盒子如上图所示做线性运动了。

var property = new Cesium.SampledProperty(Cesium.Cartesian3)
property.addSample(Cesium.JulianDate.fromDate(new Date('2017-08-25 08:00:00')), new Cesium.Cartesian3(400.0, 300.0, 100.0))
property.addSample(Cesium.JulianDate.fromDate(new Date('2017-08-25 08:00:20')), new Cesium.Cartesian3(400.0, 300.0, 900.0))
marsBox.setStyle({ dimensions: property })

以上代码的意思就是在两个不同的时间点分别赋予不同的位置,用SampledProperty包装成一个property,最后赋给marsBox的dimensions样式。

由此可见,Property最大的特点是和时间相互关联,在不同的时间可以动态地返回不同的属性值。而Entity则可以感知这些Property的变化,在不同的时间驱动物体进行动态展示。

平台是数据驱动和 time-dynamic visualization,这些可都是仰仗Property属性机制来实现的。

当然,Property可不只是这么简单,以下再详细论述。

#2.Property的分类

Cesium的Property不止有刚才示例代码中的SampleProperty,还有很多其他的类型。如果搜索一下Cesium的API文档,会有很多。如下图所示:

Cesium API文档搜索Property 我们简单分类一下

#2.Property虚基类

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

Property类型的公共接口

  • getValue 是一个方法,用来获取某个时间点的特定属性值。它有两个参数:第一个是time,用来传递一个时间点;第二个是result,用来存储属性值,当然也可以是undefined。这个result是Cesium的scratch机制,主要是用来避免频繁创建和销毁对象而导致内存碎片。Cesium就是通过调用getValue类似的一些函数来感知Property的变化的,当然这个方法我们在外部也是可以使用的。

  • isConstant 用来判断该属性是否会随时间变化,是一个布尔值。Cesium会通过这个变量来决定是否需要在场景更新的每一帧中都获取该属性的数值,从而来更新三维场景中的物体。如果isConstant为true,则只会获取一次数值,除非definitionChanged事件被触发。

  • definitionChanged 是一个事件,可以通过该事件,来监听该Property自身所发生的变化,比如数值发生修改。

  • equals 是一个方法,用来检测属性值是否相等。

#2.基本Property类型

#2. SampleProperty类

SampleProperty类 是我们最早在上述示例中使用的就是它,用来通过给定多个不同时间点的Sample,然后在每两个时间点之间进行线性插值的一种Property。代码写法如下:

var property = new Cesium.SampledProperty(Cesium.Cartesian3)
property.addSample(Cesium.JulianDate.fromDate(new Date('2017-08-25 08:00:00')), new Cesium.Cartesian3(400.0, 300.0, 100.0))
property.addSample(Cesium.JulianDate.fromDate(new Date('2017-08-25 08:00:20')), new Cesium.Cartesian3(400.0, 300.0, 900.0))
//让盒子一直存在
// property.addSample(Cesium.JulianDate.fromDate(new Date('2017-08-26 00:00:00')), new Cesium.Cartesian3(400.0, 300.0, 900.0))marsBox.setStyle({ dimensions: property })

盒子逐渐变长

#2. TimeIntervalCollectionProperty

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

代码如下:

var property = new Cesium.TimeIntervalCollectionProperty()
property.intervals.addInterval(Cesium.TimeInterval.fromIso8601({iso8601: '2017-08-25T00:00:00.00Z/2017-08-25T00:00:02.00Z',isStartIncluded: true,isStopIncluded: false,data: new Cesium.Cartesian3(400.0, 300.0, 200.0),})
)
property.intervals.addInterval(Cesium.TimeInterval.fromIso8601({iso8601: '2017-08-25T00:00:02.00Z/2017-08-25T00:00:04.00Z',isStartIncluded: true,isStopIncluded: false,data: new Cesium.Cartesian3(400.0, 300.0, 400.0),})
)
property.intervals.addInterval(Cesium.TimeInterval.fromIso8601({iso8601: '2017-08-25T00:00:04.00Z/2017-08-25T00:00:06.00Z',isStartIncluded: true,isStopIncluded: false,data: new Cesium.Cartesian3(400.0, 300.0, 500.0),})
)
property.intervals.addInterval(Cesium.TimeInterval.fromIso8601({iso8601: '2017-08-25T00:00:06.00Z/2017-08-25T00:00:08.00Z',isStartIncluded: true,isStopIncluded: true,data: new Cesium.Cartesian3(400.0, 300.0, 700.0),})
)marsBox.setStyle({ dimensions: property })

#2. ConstantProperty

通过对TimeIntervalCollectionProperty和SampleProperty的描述,读者应该基本了解Property的特点。 我们回过头来说下 ConstantProperty ,其实这才是最常用的Property,也是平台默认使用的Property。

示例代码如下:

let dimensions = new Cesium.Cartesian3(400.0, 300.0, 200.0);
marsBox.setStyle({dimensions:dimensions})

以上代码貌似没有使用ConstantProperty,实际上他是等同于:

let dimensions = new ConstantProperty(new Cesium.Cartesian3(400.0, 300.0, 200.0));
marsBox.setStyle({dimensions:dimensions})

也就是Entity的 dimensions style样式并不是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,代码如下:

marsBox.entityGraphic.dimensions.setValue(new Cesium.Cartesian3(400.0, 300.0, 700.0));

需要注意的是,虽然最终效果一样,但是以下两种写法的意义是不一样的。

//会创建一个新的ConstantProperty
marsBox.entityGraphic.dimensions = new Cesium.Cartesian3(400.0, 300.0, 200.0);
//会修改原有的ConstantProperty的值。
marsBox.entityGraphic.dimensions.setValue(new Cesium.Cartesian3(400.0, 300.0, 700.0));

#2. CompositeProperty

CompositeProperty 的意思是组合的Property,可以把多种不同类型的ConstantProperty、SampleProperty、TimeIntervalCollectionProperty等Property组合在一起来操作。比如前一个时间段需要线性运动,后一段时间再跳跃式运动。则可以使用类似下面这段代码来实现。

// 1 sampledProperty
var sampledProperty = new Cesium.SampledProperty(Cesium.Cartesian3)
sampledProperty.addSample(Cesium.JulianDate.fromIso8601('2017-08-25T00:00:00.00Z'), new Cesium.Cartesian3(400.0, 300.0, 100.0))
sampledProperty.addSample(Cesium.JulianDate.fromIso8601('2017-08-25T00:00:10.00Z'), new Cesium.Cartesian3(400.0, 300.0, 500.0))// 2 ticProperty
var ticProperty = new Cesium.TimeIntervalCollectionProperty()
ticProperty.intervals.addInterval(Cesium.TimeInterval.fromIso8601({iso8601: '2017-08-25T00:00:10.00Z/2017-08-25T00:00:12.00Z',isStartIncluded: true,isStopIncluded: false,data: new Cesium.Cartesian3(400.0, 300.0, 600.0),})
)
ticProperty.intervals.addInterval(Cesium.TimeInterval.fromIso8601({iso8601: '2017-08-25T00:00:12.00Z/2017-08-25T00:00:14.00Z',isStartIncluded: true,isStopIncluded: false,data: new Cesium.Cartesian3(400.0, 300.0, 700.0),})
)
ticProperty.intervals.addInterval(Cesium.TimeInterval.fromIso8601({iso8601: '2017-08-25T00:00:14.00Z/2017-08-25T00:00:16.00Z',isStartIncluded: true,isStopIncluded: false,data: new Cesium.Cartesian3(400.0, 300.0, 800.0),})
)
ticProperty.intervals.addInterval(Cesium.TimeInterval.fromIso8601({iso8601: '2017-08-25T00:00:16.00Z/2017-08-25T00:00:18.00Z',isStartIncluded: true,isStopIncluded: true,data: new Cesium.Cartesian3(400.0, 300.0, 900.0),})
)// 3 compositeProperty
var compositeProperty = new Cesium.CompositeProperty()
compositeProperty.intervals.addInterval(Cesium.TimeInterval.fromIso8601({iso8601: '2017-08-25T00:00:00.00Z/2017-08-25T00:00:10.00Z',data: sampledProperty,})
)
compositeProperty.intervals.addInterval(Cesium.TimeInterval.fromIso8601({iso8601: '2017-08-25T00:00:10.00Z/2017-08-25T00:00:20.00Z',isStartIncluded: false,isStopIncluded: false,data: ticProperty,})
)// 4 设置dimensions
marsBox.setStyle({ dimensions: compositeProperty })

最终实现的效果如下:

#2. PositionProperty坐标属性

基于PositionProperty的类型有以下几种:

  • CompositePositionProperty
  • ConstantPositionProperty
  • PositionProperty
  • PositionPropertyArray
  • SampledPositionProperty
  • TimeIntervalCollectionPositionProperty

稍加留意,就会发现,和普通的Property相比,只是多了一个Position,所以用法上也大同小异,只不过他们是用来专门表示位置的。

#2. SampledPositionProperty

SampledPositionProperty 的用法,不多解释,直接看代码吧:

var property = new Cesium.SampledPositionProperty()
property.addSample(Cesium.JulianDate.fromDate(new Date('2017-08-25 08:00:00')), Cesium.Cartesian3.fromDegrees(117.198461, 31.834956, 40.2))
property.addSample(Cesium.JulianDate.fromDate(new Date('2017-08-25 08:00:20')), Cesium.Cartesian3.fromDegrees(117.231979, 31.833411, 35.6))marsBox.position = property

效果如下:

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

//线性插值
marsBox.position.setInterpolationOptions({interpolationDegree : 1,interpolationAlgorithm : Cesium.LinearApproximation
});//Lagrange插值
marsBox.position.setInterpolationOptions({interpolationDegree : 5,interpolationAlgorithm : Cesium.LagrangePolynomialApproximation
});//Hermite插值
marsBox.position.setInterpolationOptions({interpolationDegree : 2,interpolationAlgorithm : Cesium.HermitePolynomialApproximation
});

#2. MaterialProperty

MaterialProperty 是用来专门表示材质的Property,它对Property进行了扩展,增加了getType方法,用来获取材质类型。 效果如下:

MaterialProperty也是一个虚基类,派生类有:

  • CheckerboardMaterialProperty
  • ColorMaterialProperty
  • CompositeMaterialProperty
  • GridMaterialProperty
  • ImageMaterialProperty
  • PolylineArrowMaterialProperty
  • PolylineDashMaterialProperty
  • PolylineGlowMaterialProperty
  • PolylineOutlineMaterialProperty
  • StripeMaterialProperty
  • CircleScanMaterialProperty
  • CircleWaveMaterialProperty
  • LineFlowMaterialProperty
  • TextMaterialProperty
  • WaterMaterialProperty
  • ……

使用上大同小异,我们以 ColorMaterialProperty 来说明一下。

marsBox.setStyle({ material: new Cesium.ColorMaterialProperty(new Cesium.Color(0, 1, 0)) })
// 以上代码等同于
marsBox.setStyle({ material: new Cesium.Color(0, 1, 0) })

效果如下:

ColorMaterialProperty 的动态变化

如果希望Color动起来的话,也是可以的。ColorMaterialProperty的内部有一个color属性,可以赋予一个SampledProperty来实现动态效果。

var colorProperty = new Cesium.SampledProperty(Cesium.Color)
colorProperty.addSample(Cesium.JulianDate.fromDate(new Date('2017-08-25 08:00:00')), new Cesium.Color(0, 0, 1))
colorProperty.addSample(Cesium.JulianDate.fromDate(new Date('2017-08-25 08:00:10')), new Cesium.Color(1, 1, 0))marsBox.setStyle({ material: new Cesium.ColorMaterialProperty(colorProperty) })

效果如下:

#2. CallbackProperty

CallbackProperty 是自由度最高的一种Property,让用户通过自定义,回调函数,来返回需要的值。回调函数中,用户可以使用time来给定value,也可以以自己的方式给给定。

以下代码就是不通过time,自己手动调整dimension的示例。

var len = 100.0
var property = new Cesium.CallbackProperty(function (time, result) {result = result || new Cesium.Cartesian3(400.0, 300.0, 500.0)len += 3.0if (len > 900.0) {len = 100.0}result.x = 400.0result.y = 300.0result.z = lenreturn result
}, false)marsBox.setStyle({ dimensions: property })

效果如下,盒子逐渐变长:

#2. ReferenceProperty

ReferenceProperty 可以直接链接到别的对象的Property上,相当于引用,省得自己构建了。比如这里我创建了一个红色的盒子redBox,希望它和之前的蓝色盒子一起变大。那么可以使用以下代码:

以下代码就是不通过time,自己手动调整dimension的示例。

var collection = graphicLayer.dataSource.entities
let dimensions = new Cesium.ReferenceProperty(collection, marsBox.uuid, ['box', 'dimensions'])
redBox.setStyle({ dimensions: dimensions })

效果如下,盒子逐渐变长:

ReferenceProperty的使用

ReferenceProperty 构造函数的参数 ReferenceProperty构造函数的参数有三个。第一个参数用来指定需要引用的对象所属的collection,如果没有自己专门创建EntityCollection的话,可以直接使用viewer.entities。第二个参数传递所指对象的id。第三个参数指定属性的位置的数组,如果是有层级的属性,可以依次写入。比如 ['billboard', 'scale'] 指定的是entity.billboard.scale 属性。当然还有其他设置方式,可以参见API文档 。

#2. PropertyBag

PropertyBag 虽然不是以Property结尾,但实际上也是一个Property。它的特点是可以包装一个对象(JS中的对象概念),该对象的每一个属性(JS中的属性概念),都可以作为一个动态的Property。

比如之前修改dimensions的话,dimensions是作为一个Cartesian3类型变量整体封装到Property中去的,如果我们只想修改dimensions的x。则可以使用PropertyBag来实现,代码如下:

var zp = new Cesium.SampledProperty(Number)
zp.addSample(Cesium.JulianDate.fromDate(new Date('2017-08-25 08:00:00')), 100.0)
zp.addSample(Cesium.JulianDate.fromDate(new Date('2017-08-25 08:00:10')), 800.0)let dimensions = new Cesium.PropertyBag({x: 400.0,y: 300.0,z: zp,
})
marsBox.setStyle({ dimensions: dimensions })

效果如下,盒子逐渐变长:

效果和sampleProperty类似,但是修改的只是dimensions的x。

#2. PropertyArray

PropertyArray 和上述的PropertyBag类似,只是其内部封装了一个数组而已。这里不再赘述。

#2. VelocityOrientationProperty

VelocityOrientationProperty 用来Entity的position的位置变化,来计算出移动的方向,最后把速度方向输出成Orientation。Cesium自带的示例中有一个Interpolation中有其用法,不再赘述。

#2. VelocityVectorProperty

VelocityVectorProperty 与上面的Property类似,把速度方向转成Vector。使用示例如下:

//计算演示的SampledPositionProperty轨迹
function getSampledPositionProperty(points) {let property = new Cesium.SampledPositionProperty()let start = map.clock.currentTimelet positions = mars3d.LatLngArray.toCartesians(points)for (let i = 0; i < positions.length; i++) {let time = Cesium.JulianDate.addSeconds(start, i * 20, new Cesium.JulianDate())let position = positions[i]property.addSample(time, position)}return property
}let propertyFJ = getSampledPositionProperty([[117.198461, 31.834956, 40.2],[117.231979, 31.833411, 35.6],
])
var graphic = new mars3d.graphic.BillboardEntity({position: propertyFJ,orientation: new Cesium.VelocityOrientationProperty(propertyFJ),style: {image: 'img/marker/huojian.svg',scale: 0.5,alignedAxis: new Cesium.VelocityVectorProperty(propertyFJ, true),},
})
graphicLayer.addGraphic(graphic)

可见图像的摆放方向和位置移动的方向保持一致。效果如下:

Mars3D开发基础学习:Property属性机制相关推荐

  1. Mars3D开发基础学习:矢量数据

    矢量数据 是用经度.纬度.高度坐标来表示地图图形或地理实体位置的数据,一般是通过记录坐标的方式来尽可能将地理实体的空间位置表现的准确无误,常见的矢量数据有:点.线.面.体等格式. #1. 矢量数据对象 ...

  2. Mars3D开发基础学习:矢量图层

    三维场景中,地形和栅格来组成了三维的基础,但更多的业务还是需要 点线面等矢量数据来充实, 这就是我们的矢量数据图层. #1. 图层类型清单 当前主要使用的矢量图层,是指GraphicLayer 类及其 ...

  3. Mars3D开发基础学习:栅格瓦片图层

    前面我们说到地形是三维场景的"骨骼",栅格瓦片图层就是我们浏览三维能感知的"皮肤"了,通常我们叠加的是各种卫星影像或瓦片数据. Mars3D支持多种服务来源的高 ...

  4. Mars3D开发基础学习:Material材质

    在真实世界里,每个物体会对光产生不同的反应.钢看起来比陶瓷花瓶更闪闪发光,一个木头箱子不会像钢箱子一样对光产生很强的反射.每个物体对镜面高光也有不同的反应.有些物体不会散射(Scatter)很多光却会 ...

  5. Mars3D开发基础学习:坐标系及坐标变换

    只要涉及到地图开发,无论如何关于坐标系的概念是逃不掉的,谁让地球它是个球呢. 地球就像个橘子 不同的坐标系就是不同的剝橘子的方法 这里就不列举国内常用的坐标系及转换方法,大家可以自行百度. 相关GIS ...

  6. Mars3D开发基础学习:场景特效

    平台支持一些场景特效,包括 雾天气,雨天气,雪天气, 泛光特效,亮度效果,夜视效果,黑白效果,马赛克效果,景深效果 等. #1. 特效的底层实现:后处理(Post Processing) 特效底层是使 ...

  7. Mars3D开发基础学习:相机Camera及视角控制

    Camera相机控制了三维场景的视图.有很多方法可以操作Camera,如旋转(rotate).缩放(zoom).平移(pan)和飞到目的地(flyTo).同时也有鼠标和触摸事件用来处理与Camrea的 ...

  8. Mars3D开发基础学习:glTF小模型

    glTF全称是 Graphics Language Transmission Format (图形语言传输格式),是一种针对GL(WebGL,OpenGL ES以及OpenGL)接口的运行时资产传递格 ...

  9. ASP.Net MVC开发基础学习笔记(5):区域、模板页与WebAPI初步

    http://blog.jobbole.com/85008/ ASP.Net MVC开发基础学习笔记(5):区域.模板页与WebAPI初步 2015/03/17 · IT技术 · .Net, Asp. ...

最新文章

  1. 自动化Build的方法如下所示
  2. 前众信旅游B端产品经理吴彪:如何搭建B端电商产品及用户体系
  3. 梯度下降法进行线性回归---------二维及多维
  4. SAP云平台ABAP编程环境免费账号使用过程中的一些问题
  5. IOS中关于MBProgressHUD的使用
  6. HDFS分布式文件系统设计思想
  7. maven build时报错Failed to execute goal org.apache.maven.plugins......
  8. Linux内核第二节
  9. java 是怎么跨平台运行的
  10. 【C++】【GADL】读取栅格数据获取信息
  11. 局域网和内网?系统远程桌面和内网远程软件?
  12. 从asp空间下载apk文件
  13. 天猫精灵通过AliOS网桥控制Zigbee设备
  14. Git常用命令、及常见报错处理:You have not concluded your merge (MERGE_HEAD exists)
  15. 前端技术探索 - 你不知道的JS 沙箱隔离
  16. 基于 ESO-PLL 的永磁同步电机无位置传感器控制
  17. 自己动手丰衣足食之图片放大镜
  18. 数据分析——“鲍鱼的年龄”数据集
  19. FEKO地平面的设置和计算参数的定义
  20. 针对TEXworks使用bibtex仍无法出现参考文献格式的解决方法

热门文章

  1. 鼠标点击添加动态类名active
  2. 跟刀客一起追寻昨日的足迹
  3. 实战 | OpenCV如何将不同轮廓合并成一个轮廓(附Python / C++源码)
  4. 现在投资区块链还来得及吗?一个因素决定IPFS的颠覆价值
  5. git 修改倒数二个 commit
  6. git 修改历史信息
  7. 用python抓取智联招聘信息并存入excel
  8. 加减法叫做什么运算_加减法四则运算的计算方法是什么
  9. 完全用Linux工作,作者王垠
  10. moviepy截取视频片段的两种方法