本文主要是介绍cesium轨道双行数(tle),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
在项目中需要用到卫星绕地球实时观测,查找了很多czml的资料,发现基于cmzl再扩展一些其他的交互(比如实时变换全向光度)非常费劲,于是退而求其次的使用实体(Entity) 来实现,数据量不是特别大的情况下效果还是比较ok的,下面我们来一起实现这个功能吧,先看看下面这张实现的效果图
开始编码之前请确保cesium的版本不低于1.95,本案例就是基于cesium1.95版本实现
1:引入如下库
Cesium195/Widgets/widgets.css,
Cesium195/Cesium.js
satellite.min.js 这个js可以通过npm安装得来
2: 先封装一个卫星类(SatelliteEntity.js),代码如下
class SatelliteEntity {constructor(tle = "", options = {}) {let name = tle[0];let tleLine1 = tle[1];let tleLine2 = tle[2];let circle = tleLine2.slice(52, 64);this.name = name.trim();this.tleLine1 = tleLine1.trim();this.tleLine2 = tleLine2.trim();this.satrec = satellite.twoline2satrec(this.tleLine1, this.tleLine2);this.totalSeconds = 86400;// 24小时this.stepSeconds = 100;this.leadTime = parseInt(24 * 3600 / circle);this.trailTime = 0;}// 获取地心惯性坐标系坐标getPositionEci(time) {return satellite.propagate(this.satrec, time).position;}// 创建PositionProperty_getPositionProperty() {const start = Cesium.JulianDate.fromIso8601(new Date().toISOString());const positionProperty = new Cesium.SampledPositionProperty(Cesium.ReferenceFrame.INERTIAL);let now = Date.now();for (let i = 0; i < this.totalSeconds / this.stepSeconds; i++) {let sateTime = new Date(now + i * this.stepSeconds * 1000);let sateCoord = this.getPositionEci(sateTime);if (!sateCoord) continue;const cesiumTime = Cesium.JulianDate.addSeconds(start, i * this.stepSeconds, new Cesium.JulianDate());const cesiumPosition = { x: sateCoord.x * 1000, y: sateCoord.y * 1000, z: sateCoord.z * 1000 };positionProperty.addSample(cesiumTime, cesiumPosition);}return positionProperty;}// cartesian2转经纬度cartesian2lnglat(viewer,cartesian3){var ellipsoid=viewer.scene.globe.ellipsoid;var cartographic=ellipsoid.cartesianToCartographic(cartesian3);var lat=Cesium.Math.toDegrees(cartographic.latitude);var lng=Cesium.Math.toDegrees(cartographic.longitude);var alt=cartographic.height;return { lng, lat, alt }}// 创建卫星实例createSatelliteEntity(viewer,model) {const start = Cesium.JulianDate.fromIso8601(new Date().toISOString());const stop = Cesium.JulianDate.addSeconds(start, this.totalSeconds, new Cesium.JulianDate());let property = this._getPositionProperty();let satelliteEntity = viewer.entities.add({name: this.name,description: this.name,availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({ start: start, stop: stop })]),position: property,point: {pixelSize: 8,color: Cesium.Color.fromRandom({ alpha: 1.0 }),// scaleByDistance: new Cesium.NearFarScalar(1.5e3, 1, 8.0e8, 0.5),},model:model,path: new Cesium.PathGraphics({width: 1,show: true,leadTime: this.leadTime,trailTime: this.trailTime,material: Cesium.Color.fromRandom({ alpha: 1.0 }),}),label: {text: this.name,font: '12px sans-serif',showBackground: true,backgroundColor: new Cesium.Color(0.165, 0.165, 0.165, 0.5),backgroundPadding: new Cesium.Cartesian2(4, 4),outlineWidth: 1,verticalOrigin: Cesium.VerticalOrigin.TOP,horizontalOrigin: Cesium.VerticalOrigin.LEFT,pixelOffset: new Cesium.Cartesian2(0, 5),fillColor: Cesium.Color.WHITE,distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 5000000),}});satelliteEntity.cylinder = {show:true,length: new Cesium.CallbackProperty(() => {let cartesian = satelliteEntity.position.getValue(viewer.clock.currentTime)if(cartesian){let pos = this.cartesian2lnglat(viewer,cartesian)return Cesium.Cartesian3.distance(Cesium.Cartesian3.fromDegrees(pos.lng, pos.lat, pos.alt), Cesium.Cartesian3.fromDegrees(pos.lng, pos.lat, 0))}}, false),topRadius: 0.0,bottomRadius: 400000.0,heightReference:Cesium.HeightReference.CLAMP_TO_GROUND,material: Cesium.Color.fromRandom({ alpha: 0.6 }),outline:false,// outlineColor:color.withAlpha(0.3),// outlineWidth:1,slices:128,// distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0,50000000),}return satelliteEntity;}
}export default SatelliteEntity
3:找到自己的需要的TLE(双行)轨道数据,参考网站:https://celestrak.org/NORAD/elements/,可以在页面通过axios发送请求获取,获取方式如下
//解析
function parseTle(data) {if (data.length === 0) return;let result = data.split("\r\n");let tles = [], i = 0, tem = [];result.forEach(item => {i++;tem.push(item)if (i === 3) {tles.push(tem.join("\r\n"));tem = [];i = 0;}});return tles;
}axios.get('https://celestrak.org/NORAD/elements/gp.php?GROUP=last-30-days&FORMAT=tle').then((response)=> {let tleResult = parseTle(response.data);
})
此处为了演示我就写死了3条tle数据
let tleData = [['aaa','1 11962U 80073A 80253.44930232 .00000016 00000-0 00000+0 0 12','2 11962 81.2400 177.7389 0060506 293.5174 65.9686 14.13684653 07'],['bbb','1 11962U 80073A 80253.52032942 .00000015 00000-0 00000+0 0 22','2 11962 81.2574 177.6557 0031206 251.7983 107.9348 14.06430944 11'],['ccc','1 11962U 80073A 80254.01808565 .00000844 00000-0 48489-3 0 37 22','2 11962 81.2459 177.2133 0031790 270.5020 89.2378 14.07089367 80'],['ddd','1 11962U 80073A 80258.42677503 .00000503 00000-0 28139-3 0 90','2 11962 81.2445 172.9469 0031840 257.9790 101.7807 14.07098597 709']]
数组中的第1个参数代表tle名称
数组中的第2个参数代表第一行,
数组中的第3个参数代表第二行,
两行根数的定义与解析请参考
航天器轨道根数/两行根数的定义/TLE | 李小波
数据准备好了,然后开始码代码咯!
4.先初始化cesium视图
// 引入上面封装的SatelliteEntity类
import SatelliteEntity from './tle/SatelliteEntity.js'// 格式化时间轴Cesium.Timeline.prototype.makeLabel = function (time) {let minutes = 0 - new Date().getTimezoneOffset();let dataZone8 = Cesium.JulianDate.addMinutes(time, minutes, new Cesium.JulianDate());return Cesium.JulianDate.toIso8601(dataZone8).slice(0, 19);}// 加载本地瓦片,没有瓦片资源的请注释掉let buildBaseImageryProvider = new Cesium.UrlTemplateImageryProvider({url: "./map/tile/{z}/{x}/{y}.png",maximumLevel: 3 // 最大级别})const viewer = new Cesium.Viewer("map", {infoBox: false,selectionIndicator: false,navigation: false,animation: true,shouldAnimate: true,timeline: true,baseLayerPicker: false,geocoder: false,homeButton: false,sceneModePicker: false,navigationHelpButton: false,imageryProvider:buildBaseImageryProvider});//取消左键双击事件viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); //去除版权信息viewer._cesiumWidget._creditContainer.style.display = "none";viewer.scene.fxaa = true;viewer.scene.postProcessStages.fxaa.enabled = true;// 地面变灰const currentLayer = viewer.imageryLayers.get(0)currentLayer.brightness = 0.7// 昼夜viewer.scene.globe.enableLighting = true;viewer.shadows = trueviewer.clock.clockRange = Cesium.ClockRange.CLAMPED
5:循环添加双根数
let tleData = [['aaa','1 11962U 80073A 80253.44930232 .00000016 00000-0 00000+0 0 12','2 11962 81.2400 177.7389 0060506 293.5174 65.9686 14.13684653 07'],['bbb','1 11962U 80073A 80253.52032942 .00000015 00000-0 00000+0 0 22','2 11962 81.2574 177.6557 0031206 251.7983 107.9348 14.06430944 11'],['ccc','1 11962U 80073A 80254.01808565 .00000844 00000-0 48489-3 0 37 22','2 11962 81.2459 177.2133 0031790 270.5020 89.2378 14.07089367 80'],['ddd','1 11962U 80073A 80258.42677503 .00000503 00000-0 28139-3 0 90','2 11962 81.2445 172.9469 0031840 257.9790 101.7807 14.07098597 709']]let modelEntity = viewer.entities.add({model: {show: true,uri: "../satellite/scene.gltf",minimumPixelSize: 105,// 超过5000000米就显示卫星模型distanceDisplayCondition: new Cesium.DistanceDisplayCondition(5000000)}})let model = Cesium.clone(modelEntity.model)tleData.forEach(tle => {let satellite = new SatelliteEntity(tle);satellite.createSatelliteEntity(viewer,model);});
这样就可以成功的添加tle轨道到视图中了
完整代码如下
<html lang="en">
<head><meta charset="UTF-8"/><title>卫星TLE两行数生成轨道跟实体</title><link rel="stylesheet" href="Build/Cesium195/Widgets/widgets.css"><style>*{padding: 0;margin: 0;list-style: none;}.actions{position: absolute;left: 10px;top:20px;z-index: 9;display: flex;}.actions li{padding: 10px;background-color: #00a1ff;color:#fff;cursor: pointer;transition: all;margin-right: 10px;}.actions li:hover{background-color: #0089ff;}</style><script src="Build/Cesium195/Cesium.js"></script><script src="./tle/satellite.min.js"></script></head>
<body ><div id="map" class="fullSize"></div><script type="module">import SatelliteEntity from './tle/SatelliteEntity.js'// 格式化时间轴Cesium.Timeline.prototype.makeLabel = function (time) {let minutes = 0 - new Date().getTimezoneOffset();let dataZone8 = Cesium.JulianDate.addMinutes(time, minutes, new Cesium.JulianDate());return Cesium.JulianDate.toIso8601(dataZone8).slice(0, 19);}let buildBaseImageryProvider = new Cesium.UrlTemplateImageryProvider({url: "./map/tile/{z}/{x}/{y}.png",maximumLevel: 3 // 最大级别})const viewer = new Cesium.Viewer("map", {infoBox: false,selectionIndicator: false,navigation: false,animation: true,shouldAnimate: true,timeline: true,baseLayerPicker: false,geocoder: false,homeButton: false,sceneModePicker: false,navigationHelpButton: false,imageryProvider:buildBaseImageryProvider});// viewer.imageryLayers.addImageryProvider(// new Cesium.ArcGisMapServerImageryProvider({// url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"// })// )//取消左键双击事件viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); //去除版权信息viewer._cesiumWidget._creditContainer.style.display = "none";viewer.scene.fxaa = true;viewer.scene.postProcessStages.fxaa.enabled = true;// 地面变灰const currentLayer = viewer.imageryLayers.get(0)currentLayer.brightness = 0.7// 昼夜viewer.scene.globe.enableLighting = true;viewer.shadows = trueviewer.clock.clockRange = Cesium.ClockRange.CLAMPED let tleData = [['aaa','1 11962U 80073A 80253.44930232 .00000016 00000-0 00000+0 0 12','2 11962 81.2400 177.7389 0060506 293.5174 65.9686 14.13684653 07'],['bbb','1 11962U 80073A 80253.52032942 .00000015 00000-0 00000+0 0 22','2 11962 81.2574 177.6557 0031206 251.7983 107.9348 14.06430944 11'],['ccc','1 11962U 80073A 80254.01808565 .00000844 00000-0 48489-3 0 37 22','2 11962 81.2459 177.2133 0031790 270.5020 89.2378 14.07089367 80'],['ddd','1 11962U 80073A 80258.42677503 .00000503 00000-0 28139-3 0 90','2 11962 81.2445 172.9469 0031840 257.9790 101.7807 14.07098597 709']]let modelEntity = viewer.entities.add({model: {show: true,uri: "../satellite/scene.gltf",minimumPixelSize: 105,// 超过5000000米就显示卫星模型distanceDisplayCondition: new Cesium.DistanceDisplayCondition(5000000)}})let model = Cesium.clone(modelEntity.model)tleData.forEach(tle => {let satellite = new SatelliteEntity(tle);satellite.createSatelliteEntity(viewer,model);});</script>
</body>
</html>
这只是一个基本版本,还可以在此基础上添加一些其他的交互功能,比较灵活,有兴趣的朋友可以将扫描的圆锥用传感器来代替,实现的效果更加真实!!!
这篇关于cesium轨道双行数(tle)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!