Cesium根据卫星TLE两行数生成CZML,并模拟卫星扫描

卫星轨道.gif

1.生成CZML

根据卫星显示的起始时间,终止时间,tle轨道两行数得出czml文件

import moment from "moment";
import julian from "julian";
import * as satellite from "satellite.js";
/*
根据卫星显示的起始时间,终止时间,tle轨道两行数得出czml文件,时间为js的Date对象,tles为对象数组,对象格式为
{
name:xx,
tle1:xx,
tle2:xx
}
*/
export default function tles2czml(startTime, endTime, tles) {
    
    
    console.log(endTime);
    console.log(startTime);
    // 计算起始时间和终止时间相隔的分钟数
    let minsInDuration = (endTime.getTime() - startTime.getTime()) / 6000;   //mins
    //设置为开始时间
    let initialTime = moment(startTime.toISOString()).toISOString();
    //设置为结束时间
    endTime = moment(endTime.toISOString()).toISOString();
    // 初始化czml数据,创建场景信息
    let tempCZML = [];
    tempCZML.push({
    
    
        "id": "document",
        "name": "CZML Point - Time Dynamic",
        "version": "1.0",
        "clock": {
    
    
            "interval": `${
      
      initialTime}/${
      
      endTime}`,
            "multiplier": 1,
            "range": "LOOP_STOP",
            "step": "SYSTEM_CLOCK"
        }
    },
    )


    // 处理每一个sat
    for (let no = 0; no < tles.length; no++) {
    
    
        if (!tles[no].name) {
    
    
            console.log("请输入第" + no + 1 + "个卫星的名称");
            return
        };
        if (!tles[no].tle1) {
    
    
            console.log("请输入第" + no + 1 + "个卫星的第一个两行数");
            return
        };
        if (!tles[no].tle2) {
    
    
            console.log("请输入第" + no + 1 + "个卫星的第二个两行数");
            return
        };
        let sat_name = tles[no].name;
        // 保存位置信息
        let res = [];
        let satrec
        satrec = satellite.twoline2satrec(tles[no].tle1, tles[no].tle2);
        //satrec.no:以弧度/分钟为单位的平均运动,一天有1440分钟,一弧度是0.159155圈
        // to go from RAD/DAY -> REV/DAY: rad * 1440 * 0.159155
        //to go from REV/PER DAY to MINS/REV -> 1440/RevPerDay
        let totalIntervalsInDay = satrec.no * 1440 * 0.159155; //1440 = min && 0.159155 = 1turn
        // 获得运行一圈的分钟数
        let minsPerInterval = 1440 / totalIntervalsInDay; // mins for 1 revolution around earth
        // intervalTime 取起始时间 格式为2008-09-20T12:25:40.104Z
        let intervalTime = moment(startTime.toISOString()).toISOString()


        let leadIntervalArray = [];
        let trailIntervalArray = [];
        console.log("Setting intervals...");
        // 注意:这里之所以要倒过来求leadInterval和trailInterval是因为如果正着求,很有可能在终止时刻卫星并没有运行完一圈,导致轨道只显示一半
        for (let i = minsInDuration; i >= 0; i -= minsPerInterval) {
    
    
            if (i <= minsPerInterval) {
    
     // intial interval 
                let currentOrbitalInterval = {
    
    
                    "interval": `${
      
      startTime.toISOString()}/${
      
      intervalTime}`,
                    "epoch": `${
      
      startTime.toISOString()}`,
                    "number": [
                        0, minsPerInterval * 60,
                        minsPerInterval * 60, 0
                    ]
                }
                let currTrail = {
    
    
                    "interval": `${
      
      startTime.toISOString()}/${
      
      intervalTime}`,
                    "epoch": `${
      
      startTime.toISOString()}`,
                    "number": [
                        0, 0,
                        minsPerInterval * 60, minsPerInterval * 60
                    ]
                }
                leadIntervalArray.push(currentOrbitalInterval);
                trailIntervalArray.push(currTrail);
            }
            else {
    
      //not initial so make intervals 
                let previousIntervalTime = moment(intervalTime).add(-minsPerInterval, 'm').toISOString();
                let currentOrbitalInterval = {
    
    
                    "interval": `${
      
      previousIntervalTime}/${
      
      intervalTime}`,
                    "epoch": `${
      
      previousIntervalTime}`,
                    "number": [
                        0, minsPerInterval * 60,
                        minsPerInterval * 60, 0
                    ]
                }
                let currTrail = {
    
    
                    "interval": `${
      
      previousIntervalTime}/${
      
      intervalTime}`,
                    "epoch": `${
      
      previousIntervalTime}`,
                    "number": [
                        0, 0,
                        minsPerInterval * 60, minsPerInterval * 60
                    ]
                }
                intervalTime = moment(intervalTime).add(-minsPerInterval, 'm').toISOString();
                leadIntervalArray.push(currentOrbitalInterval);
                trailIntervalArray.push(currTrail);
            }
        }
        // Seconds between current time and epoch time
        let sec = (startTime - julian.toDate(satrec.jdsatepoch)) / 1000;
        console.log(startTime, julian.toDate(satrec.jdsatepoch), sec);
        for (let i = sec; i <= sec + minsInDuration * 60; i++) {
    
     //每60秒计算一个位置信息,最后采用拉格朗日插值法处理数据
            // 根据当前时间距tle两行数历元时刻的分钟数,计算当前卫星位置和速度
            let positionAndVelocity = satellite.sgp4(satrec, i * 0.0166667); // 0.0166667min = 1sec
            // 地惯坐标系
            let positionEci = positionAndVelocity.position;
            positionEci.x = positionEci.x * 1000;
            positionEci.y = positionEci.y * 1000;
            positionEci.z = positionEci.z * 1000;
            // let velocityEci = positionAndVelocity.velocity;
            // velocityEci.x = velocityEci.x * 1000;
            // velocityEci.y = velocityEci.y * 1000;
            // velocityEci.z = velocityEci.z * 1000;
            res.push(i - sec, positionEci.x, positionEci.y, positionEci.z);
        }
        let initialCZMLProps =
        {
    
    
            "id": `${
      
      sat_name}`,
            "name": `${
      
      sat_name}`,
            "availability": `${
      
      initialTime}/${
      
      endTime}`,
            "label": {
    
    
                "fillColor": {
    
    
                    "rgba": [
                        255, 0, 255, 255
                    ]
                },
                "font": "11pt Lucida Console",
                "horizontalOrigin": "LEFT",
                "outlineColor": {
    
    
                    "rgba": [
                        0, 0, 0, 255
                    ]
                },
                "outlineWidth": 2,
                "pixelOffset": {
    
    
                    "cartesian2": [
                        12, 0
                    ]
                },
                "show": true,
                "style": "FILL_AND_OUTLINE",
                "text": `${
      
      sat_name}`,
                "verticalOrigin": "CENTER"
            },
            "path": {
    
    
                "show": [
                    {
    
    
                        "interval": `${
      
      initialTime}/${
      
      endTime}`,
                        "boolean": true
                    }
                ],
                "width": 3,
                "material": {
    
    
                    "solidColor": {
    
    
                        "color": {
    
    
                            "rgba": [
                                // 随机生成轨道颜色
                                Math.floor(255 * Math.random(0, 1)), Math.floor(255 * Math.random(0, 1)), Math.floor(255 * Math.random(0, 1)), 255
                            ]
                        }
                    }
                },
                "resolution": 120,
                // The time ahead of the animation time, in seconds, to show the path.
                "leadTime": leadIntervalArray,
                // The time behind the animation time, in seconds, to show the
                "trailTime": trailIntervalArray
            },
            "model": {
    
    
                "show": true,
                "gltf": "./data/simple_satellite_low_poly_free.glb",
                "minimumPixelSize": 55,
            },
            "position": {
    
    
                // 采用拉格朗日插值法
                "interpolationAlgorithm": "LAGRANGE",
                // 1为线性插值,2为平方插值
                "interpolationDegree": 2,
                // 参考坐标系,地惯坐标系
                "referenceFrame": "INERTIAL",
                "epoch": `${
      
      initialTime}`,
                "cartesian": res
            }
        }
        tempCZML.push(initialCZMLProps);
    }
    return tempCZML;
}

入参(此示例为两个参数)

const tles = [
  {
    name: "QingHe1",
    tle1: "1 25544U 98067A   20199.03008672 -.00000576  00000-0 -22221-5 0  9991",
    tle2: "2 25544  51.6440 200.7619 0001412 122.6206 338.3473 15.49512746236640",
  },
  {
    name: "NAVSTAR 76 (USA 266)",
    tle1: "41328U 16007A   19049.49277110  .00000017  00000-0  00000+0 0  9993",
    tle2: "2 25544  51.6440 200.7619 0001412 122.6206 338.3473 15.49512742 41328  54.8247 195.6929 0027216 214.4209 145.3559  2.00553553 22229",
  },
];
const startTime = new Date("2023-02-14T08:00:00");
const endTime = new Date("2023-02-14T13:10:00");
const czml = tles2czml(startTime, endTime, tles);

2.根据生成的CZML获取卫星的时间和位置,生成Entity实体

import * as Cesium from "cesium";
export default function scanning(viewer,czml){
    
    
    const cylinderEntity = viewer.entities.add({
    
    
    name: "Red cone",
    position: Cesium.Cartesian3.fromDegrees(-105.0, 40.0, 200000.0),
    cylinder: {
    
    
      length: 400000.0,
      topRadius: 0.0,
      bottomRadius: 200000.0,
      material: Cesium.Color.RED.withAlpha(0.5),
    },
  });
  var property;
  viewer.dataSources
    .add(Cesium.CzmlDataSource.load(czml))
    .then(function (dataSource) {
    
    
    var satellite = dataSource.entities.getById("QingHe1");
      property = new Cesium.SampledPositionProperty();
      for (var ind = 0; ind < 292; ind++) {
    
    
        var time = Cesium.JulianDate.addSeconds(
          viewer.clock.currentTime,
          300 * ind,
          new Cesium.JulianDate()
        );
        var position = satellite.position.getValue(time);
        console.log(position);
        if (position) {
    
    
          var cartographic =
            Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
          var lat = Cesium.Math.toDegrees(cartographic.latitude),
            lng = Cesium.Math.toDegrees(cartographic.longitude),
            hei = cartographic.height / 1.9;
          property.addSample(
            time,
            Cesium.Cartesian3.fromDegrees(lng, lat, hei)
          );
        }
      }


      cylinderEntity.position = property;
      cylinderEntity.position.setInterpolationOptions({
    
    
        //设定位置的插值算法
        interpolationDegree: 5,
        interpolationAlgorithm: Cesium.LagrangePolynomialApproximation,
      });


    //   viewer.clock.onTick.addEventListener(function (clock) {
    
    
    //     if (property) {
    
    
    //       var time = clock.currentTime;
    //       var val = property.getValue(clock.currentTime);
    //       // console.log(val);
    //     }
    //   });
    });
}

3.无两行数情况下输入开始时间和结束时间生成模拟轨道(非真实卫星轨迹)

import * as Cesium from "cesium";
var arrStates = [];
var start, stop, viewer;
export default function simulation(v, startTime, endTime) {
    
    
    viewer = v
    // start = new Cesium.JulianDate.fromDate(new Date()); // 获取当前时间 这不是国内的时间
    start = new Cesium.JulianDate.fromDate(startTime); // 获取当前时间 这不是国内的时间
    stop = new Cesium.JulianDate.fromDate(endTime); // 获取当前时间 这不是国内的时间
    console.log(start);
    const sec = stop.secondsOfDay - start.secondsOfDay
    // start = Cesium.JulianDate.addHours(start, 8, new Cesium.JulianDate()); // 添加八小时,得到我们东八区的北京时间
    // stop = Cesium.JulianDate.addHours(stop, 8, new Cesium.JulianDate()); // 设置一个结束时间,意思是360秒之后时间结束


    viewer.clock.startTime = start.clone(); // 给cesium时间轴设置开始的时间,也就是上边的东八区时间
    viewer.clock.stopTime = stop.clone(); // 设置cesium时间轴设置结束的时间
    viewer.clock.currentTime = start.clone(); // 设置cesium时间轴设置当前的时间
    viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; // 时间结束了,再继续重复来一遍
    //时间变化来控制速度 // 时间速率,数字越大时间过的越快
    viewer.clock.multiplier = 2;
    //给时间线设置边界
    viewer.timeline.zoomTo(start, stop);


    arrStates = [];
    getRandState(arrStates, 1, sec);
    startFunc();
}
function mySatePosition() {
    
    
    this.lon = 0;
    this.lat = 0;
    this.hei = 700000; //卫星高度
    this.phei = 700000 / 2; //轨道高度
    this.time = 0;
}
function computeCirclularFlight(source, panduan) {
    
    
    var property = new Cesium.SampledPositionProperty();
    if (panduan == 1) {
    
    
        //卫星位置
        for (var i = 0; i < source.length; i++) {
    
    
            var time = Cesium.JulianDate.addSeconds(
                start,
                source[i].time,
                new Cesium.JulianDate()
            );
            var position = Cesium.Cartesian3.fromDegrees(
                source[i].lon,
                source[i].lat,
                source[i].hei
            );
            // 添加位置,和时间对应
            property.addSample(time, position);
        }
    } else if (panduan == 2) {
    
    
        //轨道位置
        for (var i = 0; i < source.length; i++) {
    
    
            var time = Cesium.JulianDate.addSeconds(
                start,
                source[i].time,
                new Cesium.JulianDate()
            );
            var position = Cesium.Cartesian3.fromDegrees(
                source[i].lon,
                source[i].lat,
                source[i].phei
            );
            // 添加位置,和时间对应
            property.addSample(time, position);
        }
    }
    return property;
}


function getRandState(brr, count, sec) {
    
    
    for (var m = 0; m < count; m++) {
    
    
        var arr = [];
        var t1 = Math.floor(Math.random() * sec);
        var t2 = Math.floor(Math.random() * sec);
        for (var i = t1; i <= sec + t1; i += 30) {
    
    
            var aaa = new mySatePosition();
            aaa.lon = t2;
            aaa.lat = i;
            aaa.time = i - t1;
            arr.push(aaa);
        }
        brr.push(arr);
    }
    console.log(brr);
}


function getStatePath(aaa) {
    
    
    console.log(aaa);
    console.log(viewer);


    var entity_ty1p = computeCirclularFlight(aaa, 2);
    var entity_ty1 = viewer.entities.add({
    
    
        availability: new Cesium.TimeIntervalCollection([
            new Cesium.TimeInterval({
    
    
                start: start,
                stop: stop,
            }),
        ]),
        position: entity_ty1p, //轨道高度
        orientation: new Cesium.VelocityOrientationProperty(entity_ty1p),
        cylinder: {
    
    
            HeightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            length: 700000,
            topRadius: 0,
            bottomRadius: 900000 / 2,
            // material: Cesium.Color.RED.withAlpha(.4),
            // outline: !0,
            numberOfVerticalLines: 0,
            // outlineColor: Cesium.Color.RED.withAlpha(.8),
            material: Cesium.Color.fromBytes(35, 170, 242, 80),
        },
    });


    entity_ty1.position.setInterpolationOptions({
    
    
        interpolationDegree: 5,
        interpolationAlgorithm: Cesium.LagrangePolynomialApproximation,
    });


    var entity1p = computeCirclularFlight(aaa, 1);
    //创建实体
    var entity1 = viewer.entities.add({
    
    
        // 将实体availability设置为与模拟时间相同的时间间隔。
        availability: new Cesium.TimeIntervalCollection([
            new Cesium.TimeInterval({
    
    
                start: start,
                stop: stop,
            }),
        ]),
        position: entity1p, //计算实体位置属性
        //基于位置移动自动计算方向.
        orientation: new Cesium.VelocityOrientationProperty(entity1p),
        //加载飞机模型
        model: {
    
    
            uri: "./data/simple_satellite_low_poly_free.glb",
            scale: 30000,
        },
        //路径
        path: {
    
    
            resolution: 1,
            material: new Cesium.PolylineGlowMaterialProperty({
    
    
                glowPower: 0.1,
                color: Cesium.Color.PINK,
            }),
            width: 5,
        },
    });


    //差值器
    entity1.position.setInterpolationOptions({
    
    
        interpolationDegree: 5,
        interpolationAlgorithm: Cesium.LagrangePolynomialApproximation,
    });
}


function startFunc() {
    
    
    for (var i = 0; i < arrStates.length; i++) {
    
    
        getStatePath(arrStates[i]);
    }
}

入参

  /* 模拟卫星,非真实卫星轨迹 */
const startTime = new Date("2023-02-14T13:00:00");
const endTime = new Date("2023-02-14T14:20:00");
simulation(viewer, startTime, endTime);

4.仓库地址

https://github.com/FF926/Cesium/tree/main/TLE2czml

猜你喜欢

转载自blog.csdn.net/qq_38241330/article/details/129026296
今日推荐