时钟Clock及时序控制

6/9/2023

平台的强大之处也在于其可以将时间运用到三维地球上,平台不仅仅是3D的地理空间的展示,同时也具备“时间维度”的时序的相关控制,具备空间+时间的管理,可以根据“时间”进行动画、轨迹记录、地球的光照等等所有与时间相关的可视化效果。

# 1. 打开时间相关控件

为了更好理解Clock,我们可以在地图中打开2个Cesium内置时钟Clock相关的控件。

//合并属性参数,可覆盖config.json中的对应配置
var mapOptions = mars3d.Util.merge(options, { 
   control: { 
       clockAnimate: true, // 时钟动画控制(左下角)
       timeline: true, // 是否显示时间线控件 
   },
}) 
//创建三维地球场景
let map = new mars3d.Map('mars3dContainer', mapOptions) 
1
2
3
4
5
6
7
8
9

运行效果: image

# 2. 时序控制相关对象

# 2.1 clock时钟对象

map.clock (opens new window) 时钟对象,由三维地图内部创建的Clock (opens new window)类,可以对时间维度做相关控制。

clock对象是一个同步系统时间的一个对象,想要实现时间驱动数据的动态化渲染,都需要clock对象去创建一个时间序列。一般来说电脑屏幕的刷新率都是60hz,cesium定义的是每秒刷新60次,每帧需要的时间大概是16.67mm。

Clock中默认开始时间(startTime)为当前时间,终止时间(stopTime)为24小时后,并能获取当前时间(currentTime)。

clock对象的构造器有以下几个常用属性:

  • map.clock.shouldAnimate = true : 控制时钟暂停和继续
  • map.clock.startTime = Cesium.JulianDate.fromIso8601('2017-08-25'):开始时间
  • map.clock.stopTime = Cesium.JulianDate.fromIso8601('2017-08-26'):结束时间
  • map.clock.currentTime = Cesium.JulianDate.fromIso8601('2017-08-25T12:18:20Z') :当前时间
  • map.clock.multiplier= 2.0:时间速率(快速播放与慢速播放),默认1.0
  • map.clock.clockRange = Cesium.ClockRange.UNBOUNDED:表示时间轴达到终点之后的行为, 可选值:CLAMPED 达到终止时间后停止,LOOP_STOP 达到终止时间后重新循环,UNBOUNDED 达到终止时间后继续读秒。

# 2.2 Cesium.JulianDate 时间类

Clock内部以儒略日(JulianDate)维护时间。其起始日期为公元前4713年1月1日中午12时,这和我们常用的格林威治时间略有不同,主要是天文学家使用。

Cesium.JulianDate类 (opens new window)提供了非常丰富的接口,时间的对比,运算,和格林威治时间的转换等,简单易用,完全满足各类需求。同时内部还可以采用国际原子时(TAI)的方式来记录。

# 3. 时序控制的应用

# 3.1 动态加载时间序列瓦片

所谓时间序列瓦片是指存在多套瓦片,每套瓦片不是单独的,与时间有关。比如我们每天拍摄一遍地球影像,然后把每天的影像都做成一套瓦片,那么一年下来就会有365套瓦片,采用传统方案我们只能写365个页面每个页面加载一天的瓦片。这样非常麻烦,并且没有一个动态变化的效果也无法进行对比。

时间序列瓦片与普通瓦片的区别正在此处。其创建时需要多指定与时间有关的参数。如下:

//interval表示传入的时间区间,index表示是第几个区间,这两个参数也就分割了times中的完整时间段,所以我们可以给time赋值为任意想要设置的值。
function dataCallback(interval, index) {
   console.log(index);
   var time;
   if (index === 0) {
       time = Cesium.JulianDate.toIso8601(interval.stop);
   } else {
       time = Cesium.JulianDate.toIso8601(interval.start);
   }
   //返回的是key、value形式,此处Time为key,而其必须与创建图层时候的{Time}字符串一致,否则请求的时候无法替换时间信息。
   return {
       Time: time
   };
}

var times = Cesium.TimeIntervalCollection.fromIso8601({
   iso8601: '2015-07-30/2017-06-16/P20D', //iso8601参数为时间范围及间隔,用'/'分割,第一个表示开始时间,第二个表示结束时间,P20D表示间隔20天,还可以是P1M、P1Y、P1Y3M5DT6H7M30S等,代表不同的时间间隔。
   leadingInterval: true,
   trailingInterval: true,
   isStopIncluded: false,
   dataCallback: dataCallback //dataCallback表示在每个时间段内如何取值
});

var  tileLayer = new mars3d.layer.WmtsLayer({
   url : 'https://gibs.earthdata.nasa.gov/wmts/epsg4326/{best}/{Layer}/{Style}/{Time}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png', //{TileMatrix}/{TileRow}/{TileCol}表示z、x、y,无需手动设置
   layer : 'AMSR2_Snow_Water_Equivalent',
   style : 'default',//style参数会替换掉url中的{Style}字符串
   tileMatrixSetID : '2km', //tileMatrixSetID会替换掉{TileMatrixSet}字符串
   format : 'image/png',
   dimensions: {//dimensions里面的参数只要出现在url中全部会被其value替换掉。
       Layer : 'AMSR2_Snow_Water_Equivalent',
       best: 'best'
   },
   clock: map.clock, //clock表示所使用的时钟,直接设置为系统时钟
   times: times, //重点
   maximumLevel : 5
})
map.addLayer(tileLayer)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 3.2 动画轨迹

在平台中,提供SampledPositionProperty类 (opens new window) 来实现矢量对象的时序控制,达到 模型等点状对象 沿轨迹平滑移动的目的。只需要指定每个时间对应的坐标即可,中间平台自动进行按时间平滑动画移动。

//构造时序轨迹对象
let propertyFJ = getSampledPositionProperty([
    [116.341348, 30.875522, 500],
    [116.341432, 30.871815, 500], 
    [116.341181, 30.85326, 500], 
    [116.345028, 30.870436, 500],
])

//飞机模型
var graphicModel = new mars3d.graphic.ModelEntity({
    position: propertyFJ,
    orientation: new Cesium.VelocityOrientationProperty(propertyFJ),
    style: {
        url: 'http://data.mars3d.cn/gltf/mars/wrj.glb',
        scale: 0.1,
        minimumPixelSize: 20,
    },
})
graphicLayer.addGraphic(graphicModel)


//计算演示的轨迹
function getSampledPositionProperty(points) {
    let property = new Cesium.SampledPositionProperty()

    let start = map.clock.currentTime
    let positions = mars3d.LngLatArray.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
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

运行效果

新窗口查看

最后更新: 2/26/2024, 4:48:00 PM