h-cesium-viewer
Some checks failed
/ build-and-deploy-to-vercel (push) Successful in 2m45s
/ lint-build-and-check (push) Successful in 4m32s
/ playwright (push) Failing after 12m4s
/ surge (push) Successful in 2m34s

This commit is contained in:
严浩
2025-04-02 16:38:02 +08:00
parent 098a769dbd
commit 02ce0fa9a0
21 changed files with 95 additions and 367 deletions

View File

@ -1,4 +0,0 @@
- 卫星覆盖范围: 当前实现是基于卫星高度的一个简化估算altitude * 0.8),代码注释也指明了这一点。这种方法不够精确,仅能提供一个大致的视觉参考。精确的覆盖范围计算需要考虑卫星的视场角 (FOV) 或波束宽度等具体参数。
- TLE 数据 → 轨道 → 位置 & 速度
- 大小 → 需要外部规格数据
- 精确姿态 → 需要专门的 ADCS 数据 (TLE 不提供)

View File

@ -0,0 +1,4 @@
- 卫星覆盖范围: 当前实现是基于卫星高度的一个简化估算altitude \* 0.8),代码注释也指明了这一点。这种方法不够精确,仅能提供一个大致的视觉参考。精确的覆盖范围计算需要考虑卫星的视场角 (FOV) 或波束宽度等具体参数。
- TLE 数据 → 轨道 → 位置 & 速度
- 大小 → 需要外部规格数据
- 精确姿态 → 需要专门的 ADCS 数据 (TLE 不提供)

View File

@ -0,0 +1,39 @@
## 配置项目
- https://github.dev/CesiumGS/cesium-vite-example
### 其他
- https://cesium.com/blog/2024/02/13/configuring-vite-or-webpack-for-cesiumjs/
- https://cesium.com/learn/cesiumjs-learn/cesiumjs-quickstart/
- vite-plugin-cesium
## 参考
- [vue-cesium](https://zouyaoji.top/vue-cesium/#/zh-CN/component/controls/vc-navigation)
- https://cesium.pages.dev/
## 离线地图
- https://github.com/CesiumGS/cesium/tree/main/Documentation/OfflineGuide
- https://blog.csdn.net/lhllhllhl_/article/details/145857779
- https://blog.csdn.net/m0_54849806/article/details/126070809
- https://juejin.cn/post/6969838266182795278
- https://blog.csdn.net/CSDNqinzhike/article/details/139587028
## TLE
### 格式
- https://celestrak.org/NORAD/documentation/tle-fmt.php
- https://en.wikipedia.org/wiki/Two-line_element_set#Format
### 轨道数据
- https://celestrak.org/NORAD/elements/
- https://www.n2yo.com/satellites/?c=PRC&t=country
- https://www.space-track.org/#catalog
### 相关
- https://www.satview.org/?sat_id=63158U

View File

@ -1,31 +1,24 @@
import * as Cesium from 'cesium';
import { eciToEcf, gstime, propagate, type SatRec, twoline2satrec } from 'satellite.js';
import { VIEWER_OPTIONS_FN } from './VIEWER_OPTIONS';
import type { GroundStationOptions, SatelliteOptions } from './h-cesium-viewer-class.types'; // 2小时
export interface GroundStationOptions {
height?: number; // 可选高度默认为0
id: string; // 站点的唯一标识符
latitude: number;
longitude: number;
name: string;
pixelSize?: number; // 点的可选像素大小
}
import { VIEWER_OPTIONS_FN } from './helper/_VIEWER_OPTIONS';
import { configureCesium } from './helper/configureCesium';
import { configureTimeLine } from './helper/configureTimeLine';
// 卫星选项接口
export interface SatelliteOptions {
id: string; // 卫星的唯一标识符
orbitDurationHours?: number; // 轨道显示时长(小时),默认为 2
showOrbit?: boolean; // 是否显示完整轨道线,默认为 true
timeStepSeconds?: number; // 轨道计算步长(秒),默认为 30
tle: string; // 包含卫星名称和两行 TLE 数据的字符串,格式如下:
// NAME
// TLE1
// TLE2
}
const = 2 * 60 * 60;
export { type GroundStationOptions, type SatelliteOptions } from './h-cesium-viewer-class.types';
Cesium.Ion.defaultAccessToken = import.meta.env.VITE_CESIUM_ION_TOKEN; // 用了离线地图的情况是不需要的。
Object.assign(globalThis, { Cesium });
configureCesium();
export class HCesiumViewerCls {
private viewer: Cesium.Viewer | null = null;
viewer: Cesium.Viewer | null = null;
// 用于存储当前地面站实体的 Map
currentStationEntities: Map<string, Cesium.Entity> = new Map();
// 用于存储当前卫星实体的 Map (包括轨道实体)
@ -45,6 +38,10 @@ export class HCesiumViewerCls {
initCesiumViewer(container: ConstructorParameters<typeof Cesium.Viewer>[0]) {
this.viewer = new Cesium.Viewer(container, VIEWER_OPTIONS_FN());
configureTimeLine(this.viewer);
this.viewer.scene.debugShowFramesPerSecond = true;
// 初始化时清空可能存在的旧实体引用
this.currentStationEntities.clear();
this.currentSatelliteEntities.clear();
@ -158,7 +155,7 @@ export class HCesiumViewerCls {
const {
id,
tle,
orbitDurationHours = 2, // 默认轨道时长 2 小时
orbitDurationSeconds = ,
timeStepSeconds = 30, // 默认步长 30 秒
showOrbit = true, // 默认显示轨道
} = options;
@ -215,18 +212,17 @@ export class HCesiumViewerCls {
color: randomBaseColor, // 使用随机基色
}),
width: 2,
leadTime: (orbitDurationHours * 3600) / 2, // 显示未来一半时间的轨迹
trailTime: (orbitDurationHours * 3600) / 2, // 显示过去一半时间的轨迹
leadTime: orbitDurationSeconds / 2, // 显示未来一半时间的轨迹
trailTime: orbitDurationSeconds / 2, // 显示过去一半时间的轨迹
},
});
// --- 计算轨道 ---
const totalSeconds = orbitDurationHours * 60 * 60;
const startTime = this.viewer.clock.currentTime; // 使用当前 viewer 的时间作为起点
const positionProperty = new Cesium.SampledPositionProperty();
const orbitPositions: Cesium.Cartesian3[] = []; // 用于存储完整轨道点
for (let i = 0; i <= totalSeconds; i += timeStepSeconds) {
for (let i = 0; i <= orbitDurationSeconds; i += timeStepSeconds) {
const time = Cesium.JulianDate.addSeconds(startTime, i, new Cesium.JulianDate());
const jsDate = Cesium.JulianDate.toDate(time);
@ -311,7 +307,7 @@ export class HCesiumViewerCls {
ellipse: {
semiMajorAxis: coverageRadius,
semiMinorAxis: coverageRadius, // 假设圆形覆盖
material: randomBaseColor.withAlpha(0.2), // 基于随机基色的半透明填充
material: randomBaseColor.withAlpha(0.2 + 0.3), // 基于随机基色的半透明填充
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 贴合地形
outline: true,
outlineColor: randomBaseColor.withAlpha(0.8), // 基于随机基色的较深半透明轮廓

View File

@ -0,0 +1,20 @@
export interface GroundStationOptions {
height?: number; // 可选高度默认为0
id: string; // 站点的唯一标识符
latitude: number;
longitude: number;
name: string;
pixelSize?: number; // 点的可选像素大小
}
// 卫星选项接口
export interface SatelliteOptions {
id: string; // 卫星的唯一标识符
orbitDurationSeconds?: number; // 轨道显示时长
showOrbit?: boolean; // 是否显示完整轨道线,默认为 true
timeStepSeconds?: number; // 轨道计算步长(秒),默认为 30
tle: string; // 包含卫星名称和两行 TLE 数据的字符串,格式如下:
// NAME
// TLE1
// TLE2
}

View File

@ -0,0 +1,20 @@
/* prettier-ignore */
export const TOOLTIP_MAP = {
NORAD_CAT_ID_卫星编号: "5位数字如'63158'表示NORAD卫星唯一目录编号",
CLASSIFICATION_TYPE_卫星分类: "1个字母如'U',表示数据分类",
OBJECT_ID_国际标识符: "8个字符如'25045B'(年份+发射编号+部件),不足时右侧补空格",
EPOCH_历元时间: "14位数字如'25071.65907894',表示轨道数据的参考时间(年份+年积日.一天中的小数部分)",
MEAN_MOTION_DOT_平均运动一阶导数: "10位数字如'.00072212',表示平均运动变化率的一半,单位圈/天²,左侧补空格",
MEAN_MOTION_DDOT_平均运动二阶导数: "8位科学计数法如'-50502-6'表示-5.0502×10⁻⁶圈/天³,最后一位是指数",
BSTAR_BSTAR拖曳项: "BSTAR参数。8位科学计数法如'39937-3'表示0.39937×10⁻³/地球半径,表示大气拖曳影响",
EPHEMERIS_TYPE_星历类型: "通常为'0'表示使用SGP4星历模型",
ELEMENT_SET_NO_元素集编号: "4位数字如'9999'表示TLE版本号",
// CHECKSUM_校验和: "1位数字用于验证数据完整性可选项",
INCLINATION_轨道倾角: "8位数字如'19.0363'表示轨道与赤道平面的夹角范围0°-180°",
RA_OF_ASC_NODE_升交点赤经: "8位数字如'63.0294'表示轨道升交点的赤经范围0°-360°",
ECCENTRICITY_离心率: "7位数字无小数点如'7375486'表示0.7375486,小数点隐含在最前面",
ARG_OF_PERICENTER_近地点幅角: "8位数字如'181.9338'表示近地点相对升交点的角度范围0°-360°",
MEAN_ANOMALY_平近点角: "8位数字如'171.6150'表示历元时的平近点角范围0°-360°",
MEAN_MOTION_平均运动: "11位数字如'2.21786616',表示卫星每天绕地球的圈数(圈/天)",
REV_AT_EPOCH_历元时的圈数: "5位数字如'13'表示卫星在历元时完成的轨道圈数最后以为是校验和共6位",
};

View File

@ -0,0 +1,46 @@
import * as Cesium from 'cesium';
export function configureCesium() {
if (document.querySelector('#hide-cesium-viewer-bottom') === null) {
document.head.append(
Object.assign(document.createElement('style'), {
id: 'hide-cesium-viewer-bottom',
innerHTML: `
.cesium-viewer-bottom {
display: none !important;
}
`.trim(),
type: 'text/css',
}),
);
}
/* 时间日期格式化 */ {
const minutes = 0 - new Date().getTimezoneOffset(); // 0 - (-480);
// Animation 的时间日期格式化
Cesium.AnimationViewModel.defaultDateFormatter = function (date) {
const dataZone8 = Cesium.JulianDate.addMinutes(date, minutes, new Cesium.JulianDate());
return Cesium.JulianDate.toIso8601(dataZone8).slice(0, 10);
};
Cesium.AnimationViewModel.defaultTimeFormatter = function (time) {
const dataZone8 = Cesium.JulianDate.addMinutes(time, minutes, new Cesium.JulianDate());
return Cesium.JulianDate.toIso8601(dataZone8).slice(11, 19);
};
// Timeline 的时间日期格式化
// @ts-expect-error node_modules/@cesium/widgets/Source/Timeline/Timeline.js
Cesium.Timeline.prototype.makeLabel = function (time) {
const dataZone8 = Cesium.JulianDate.addMinutes(time, minutes, new Cesium.JulianDate());
return Cesium.JulianDate.toIso8601(dataZone8).slice(0, 19);
};
}
// 默认视图区域
Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(
75, // 西经
10, // 南纬
140, // 东经
60, // 北纬
);
}

View File

@ -0,0 +1,34 @@
import * as Cesium from 'cesium';
const provider = new Cesium.UrlTemplateImageryProvider({
maximumLevel: 18,
minimumLevel: 3,
url: 'https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
});
export function configureMapTile(viewer: Cesium.Viewer) {
if (viewer.baseLayerPicker) {
// 如果有底图选择器
const customLayerViewModel = new Cesium.ProviderViewModel({
category: 'Cesium ion', // 或 'Other 、Cesium ion'、'Bing Maps' 等
creationFunction() {
return provider;
},
iconUrl: 'gaodeImage.png',
name: '高德地图',
tooltip: '高德地图',
});
// 设置高德地图为默认图层
viewer.baseLayerPicker.viewModel.imageryProviderViewModels.unshift(customLayerViewModel);
const selectedViewModel = viewer.baseLayerPicker.viewModel.imageryProviderViewModels[0];
if (!selectedViewModel) {
console.error('未找到默认底图');
return;
}
viewer.baseLayerPicker.viewModel.selectedImagery = selectedViewModel;
} else {
// 如果没有底图选择器
viewer.imageryLayers.removeAll();
viewer.imageryLayers.addImageryProvider(provider);
}
}

View File

@ -0,0 +1,20 @@
import * as Cesium from 'cesium';
const = 2 * 60 * 60; // 2小时
export function configureTimeLine(viewer: Cesium.Viewer, totalSeconds = ) {
const start = Cesium.JulianDate.fromIso8601(new Date().toISOString());
const stop = Cesium.JulianDate.addSeconds(start, totalSeconds, new Cesium.JulianDate());
// 设置时钟范围
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
viewer.clock.multiplier = 30; // 30倍速播放
// 设置时间轴范围
viewer.timeline.zoomTo(start, stop);
viewer.clock.shouldAnimate = true;
}