Cesium场景之卫星轨道展示

Cesium场景之卫星轨道展示 | DLLCNX的博客

cesium在进行动画展示这一块的功能比较完善。最近有一个需求,需要进行模拟卫星的飞行轨迹,如果可以实现,针对扫描卫星需要添加模拟扫描光波。

当我首先针对需求进行卫星,将卫星运行与扫描进行拆分,当利用cesium的api实现卫星轨道后,能否针对卫星模型绑定一个固定的扫描的模型上去。后期这个想法被我抛弃了,因为我之前二维做的多,三维这一块有部分经验,但是都没有深入了解过,所以我将二维的思想带入了cesium的体系中,也走了不少绕路,cesium针对模拟动画其实有更完美的解决方案,下面我简单介绍一下自己的思维历程。

模型法

首先,我认为既然要实现卫星扫描轨迹,那么肯定需要两个模型:卫星模型和扫描模型。卫星模型网上有,glb或者gltf的都行,而扫描模型我直接使用Cesium的几何模型去实现圆锥即可。

1.初始化Vierer
  viewer = new Cesium.Viewer('cesiumContainer', {
    shouldAnimate: true,   // 这个值比较特殊,如果为true页面渲染后自动执行动画,反之需要自己手动去点击开始
    geocoder: false, // 隐藏查找位置
    homeButton: false, // 隐藏返回视角到初始位置
    sceneModePicker: false, // 隐藏视角模式的选择
    baseLayerPicker: false, // 隐藏图层选择器
    navigationHelpButton: false, // 隐藏帮助
    timeline: true, // 隐藏时间轴
    fullscreenButton: false, // 隐藏全屏按钮
    animation: true, // 隐藏动画速度控制器
    infoBox: false, // 点击的详情弹窗entity的description可以描述html显示在弹窗中,也可以通过viewer.infoBox.frame来接入访问
  });
2. 时间定义

动画的执行都是与时间有关的,从什么时间开始,到什么时间结束。而Cesium使用了不同于我们js常用的时间规范,需要用到Cesium.JulianDateCesium.JulianDate 是指示在 Cesium 中添加或描述对象动画时使用的 Julian Date 格式的时间标签。Julian Date 是以天为单位计数的相对格林尼治标准时间的一种计时法。

所以以下代码意思我们以当前时间为基准,6分钟内执行动画。但是速率是10.

// 定义开始时间
start = Cesium.JulianDate.addHours(new Cesium.JulianDate.fromDate(new Date()), 8, new Cesium.JulianDate());把js中的时间转换为JulianDate时间,东八区时间

// 定义结束时间,360秒后
stop = Cesium.JulianDate.addSeconds(start, 360, new Cesium.JulianDate());

//确保查看器处于预期的时间
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //循环结束时

//时间变化来控制速度 // 时间速率,数字越大时间过的越快
viewer.clock.multiplier = 10;

//给时间线设置边界
viewer.timeline.zoomTo(start, stop);

Cesium.JulianDate.addHours() :是一种可以在 Julian 时间戳上增加指定小时数的方法。Cesium.JulianDate.addSeconds()同理增加秒。

  • julianDate - Julian 日期时刻,可以是 JulianDate 对象或 secondsSinceEpoch 值。

  • hours - 要添加的小时数,可以为负值表示减小。

  • result - 可选,用于存储结果的 JulianDate 对象。

Cesium.JulianDate.clone():用于克隆一个 JulianDate 对象。

viewer.timeline.zoomTo(start, stop)方法可以用来在时间轴控件中设置一个时间窗口并自动居中和缩放。

  • start - 时间窗口起始时间,可以是Date对象或JulianDate对象
  • stop - 时间窗口结束时间
3.轨迹处理方法

上面定义好了播放时间以及时间间隔等等,那么准备工作做完了,可以开始构建模型了。

先定义一些存储路径变量的方法:

function mySatePosition(hen) {
  this.lon = 0;  // 经度初始化
  this.lat = 0;  // 纬度初始化
  this.satelliteHeight = hen;          // 卫星高度
  this.orbitHeight = hen / 2;     // 轨道高度
  this.time = 0;      //
}

定义轨迹方法:

可以看出这个方法利用传进去的是否纬度标识,如果是就构造了一个固定纬度degree,经度360度分段的循环数组,反之一样。所以这些变量其实可以根据自己需要定义初始化或者调整。

function getRandState(ifLat, degree, hen) {
  let arr = [];
  let lat = Math.floor(Math.random() * 360);
  for (let i = lat; i <= 360 + lat; i += 30) {
    let sateP = new mySatePosition(hen);   // new一个路径变量类
    if (ifLat == 'lon') {
      sateP.lon = degree;
      sateP.lat = i;
    } else {
      sateP.lon = i
      sateP.lat = degree;
    }
    sateP.time = i - lat;
    arr.push(sateP);
  }
  return arr
}

经纬度转换为Cesium模型使用的position

function computePosition(source, panduan) {
  let property = new Cesium.SampledPositionProperty();
  for (let i = 0; i < source.length; i++) {
    let time = Cesium.JulianDate.addSeconds(start, source[i].time, new Cesium.JulianDate());
    let position = Cesium.Cartesian3.fromDegrees(source[i].lon, source[i].lat, panduan === 1 ? source[i].satelliteHeight : source[i].orbitHeight);
    property.addSample(time, position);
  }
  return property;
}
4. 模型构建

定义好上一步方法,定义模型即可。这边三个参数ifLat, degree, hen含义上面方法也需要使用,含义分别就是是否纬度,角度以及卫星高度。

  //获取路径
  let path = getRandState(ifLat, degree, hen);
  
  /**
   * 扫描圆锥
   */
   let entityPath = computePosition(path, 2);
   let entity = viewer.entities.add({
    //关联时间轴  TimeIntervalCollection管理时间间隔数据的集合  把时间轴的起止时间同步为实体的
    availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({
      start: start,
      stop: stop
    })]),
    position: entityPath,
    orientation: new Cesium.VelocityOrientationProperty(entityPath),
    cylinder: {
      HeightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      length: hen,
      topRadius: 0,
      bottomRadius: hen / 2,
      material: Cesium.Color.RED.withAlpha(0.4),
      outline: true,
      numberOfVerticalLines: 0,
      outlineColor: Cesium.Color.RED.withAlpha(0.8)
    },
  });
  //插值器,两个点位之间的模拟插值
  entity.position.setInterpolationOptions({
    interpolationDegree: 5,
    interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
  });


  /**
   * 卫星
   */
   let satellitePath = computePosition(path, 1);
   let satelliteEntity = viewer.entities.add({
    // 将实体availability设置为与模拟时间相同的时间间隔。
    availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({
      start: start,
      stop: stop
    })]),
    //计算实体位置属性
    position: satellitePath,
    //基于位置移动自动计算方向.
    orientation: new Cesium.VelocityOrientationProperty(satellitePath),
    //加载飞机模型
    model: {
      uri: './sources/kml.glb',
      minimumPixelSize: 68,
      scale: 2000.0,
    },
    //路径
     path: {
      resolution: 1,
      material: new Cesium.PolylineGlowMaterialProperty({
        glowPower: 0.1,
        color: Cesium.Color.GREEN
      }),
      width: 5
    }
  });
 //插值器,两个点位之间的模拟插值
  satelliteEntity.position.setInterpolationOptions({
    interpolationDegree: 5,
    interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
  });
5. 开始执行

我们给第四步添加好ifLat, degree, hen三个参数就可以看到一颗卫星运行起来。我们可以把上一步继续封装来实现多个卫星运行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Cesium Demo01

CZML法

当我参考网上案例完成上一步卫星轨道的过程中,就发现了其实Cesium对于动画类的模型,其实推荐使用CZML数据驱动的模式,并且上一步实现的卫星轨道有一个问题,轨道高度固定,而往往真实的卫星轨道可能会随时改变。如果大家想要了解CZML是什么,可以访问Cesium官网或者看一下我对于CZML的简单理解Cesium之CZML。简单来说,CZML将动画运行的轨道,模型,渲染样式等等全部以json数据格式的方式写在了czml文档里面,用数据驱动场景渲染。

1.czml定义

我们按照规范可以自己完整的构建一个CZML文档,但是卫星一般网上有能下载到,然后也有转换工具,可以直接生成CZML。下面是一个示例:

注意:因为czml里面包含大量坐标导致过长,填入了下载地址。

test.czml

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2. 调用
viewer = new Cesium.Viewer('cesiumContainer', {
        shouldAnimate: true,
        geocoder: false, // 隐藏查找位置
        homeButton: false, // 隐藏返回视角到初始位置
        sceneModePicker: false, // 隐藏视角模式的选择
        baseLayerPicker: false, // 隐藏图层选择器
        navigationHelpButton: false, // 隐藏帮助
        timeline: true, // 隐藏时间轴
        fullscreenButton: false, // 隐藏全屏按钮
        animation: true, // 隐藏动画速度控制器
        infoBox: false, // 点击的详情弹窗entity的description可以描述html显示在弹窗中,也可以通过viewer.infoBox.frame来接入访问
    });


    var clock = viewer.clock;
    var cylinderEntity = viewer.entities.add({
        cylinder: {
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            length: 600000,
            topRadius: 0,
            bottomRadius: 600000/2,
            material: Cesium.Color.RED.withAlpha(.4),
            outline: !0,
            numberOfVerticalLines: 0,
            outlineColor: Cesium.Color.RED.withAlpha(.4)
        }
    });



    // 卫星带扫描
    var property;
    var satellite = null;
    viewer.dataSources.add(Cesium.CzmlDataSource.load("xxx/test.czml")).then(function (dataSource) {
				// 添加扫描
        satellite = dataSource.entities.getById("Satellite/GAOFEN 1");

        property = new Cesium.SampledPositionProperty();
        var date = Cesium.JulianDate.toDate(clock.startTime);
        for (var ind = 0; ind < 292; ind++) {
            var time = Cesium.JulianDate.addSeconds(clock.startTime, 300 * ind, new Cesium.JulianDate());
            var position = satellite.position.getValue(time);

            var cartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(position);
            var lat = Cesium.Math.toDegrees(cartographic.latitude),
                lng = Cesium.Math.toDegrees(cartographic.longitude),
                hei = cartographic.height;
            // console.log(position)
            property.addSample(time, Cesium.Cartesian3.fromDegrees(lng, lat, hei));
        }
       cylinderEntity.position = property;
        cylinderEntity.position.setInterpolationOptions({ //设定位置的插值算法
            interpolationDegree: 5,
            interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
        });

    });

代码部分有点难以理解,其实我们viewer.dataSources.add(Cesium.CzmlDataSource.load("xxx/test.czml"))就可以加载卫星轨道以及模拟,但是,因为czml驱动的动画,我们如果想要获取模型entity,那么可能就得通过xxx.then函数链来获取具体内容了。里面的操作逻辑其实就是分段获取每个时刻卫星的状态,然后又通过转换对应赋值给圆锥实体,这样可以实现效果,但是比较麻烦。能不能进一步优化?

3. 优化

既然czml可以定义模型,是否可以同时定义圆锥和卫星模型,然后两个使用同一份动画数据呢?答案是可以。

我们在第一步czml文件中直接添加圆锥模型,省略了其它没变的地方:

[
	{
		...
	},
	{
	 ...,
   "model": {
          "gltf": "../sources/kml.glb",
          "scale": 1,
          "minimumPixelSize": 128
     },
    "cylinder": {
          "length": 650000,
          "topRadius": 0,
          "bottomRadius": 300000,
          "heightReference": "CLAMP_TO_GROUND",
          "outline": true,
          "numberOfVerticalLines": 0,
          "material": [214,88,148, 0.4],
          "outlineColor": [214,88,148, 0.4]

      },
      ...
	}
]

注意:czml定义和代码定义时有一些变量是无法使用的,只能用基本数据类型。

 viewer = new Cesium.Viewer('cesiumContainer', {
        shouldAnimate: true,
        geocoder: false, // 隐藏查找位置
        homeButton: false, // 隐藏返回视角到初始位置
        sceneModePicker: false, // 隐藏视角模式的选择
        baseLayerPicker: false, // 隐藏图层选择器
        navigationHelpButton: false, // 隐藏帮助
        timeline: true, // 隐藏时间轴
        fullscreenButton: false, // 隐藏全屏按钮
        animation: true, // 隐藏动画速度控制器
        infoBox: false, // 点击的详情弹窗entity的description可以描述html显示在弹窗中,也可以通过viewer.infoBox.frame来接入访问
    });

    // 高分一号,带扫描
    var property;
    var satellite = null;
    viewer.dataSources.add(Cesium.CzmlDataSource.load("xxx/gf.czml"))

代码清晰简单多了,将所有的数据定义全部放在了czml文件中。当然我们可以多找几份czml文件,然后添加渲染。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Cesium Demo02

4. 存在的问题

因为卫星轨道不再如方法一一样是固定高度,那么存在了一个问题就是扫描高度没法动态跟着联动,后边我需要再研究研究czml文档规范去优化。

参考资料

cesium 卫星环绕扫描_cesium 卫星扫描-CSDN博客

  • 17
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值