Commit f1af583a by licheng

feat: 新增从轨道数据文件读取轨道的方法

parent b893c104
......@@ -66,7 +66,6 @@
"pinia-plugin-persistedstate": "^3.2.1",
"qrcode": "^1.5.3",
"qs": "^6.12.0",
"satellite.js": "^6.0.1",
"sortablejs": "^1.15.3",
"steady-xml": "^0.1.0",
"url": "^0.11.3",
......
......@@ -131,9 +131,6 @@ importers:
qs:
specifier: ^6.12.0
version: 6.13.1
satellite.js:
specifier: ^6.0.1
version: 6.0.1
sortablejs:
specifier: ^1.15.3
version: 1.15.6
......@@ -4677,9 +4674,6 @@ packages:
engines: {node: '>=14.0.0'}
hasBin: true
satellite.js@6.0.1:
resolution: {integrity: sha512-T0qpKYSlNIH9L0yY1SRF2J6XfV9TToZuDNBXSeTW9K6fN5kwf4uidzk3+q6Rg4KVHibcLaire910C47yai0W9A==}
sax@1.4.1:
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
......@@ -10207,8 +10201,6 @@ snapshots:
optionalDependencies:
'@parcel/watcher': 2.5.0
satellite.js@6.0.1: {}
sax@1.4.1: {}
saxen@8.1.2: {}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -52,7 +52,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
},
{
path: '/chart',
component: () => import('@/views/Home/Index2.vue'),
component: () => import('@/views/Home/lineChart2.vue'),
name: 'chart',
meta: {
hidden: true,
......
......@@ -11,8 +11,7 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import * as Cesium from 'cesium'
import * as satellite from 'satellite.js'
import { computeRandomOrbit } from './satellite-data'
import { computeRandomOrbit, computeOrbitFromXYZ } from './satellite-data'
// ---------------- Cesium Token ----------------
Cesium.Ion.defaultAccessToken =
......@@ -25,7 +24,7 @@ const cesiumContainer = ref<HTMLDivElement | null>(null)
let viewer: Cesium.Viewer
const infoOffset = 2000000 // 信息框相对卫星的高度偏移(米)
const imageUrl = '/src/assets/imgs/satellite.png' // 卫星图标路径
const satelliteNum = 13 // 添加卫星数量
const satelliteNum = 1 // 添加卫星数量
const activeSatellite = ref(1)
// ---------- 所有卫星实体集合(用于全局点击事件) ----------
......@@ -38,91 +37,14 @@ const satellites: {
}[] = []
/**
* 根据 TLE(Two-Line Element Set)计算卫星轨道
* @param tle1 TLE 第一行数据(包含卫星编号、轨道参数)
* @param tle2 TLE 第二行数据(包含倾角、升交点赤经、近地点等)
* @param numPoints 采样点数量(轨道上要取多少个点,越多轨道越平滑,默认 360)
* @param timeStep 每两个采样点之间的时间间隔(秒),默认 60 秒
* @returns {
* positionProperty: SampledPositionProperty(随时间变化的卫星位置)
* orbitPositions: Cartesian3[](整个轨道的固定点集合,用于绘制完整轨道线)
* startTime: JulianDate(轨道计算起始时间)
* stopTime: JulianDate(轨道计算结束时间)
* }
*/
function computeOrbitFromTLE(
tle1: string,
tle2: string,
numPoints = 720,
timeStep = 6
): {
positionProperty: Cesium.SampledPositionProperty
orbitPositions: Cesium.Cartesian3[]
startTime: Cesium.JulianDate
stopTime: Cesium.JulianDate
} {
// 将 TLE 转换成可用于计算的卫星对象
const satrec = satellite.twoline2satrec(tle1, tle2)
// 起始时间:以当前时间为起点
const startTime = Cesium.JulianDate.now()
// 结束时间:根据采样点数量和时间间隔计算
const stopTime = Cesium.JulianDate.addSeconds(
startTime,
numPoints * timeStep,
new Cesium.JulianDate()
)
// Cesium 的 SampledPositionProperty 用于保存随时间变化的位置
const positionProperty = new Cesium.SampledPositionProperty()
// 存放整条轨道的固定点集合,用于画完整轨道线
const orbitPositions: Cesium.Cartesian3[] = []
for (let i = 0; i < numPoints; i++) {
// 当前采样点的时间
const currentTime = Cesium.JulianDate.addSeconds(
startTime,
i * timeStep,
new Cesium.JulianDate()
)
// 转换为 JavaScript Date 对象,satellite.js 接口需要 Date 类型
const date = Cesium.JulianDate.toDate(currentTime)
// 根据 TLE 推算卫星在当前时间的 ECI 坐标(地心惯性坐标)
const eciPosVel = satellite.propagate(satrec, date)
if (eciPosVel?.position) {
// 地球自转角度(Greenwich Mean Sidereal Time)
const gmst = satellite.gstime(date)
// 将 ECI 转换为大地坐标(经纬度+高度)
const geo = satellite.eciToGeodetic(eciPosVel.position, gmst)
const lon = Cesium.Math.toDegrees(geo.longitude) // 经度(°)
const lat = Cesium.Math.toDegrees(geo.latitude) // 纬度(°)
const height = geo.height * 1000 // 高度(m),satellite.js 返回的是 km
// 转换成 Cesium 世界坐标(笛卡尔坐标系)
const cartesian = Cesium.Cartesian3.fromDegrees(lon, lat, height)
// 加入时间序列属性
positionProperty.addSample(currentTime, cartesian)
// 加入轨道点集合
orbitPositions.push(cartesian)
}
}
return { positionProperty, orbitPositions, startTime, stopTime }
}
/**
* 添加一个卫星实体(包含图标、轨道、信息框)
* @param name 卫星名称
* @param tle1 TLE 第一行
* @param tle2 TLE 第二行
* @param filePath 文件路径
*/
function addSatelliteEntity(name: string, _tle1: string = '', _tle2: string = '') {
async function addSatelliteEntityFromXYZ(name: string, filePath: string) {
// 计算轨道数据
const { positionProperty, orbitPositions } = computeRandomOrbit()
const { positionProperty, orbitPositions, startTime, stopTime } = await computeOrbitFromXYZ(filePath) // 从文件读取轨道
// const { positionProperty, orbitPositions, startTime, stopTime } = await computeRandomOrbit() // 随机生成轨道
// ---------- 卫星本体(图标) ----------
const satelliteEntity = viewer.entities.add({
......@@ -256,8 +178,11 @@ onMounted(() => {
viewer.clock.shouldAnimate = true
// ---------- 添加卫星 ----------
for (let i = 0;i < satelliteNum; i++) {
addSatelliteEntity(`satellite${i + 1}`)
// for (let i = 0;i < satelliteNum; i++) { // 模拟轨道卫星
// addSatelliteEntityFromXYZ(`satellite${i + 1}`, '')
// }
for (let i = 0;i < satelliteNum; i++) { // 真实轨道卫星
addSatelliteEntityFromXYZ(`satellite${i + 1}`, '/xyz.txt')
}
// ---------- 全局点击事件 ----------
......
import * as Cesium from 'cesium'
// import * as satellite from 'satellite.js'
/**
* 从 WGS84 XYZ 文件中读取卫星轨道
* 文件格式示例:
* 2025-08-01T09:00:00.000Z -1652779.741790, 42113447.389216, 18249.76
* 2025-08-01T09:00:01.000Z -1652782.322471, 42113448.046412, 18250.26
* returns {
* positionProperty: Cesium.SampledPositionProperty, // 轨道位置属性
* orbitPositions: Cesium.Cartesian3[], // 轨道点数组
* startTime: Cesium.JulianDate, // 轨道开始时间
* stopTime: Cesium.JulianDate // 轨道结束时间
* }
*/
export async function computeOrbitFromXYZ(filePath: string): Promise<{
positionProperty: Cesium.SampledPositionProperty
orbitPositions: Cesium.Cartesian3[]
startTime: Cesium.JulianDate
stopTime: Cesium.JulianDate
}> {
// 读取文件内容
const response = await fetch(filePath)
const text = await response.text()
const lines = text.trim().split('\n')
const positionProperty = new Cesium.SampledPositionProperty()
const orbitPositions: Cesium.Cartesian3[] = []
let startTime: Cesium.JulianDate | null = null
let stopTime: Cesium.JulianDate | null = null
for (const line of lines) {
if (!line.trim()) continue // 跳过空行
// 找到第一个空格,前面是时间,后面是坐标
const firstSpaceIndex = line.indexOf(' ')
if (firstSpaceIndex === -1) continue
const timeStr = line.substring(0, firstSpaceIndex).trim()
const coordsStr = line.substring(firstSpaceIndex + 1).trim()
console.log(coordsStr)
// 分割三个坐标
const coords = coordsStr.split(', ').map((v) => parseFloat(v.trim()))
if (coords.length !== 3 || coords.some(isNaN)) continue
const [x, y, z] = coords
// 时间转 JulianDate
const julian = Cesium.JulianDate.fromIso8601(timeStr)
// Cesium Cartesian3,直接用 ECEF 坐标
const cartesian = new Cesium.Cartesian3(x, y, z)
// 加入轨迹
positionProperty.addSample(julian, cartesian)
orbitPositions.push(cartesian)
if (!startTime) startTime = julian
stopTime = julian
}
if (!startTime || !stopTime) {
throw new Error('XYZ 文件为空或格式错误')
}
return { positionProperty, orbitPositions, startTime, stopTime }
}
/**
* 随机生成卫星轨道数据(不依赖 TLE)
......@@ -7,8 +73,8 @@ import * as Cesium from 'cesium'
* @param timeStep 每两个采样点之间的时间间隔(秒)
*/
export function computeRandomOrbit(
numPoints = 720,
timeStep = 6
numPoints = 86400, // 与从xyz.txt读取的点数保持一致
timeStep = 1
): {
positionProperty: Cesium.SampledPositionProperty
orbitPositions: Cesium.Cartesian3[]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment