import * as Cesium from 'cesium'; import { eciToEcf, gstime, propagate, type SatRec, twoline2satrec } from 'satellite.js'; import type { I卫星 } from '../managers/HCesiumManager.types'; // 保持类型定义位置 const 默认轨道时长秒 = 2 * 60 * 60; // 2小时 const 默认时间步长秒 = 30; export interface OrbitCalculationResult { orbitPositions: Cesium.Cartesian3[]; // 用于绘制完整轨道线 sampledPositionProperty: Cesium.SampledPositionProperty; } export interface OrbitSample { position: Cesium.Cartesian3; time: Cesium.JulianDate; } export class SatelliteCalculator { /** * 解析 TLE 字符串获取卫星记录对象。 * @param tle - 包含名称和两行数据的 TLE 字符串。 * @param satelliteId - 用于错误日志的卫星 ID。 * @returns 解析成功返回 SatRec 对象,否则返回 null。 */ parseTle(tle: string, satelliteId: string): null | SatRec { const tleLines = tle.trim().split('\n') as [string, string, string]; if (tleLines.length < 3) { console.error(`无效的 TLE 格式 (ID: ${satelliteId}): TLE 字符串至少需要三行`); return null; } const tle1 = tleLines[1].trim(); const tle2 = tleLines[2].trim(); try { return twoline2satrec(tle1, tle2); } catch (error) { console.error(`解析 TLE 失败 (ID: ${satelliteId}):`, error); return null; } } /** * 计算卫星在给定时间段内的轨道位置。 * @param satrec - 卫星记录对象。 * @param startTime - 计算轨道的开始时间。 * @param options - 包含轨道时长、步长等选项。 * @param satelliteId - 用于日志记录的卫星 ID。 * @returns 包含 SampledPositionProperty 和轨道点数组的对象,如果计算失败则返回 null。 */ calculateOrbit( satrec: SatRec, startTime: Cesium.JulianDate, options: Pick, satelliteId: string, ): null | OrbitCalculationResult { const { orbitDurationSeconds = 默认轨道时长秒, timeStepSeconds = 默认时间步长秒, showOrbit } = options; const sampledPositionProperty = new Cesium.SampledPositionProperty(); const orbitPositions: Cesium.Cartesian3[] = []; let hasSamples = false; // 标记是否成功添加了至少一个样本点 for (let i = 0; i <= orbitDurationSeconds; i += timeStepSeconds) { const time = Cesium.JulianDate.addSeconds(startTime, i, new Cesium.JulianDate()); const jsDate = Cesium.JulianDate.toDate(time); try { const positionAndVelocity = propagate(satrec, jsDate); if (typeof positionAndVelocity.position === 'boolean') { console.warn(`卫星 ${satelliteId} 在时间 ${jsDate} 位置计算失败或已衰减。`); continue; // 跳过这个时间点 } const gmst = gstime(jsDate); const positionEcf = eciToEcf(positionAndVelocity.position, gmst); // 转换为 Cesium 坐标(单位:米) const cesiumPosition = new Cesium.Cartesian3(positionEcf.x * 1000, positionEcf.y * 1000, positionEcf.z * 1000); // 添加位置样本 sampledPositionProperty.addSample(time, cesiumPosition); hasSamples = true; // 标记已添加样本 if (showOrbit) { orbitPositions.push(cesiumPosition); } } catch (error) { console.error(`计算卫星 ${satelliteId} 在时间 ${jsDate} 的位置时出错:`, error); // 可以在这里决定是跳过还是中断循环 continue; } } // 确保至少有一个样本点,否则 SampledPositionProperty 会有问题 if (!hasSamples) { console.warn(`卫星 ${satelliteId} 未能计算出任何有效轨道点。`); return null; } return { sampledPositionProperty, orbitPositions }; } }