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 HCesiumSatelliteManager { private viewerManager: HCesiumManager; private calculator: SatelliteCalculator; // 用于存储当前由此管理器管理的卫星相关实体的 Map private currentSatelliteEntities: Map = 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 } = 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 { return this.currentSatelliteEntities; } /** * 销毁管理器,清理资源。 */ destroy(): void { this.clearAllSatellites(); // console.log('SatelliteManager 已销毁。'); } }