Refactor: 重构 HCesiumManager

This commit is contained in:
严浩
2025-04-03 12:35:18 +08:00
parent b1c8597936
commit 8198fefe91
21 changed files with 905 additions and 683 deletions

View File

@ -0,0 +1,289 @@
import * as Cesium from 'cesium';
import type { HCesiumManager } from './HCesiumManager';
import type { I卫星 } from './HCesiumManager.types';
import { type OrbitCalculationResult, SatelliteCalculator } from '../calculators/SatelliteCalculator';
interface ManagedSatelliteEntities {
coverageEntity?: Cesium.Entity;
entity: Cesium.Entity;
orbitEntity?: Cesium.Entity;
}
export class SatelliteManager {
private viewerManager: HCesiumManager;
private calculator: SatelliteCalculator;
// 用于存储当前由此管理器管理的卫星相关实体的 Map
private currentSatelliteEntities: Map<string, ManagedSatelliteEntities> = new Map();
constructor(viewerManager: HCesiumManager, calculator: SatelliteCalculator) {
this.viewerManager = viewerManager;
this.calculator = calculator;
}
/**
* 向视图中添加或更新卫星实体及其相关元素(轨道、覆盖范围)。
* 注意:当前实现仅添加,如果已存在则警告并返回现有实体。
* @param options - 卫星的选项参数
* @returns 添加的卫星主实体对象,如果已存在或添加失败则返回 null 或现有实体。
*/
addOrUpdateSatellite(options: I卫星): Cesium.Entity | null {
const existingEntry = this.currentSatelliteEntities.get(options.id);
if (existingEntry) {
console.warn(`ID 为 "${options.id}" 的卫星实体已由管理器追踪,跳过添加。`);
// 未来可以扩展为更新逻辑
return existingEntry.entity;
}
const { id, tle, showOrbit = true } = options;
// --- 解析 TLE 和计算轨道 ---
const satrec = this.calculator.parseTle(tle, id);
if (!satrec) {
return null; // 解析失败,已打印错误
}
const viewer = this.viewerManager.getViewer();
if (!viewer) {
console.error('Viewer 未初始化,无法计算轨道。');
return null;
}
const startTime = viewer.clock.currentTime; // 使用当前 viewer 的时间作为起点
const orbitResult: null | OrbitCalculationResult = this.calculator.calculateOrbit(satrec, startTime, options, id);
if (!orbitResult) {
console.error(`计算卫星 ${id} 的轨道失败。`);
return null;
}
const { sampledPositionProperty, orbitPositions } = orbitResult;
// --- 计算结束 ---
// --- 从 TLE 提取名称 ---
const tleLines = tle.trim().split('\n');
const name = tleLines.length > 0 ? tleLines[0].trim() : `Satellite ${id}`;
// --- 提取结束 ---
// --- 创建实体 ---
const randomBaseColor = Cesium.Color.fromRandom({ alpha: 1 }); // 确保 alpha 为 1
// 创建卫星实体
const satelliteEntity = new Cesium.Entity({
id,
name,
position: sampledPositionProperty, // 使用计算好的位置属性
orientation: new Cesium.VelocityOrientationProperty(sampledPositionProperty),
point: {
pixelSize: 8,
color: randomBaseColor,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 1,
},
label: {
text: name,
font: '14pt sans-serif',
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth: 2,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(0, -10),
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.BLACK,
},
// 动态轨迹路径 (Path) - 注意:这与完整轨道线 (Polyline) 不同
path: {
resolution: 1,
material: new Cesium.PolylineGlowMaterialProperty({
glowPower: 0.15,
color: randomBaseColor,
}),
width: 2,
leadTime: (options.orbitDurationSeconds ?? 3600 * 2) / 2, // 默认1小时
trailTime: (options.orbitDurationSeconds ?? 3600 * 2) / 2, // 默认1小时
},
});
// 添加卫星地面覆盖范围
const coverageEntity = this.createCoverageEntity(id, name, sampledPositionProperty, randomBaseColor);
// 添加完整轨道线(如果需要)
let orbitEntity: Cesium.Entity | undefined;
if (showOrbit && orbitPositions.length > 1) {
orbitEntity = new Cesium.Entity({
id: `${id}-orbit`,
name: `${name} 轨道`,
polyline: {
positions: orbitPositions,
width: 1,
material: new Cesium.PolylineDashMaterialProperty({
color: randomBaseColor.withAlpha(0.5),
dashLength: 16,
}),
clampToGround: false,
},
});
}
// --- 创建结束 ---
// --- 添加到 Viewer ---
const addedMainEntity = this.viewerManager.addEntity(satelliteEntity);
if (!addedMainEntity) {
console.error(`通过 ViewerManager 添加卫星主体 ID 为 "${id}" 的实体失败。`);
return null; // 主实体添加失败则中止
}
let addedCoverageEntity: Cesium.Entity | null = null;
if (coverageEntity) {
addedCoverageEntity = this.viewerManager.addEntity(coverageEntity);
if (!addedCoverageEntity) {
console.warn(`通过 ViewerManager 添加卫星覆盖范围 ID 为 "${coverageEntity.id}" 的实体失败。`);
}
}
let addedOrbitEntity: Cesium.Entity | null = null;
if (orbitEntity) {
addedOrbitEntity = this.viewerManager.addEntity(orbitEntity);
if (!addedOrbitEntity) {
console.warn(`通过 ViewerManager 添加卫星轨道 ID 为 "${orbitEntity.id}" 的实体失败。`);
}
}
// --- 添加结束 ---
// 存储实体引用
this.currentSatelliteEntities.set(id, {
entity: addedMainEntity, // 存储实际添加成功的实体
orbitEntity: addedOrbitEntity ?? undefined,
coverageEntity: addedCoverageEntity ?? undefined,
});
return addedMainEntity;
}
/**
* 创建卫星覆盖范围实体。
*/
private createCoverageEntity(
satelliteId: string,
satelliteName: string,
positionProperty: Cesium.SampledPositionProperty,
baseColor: Cesium.Color,
): Cesium.Entity | null {
// 使用 CallbackProperty 动态计算星下点位置
const subsatellitePosition = new Cesium.CallbackPositionProperty( // 使用 CallbackPositionProperty
(time, result) => {
const satelliteCartesian = positionProperty.getValue(time, result);
if (!satelliteCartesian) return;
const satelliteCartographic = Cesium.Cartographic.fromCartesian(satelliteCartesian);
if (!satelliteCartographic) return;
const subsatelliteCartographic = new Cesium.Cartographic(
satelliteCartographic.longitude,
satelliteCartographic.latitude,
0,
);
return Cesium.Cartographic.toCartesian(subsatelliteCartographic, Cesium.Ellipsoid.WGS84, result);
},
false,
Cesium.ReferenceFrame.FIXED,
);
// 使用 CallbackProperty 动态计算覆盖半径 (基于高度的简单估算)
const coverageRadius = new Cesium.CallbackProperty((time) => {
const satelliteCartesian = positionProperty.getValue(time);
if (!satelliteCartesian) return 100_000; // 默认半径
const satelliteCartographic = Cesium.Cartographic.fromCartesian(satelliteCartesian);
if (!satelliteCartographic) return 100_000;
const altitude = satelliteCartographic.height;
// 简化的估算
const calculatedRadius = altitude * 0.8;
return Math.max(calculatedRadius, 50_000); // 最小半径 50km
}, false);
return new Cesium.Entity({
id: `${satelliteId}-coverage`,
name: `${satelliteName} 覆盖范围`,
position: subsatellitePosition,
ellipse: {
semiMajorAxis: coverageRadius,
semiMinorAxis: coverageRadius,
material: baseColor.withAlpha(0.2), // 半透明填充
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
outline: true,
outlineColor: baseColor.withAlpha(0.5), // 轮廓
outlineWidth: 1,
granularity: Cesium.Math.toRadians(1),
},
});
}
/**
* 从视图中移除指定的卫星实体及其相关元素 (通过 ID)。
* @param entityId - 要移除的卫星实体的 ID。
* @returns 如果成功移除所有相关实体则返回 true否则返回 false。
*/
removeSatellite(entityId: string): boolean {
const satelliteData = this.currentSatelliteEntities.get(entityId);
if (!satelliteData) {
// console.warn(`未在 SatelliteManager 中找到 ID 为 "${entityId}" 的实体,无法移除。`);
return false; // 不在管理范围内
}
let allRemoved = true;
// 移除主体
if (!this.viewerManager.removeEntity(satelliteData.entity)) {
console.warn(`尝试通过 ViewerManager 移除卫星主体 ID 为 "${entityId}" 的实体失败。`);
allRemoved = false;
}
// 移除轨道
if (satelliteData.orbitEntity && !this.viewerManager.removeEntity(satelliteData.orbitEntity)) {
console.warn(`尝试通过 ViewerManager 移除卫星轨道 ID 为 "${satelliteData.orbitEntity.id}" 的实体失败。`);
allRemoved = false;
}
// 移除覆盖范围
if (satelliteData.coverageEntity && !this.viewerManager.removeEntity(satelliteData.coverageEntity)) {
console.warn(`尝试通过 ViewerManager 移除卫星覆盖范围 ID 为 "${satelliteData.coverageEntity.id}" 的实体失败。`);
allRemoved = false;
}
// 从 Map 中删除,无论移除是否完全成功,以避免状态不一致
this.currentSatelliteEntities.delete(entityId);
return allRemoved;
}
/**
* 清除所有由此管理器管理的卫星实体及其相关元素。
*/
clearAllSatellites(): void {
const idsToRemove = [...this.currentSatelliteEntities.keys()];
let removalFailed = false;
for (const id of idsToRemove) {
if (!this.removeSatellite(id)) {
removalFailed = true;
}
}
if (removalFailed) {
console.warn('清除部分卫星实体时遇到问题。');
}
// 确保最终清空 Map
this.currentSatelliteEntities.clear();
}
/**
* 获取当前管理的卫星实体 Map。
* @returns 返回包含当前卫星实体及其关联实体的 Map。
*/
getCurrentSatelliteEntities(): Map<string, ManagedSatelliteEntities> {
return this.currentSatelliteEntities;
}
/**
* 销毁管理器,清理资源。
*/
destroy(): void {
this.clearAllSatellites();
// console.log('SatelliteManager 已销毁。');
}
}