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 = isateP.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博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/434283.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[UI5 常用控件] 02.Title,Link,Label

文章目录 前言1. Title1.1 结合Panel1.2 结合Table1.3 Title里嵌套Link 2. Link3. Label3.1 普通用法3.2 在Form里使用 前言 本章节记录常用控件Title,Link,Label。 其路径分别是&#xff1a; sap.m.Titlesap.m.Linksap.m.Label 1. Title Title可以结合其他控件一起使用 1.…

List使用addAll()方法报错

当使用Arrays.asList方式创建出来的list&#xff0c;在使用addAll方法的时候报错如下&#xff1a; Exception in thread "main" java.lang.UnsupportedOperationException 这个问题记录下&#xff0c;以防以后忘记。 下面是代码 List<String> objects new A…

MATLAB|【完全复现】含可再生能源和储能的区域微电网的最优运行(考虑鲁棒性和不确定性)【多阶段鲁棒调度模型】

目录 主要内容 模型研究 一、区域微网模型 二、模型优化流程​ 结果一览 下载链接 主要内容 该程序实现了一种基于可再生能源和储能的区域微电网的多阶段优化调度方法&#xff0c;该方法可以同时保证优化调度方案的鲁棒性和非预测性。模型考虑两类不确定性&…

CentOS网络配置进阶:深入研究network服务和NetworkManager

前言 如果你正在使用CentOS系统,并且想要深入了解网络管理和配置,那么本文肯定适合你!在这篇文章中,作者深入探讨了CentOS中的两种网络管理方式:network服务和NetworkManager。通过详实的讲解和实用的示例,你将会学习到如何使用这两种工具来管理网络接口、配置IP地址、网…

防御保护---安全策略

文章目录 目录 一.安全策略概述 概述&#xff1a; 安全策略的作用&#xff1a; 安全策略与传统防火墙的区别 二.案例分析 练习 一.安全策略概述 概述&#xff1a; 防火墙安全策略的作用在于加强网络系统的安全性&#xff0c;保护网络免受恶意攻击、非法访问和数据泄露的威胁。…

acwing周赛140 b题

思路&#xff1a;我们按照从小到大的顺序将数组逆转好&#xff0c;然后枚举数组首项&#xff0c;分别让其1&#xff0c;-1&#xff0c;0&#xff0c;然后求出公差&#xff0c;从前往后遍历即可。 代码&#xff1a; int ans1(){//不动int cha (a[n] - a[1] 1) / (n - 1);int…

未来时尚:数字化管理引领服装企业商品计划的创新浪潮

时尚产业正经历着一场数字化的浪潮&#xff0c;数字化管理正成为引领服装企业商品计划的不可忽视的创新力量。这一变革不仅影响了企业内部的运营方式&#xff0c;更深刻地塑造了未来时尚的面貌。本文将深入探讨数字化管理如何领导着服装企业商品计划进入创新浪潮&#xff0c;重…

Zabbix简单介绍

Zabbix简单介绍 Zabbix简介 Zabbix是一个企业级的、开源的、分布式监控套件&#xff0c;用于监控IT基础设施的可用性和性能&#xff1b;Zabbix可以监控网络和服务的状况&#xff1b;Zabbix利用灵活的告警机制&#xff0c;允许用户对事件发送基于邮件、短信、微信和钉钉等告警…

c语言-柔性数组

文章目录 前言一、柔性数组的介绍1.1 柔性数组的定义 二、柔性数组的使用2.1 使用说明2.2 结构体中的成员只包含一个柔性数组成员2.3 结构体中的成员包含其他成员和一个柔性数组成员 三、模拟柔性数组总结 前言 本篇文章介绍c语言中的柔性数组。 一、柔性数组的介绍 1.1 柔性…

JavaSec基础命令执行

记录https://github.com/javaweb-sec/javaweb-sec的学习 CommandExecute Runtime#exec ProcessBuilder#start 以上两个最终都要调到ProcessImpl 而ProcessImpl会调用native的forkAndExec 实际最终都是调到Java_java_lang_ProcessImpl_forkAndExec 而我们只需要直接调用最…

单调栈第二天(还没写完)

503.下一个更大元素II 力扣题目链接(opens new window) 给定一个循环数组&#xff08;最后一个元素的下一个元素是数组的第一个元素&#xff09;&#xff0c;输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序&#xff0c;这个数字之后的第一个比它更…

一、对人工智能大模型了解与认知

黑8说 月黑风高&#xff0c;乌云密布&#xff0c;树木低垂&#xff0c;黯淡沉闷。这黎明前的风暴&#xff0c;预示着新时代的变革即将到来。 在一个8线小城市的办公室中 黑8对主任说&#xff1a; 世界上有男人、女人、人妖&#xff0c;米国有1/3男&#xff0c;2/3女…&#xff…