diff --git a/src/components/h-cesium-viewer/README.md b/src/components/h-cesium-viewer/README.md new file mode 100644 index 0000000..cf60040 --- /dev/null +++ b/src/components/h-cesium-viewer/README.md @@ -0,0 +1,4 @@ +- 卫星覆盖范围: 当前实现是基于卫星高度的一个简化估算(altitude * 0.8),代码注释也指明了这一点。这种方法不够精确,仅能提供一个大致的视觉参考。精确的覆盖范围计算需要考虑卫星的视场角 (FOV) 或波束宽度等具体参数。 +- TLE 数据 → 轨道 → 位置 & 速度 +- 大小 → 需要外部规格数据 +- 精确姿态 → 需要专门的 ADCS 数据 (TLE 不提供) diff --git a/src/components/h-cesium-viewer/h-cesium-viewer-class.ts b/src/components/h-cesium-viewer/h-cesium-viewer-class.ts index 6f39890..b9551d9 100644 --- a/src/components/h-cesium-viewer/h-cesium-viewer-class.ts +++ b/src/components/h-cesium-viewer/h-cesium-viewer-class.ts @@ -29,7 +29,14 @@ export class HCesiumViewerCls { // 用于存储当前地面站实体的 Map currentStationEntities: Map = new Map(); // 用于存储当前卫星实体的 Map (包括轨道实体) - currentSatelliteEntities: Map = new Map(); + currentSatelliteEntities: Map< + string, + { + coverageEntity?: Cesium.Entity; + entity: Cesium.Entity; + orbitEntity?: Cesium.Entity; + } + > = new Map(); /** * 初始化 Cesium Viewer @@ -250,6 +257,67 @@ export class HCesiumViewerCls { satelliteEntity.position = positionProperty; satelliteEntity.orientation = new Cesium.VelocityOrientationProperty(positionProperty); + // --- 添加卫星地面覆盖范围 --- + // 使用 CallbackProperty 动态计算星下点位置 + const subsatellitePosition = new Cesium.CallbackPositionProperty( + (time, result) => { + // 从 satelliteEntity 获取当前时间的精确位置 + const satelliteCartesian = positionProperty.getValue(time, result); + if (!satelliteCartesian) { + return; // 如果位置无效,则不返回任何内容 + } + // 转换为地理坐标(包含高度) + const satelliteCartographic = Cesium.Cartographic.fromCartesian(satelliteCartesian); + if (!satelliteCartographic) { + return; // 如果转换失败,则不返回任何内容 + } + // 创建星下点地理坐标(高度设为0) + const subsatelliteCartographic = new Cesium.Cartographic( + satelliteCartographic.longitude, + satelliteCartographic.latitude, + 0, + ); + // 转换回笛卡尔坐标 + return Cesium.Cartographic.toCartesian(subsatelliteCartographic, Cesium.Ellipsoid.WGS84, result); + }, + false, + Cesium.ReferenceFrame.FIXED, + ); // isConstant: false, referenceFrame: FIXED + + // 使用 CallbackProperty 动态计算覆盖半径 (基于高度的简单估算) + const coverageRadius = new Cesium.CallbackProperty((time) => { + const satelliteCartesian = positionProperty.getValue(time); + if (!satelliteCartesian) { + return 100_000; // 默认半径 100km + } + const satelliteCartographic = Cesium.Cartographic.fromCartesian(satelliteCartesian); + if (!satelliteCartographic) { + return 100_000; + } + const altitude = satelliteCartographic.height; + // 简化的估算:半径约为高度的 0.8 倍,最小 50km + // 实际应用中应基于卫星的视场角 (FOV) 或波束宽度计算 + const calculatedRadius = altitude * 0.8; + return Math.max(calculatedRadius, 50_000); // 最小半径 50km + }, false); // isConstant 设置为 false + + const coverageEntity = this.viewer.entities.add({ + id: `${id}-coverage`, + name: `${name} 覆盖范围`, + position: subsatellitePosition, + ellipse: { + semiMajorAxis: coverageRadius, + semiMinorAxis: coverageRadius, // 假设圆形覆盖 + material: Cesium.Color.RED.withAlpha(0.3), // 半透明红色 + heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 贴合地形 + outline: true, + outlineColor: Cesium.Color.BLACK.withAlpha(0.5), + outlineWidth: 1, + // fill: true, // 默认填充 + }, + }); + // --- 覆盖范围结束 --- + let orbitEntity: Cesium.Entity | undefined; // 添加完整轨道线(如果需要) if (showOrbit && orbitPositions.length > 1) { @@ -269,7 +337,7 @@ export class HCesiumViewerCls { } // 存储实体引用 - this.currentSatelliteEntities.set(id, { entity: satelliteEntity, orbitEntity }); + this.currentSatelliteEntities.set(id, { entity: satelliteEntity, orbitEntity, coverageEntity }); return satelliteEntity; } @@ -288,6 +356,7 @@ export class HCesiumViewerCls { if (satelliteData) { let removedMain = true; let removedOrbit = true; + let removedCoverage = true; // 新增:覆盖范围移除状态 // 移除卫星主体 if (satelliteData.entity) { @@ -305,8 +374,17 @@ export class HCesiumViewerCls { } } + // 移除覆盖范围 + if (satelliteData.coverageEntity) { + removedCoverage = this.viewer.entities.remove(satelliteData.coverageEntity); + if (!removedCoverage) { + console.warn(`尝试从 Cesium 移除卫星覆盖范围 ID 为 "${satelliteData.coverageEntity.id}" 的实体失败。`); + } + } + // 如果主体和轨道(如果存在)都移除成功或不存在,则从 Map 中删除 - if (removedMain && removedOrbit) { + // 如果主体、轨道(如果存在)和覆盖范围(如果存在)都移除成功或不存在,则从 Map 中删除 + if (removedMain && removedOrbit && removedCoverage) { this.currentSatelliteEntities.delete(entityId); return true; } else {