Refactor: 重构 HCesiumManager
This commit is contained in:
@ -0,0 +1,101 @@
|
||||
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');
|
||||
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<I卫星, 'orbitDurationSeconds' | 'showOrbit' | 'timeStepSeconds'>,
|
||||
satelliteId: string,
|
||||
): null | OrbitCalculationResult {
|
||||
const { orbitDurationSeconds = 默认轨道时长秒, timeStepSeconds = 默认时间步长秒, showOrbit = true } = 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 };
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user