feat: 添加卫星实体类及相关功能,优化 Cesium 初始化和时间线设置
All checks were successful
/ depcheck (push) Successful in 2m5s
/ lint-build-and-check (push) Successful in 2m43s
/ build-and-deploy-to-vercel (push) Successful in 3m1s
/ surge (push) Successful in 3m3s
/ playwright (push) Successful in 5m52s

This commit is contained in:
严浩
2025-03-11 16:01:55 +08:00
parent ec49e340ea
commit a2f07c7d76
7 changed files with 147 additions and 7 deletions

View File

@ -7,9 +7,9 @@ export const VIEWER_OPTIONS: Viewer.ConstructorOptions = {
baseLayer: Cesium.ImageryLayer.fromProviderAsync(
Cesium.TileMapServiceImageryProvider.fromUrl(Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII')),
),
baseLayerPicker: !true,
baseLayerPicker: false,
fullscreenButton: !true, // 全屏按钮
geocoder: !true, // = IonGeocodeProviderType.DEFAULT] - 在使用Geocoder小部件进行搜索时使用的地理编码服务或服务。如果设置为false则不会创建Geocoder小部件。
geocoder: false, // = IonGeocodeProviderType.DEFAULT] - 在使用Geocoder小部件进行搜索时使用的地理编码服务或服务。如果设置为false则不会创建Geocoder小部件。
// globe: false, // 地球
homeButton: true, // Home按钮

View File

@ -4,6 +4,8 @@ import { VIEWER_OPTIONS } from './00.cesium-init.VIEWER_OPTIONS';
import 'cesium/Build/Cesium/Widgets/widgets.css';
Cesium.Ion.defaultAccessToken = import.meta.env.VITE_CESIUM_ION_TOKEN; // 用了离线地图的情况是不需要的。
Object.assign(window, { Cesium });
_configureCesium();
@ -13,6 +15,8 @@ export function cesium_init(container: Element) {
viewer.scene.debugShowFramesPerSecond = true;
initTimeLine(viewer);
return viewer;
}
@ -60,3 +64,15 @@ function _configureCesium() {
60, // 北纬
);
}
function initTimeLine(viewer: Cesium.Viewer, totalSeconds = /* 默认场景的时间跨度 */ 24 * 60 * 60) {
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.timeline.zoomTo(start, stop);
viewer.clock.multiplier = 1;
viewer.clock.shouldAnimate = true;
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
}

View File

@ -0,0 +1,108 @@
import type { Cartesian3 } from 'cesium';
import * as Cesium from 'cesium';
import { propagate, twoline2satrec } from 'satellite.js';
class SatelliteEntity {
private leadTime!: number;
private name!: string;
private satrec: any;
private stepSeconds!: number;
private tleLine1!: string;
private tleLine2!: string;
private totalSeconds!: number;
private trailTime!: number;
constructor(tle = '' /* , options = {} */) {
const [name, tleLine1, tleLine2] = this._checkTle(tle);
const circle = Number(tleLine2.slice(52, 64));
this.name = name.trim();
this.tleLine1 = tleLine1.trim();
this.tleLine2 = tleLine2.trim();
this.satrec = twoline2satrec(this.tleLine1, this.tleLine2);
this.totalSeconds = 86_400; // 24小时
this.stepSeconds = 100;
this.leadTime = Math.round((24 * 3600) / circle);
this.trailTime = 0;
}
_checkTle(tle: string) {
const elements = tle.split('\n');
if (elements.length !== 3) throw new Error('tle data error');
return elements as [string, string, string];
}
// 创建PositionProperty
_getPositionProperty() {
const start = Cesium.JulianDate.fromIso8601(new Date().toISOString());
const positionProperty = new Cesium.SampledPositionProperty(Cesium.ReferenceFrame.INERTIAL);
const now = Date.now();
for (let i = 0; i < this.totalSeconds / this.stepSeconds; i++) {
const sateTime = new Date(now + i * this.stepSeconds * 1000);
const sateCoord = this.getPositionEci(sateTime);
if (!sateCoord) continue;
const cesiumTime = Cesium.JulianDate.addSeconds(start, i * this.stepSeconds, new Cesium.JulianDate());
const cesiumPosition = {
x: sateCoord.x * 1000,
y: sateCoord.y * 1000,
z: sateCoord.z * 1000,
} as Cartesian3;
positionProperty.addSample(cesiumTime, cesiumPosition);
}
return positionProperty;
}
// 创建卫星实例
createSatelliteEntity() {
const start = Cesium.JulianDate.fromIso8601(new Date().toISOString());
const stop = Cesium.JulianDate.addSeconds(start, this.totalSeconds, new Cesium.JulianDate());
const color = Cesium.Color.fromRandom({ alpha: 1 });
const satelliteEntity = {
availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({ start, stop })]),
description: this.name,
label: {
backgroundColor: new Cesium.Color(0.165, 0.165, 0.165, 0.5),
backgroundPadding: new Cesium.Cartesian2(4, 4),
fillColor: Cesium.Color.WHITE,
font: '12px sans-serif',
horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
outlineWidth: 1,
pixelOffset: new Cesium.Cartesian2(0, 5),
showBackground: true,
text: this.name,
verticalOrigin: Cesium.VerticalOrigin.TOP,
// distanceDisplayCondition: new Cesium.DistanceDisplayCondition(10.0, 50000000),
},
name: this.name,
path: new Cesium.PathGraphics({
leadTime: this.leadTime,
material: color,
show: true,
trailTime: this.trailTime,
width: 0.5,
}),
point: {
color,
pixelSize: 8,
// scaleByDistance: new Cesium.NearFarScalar(1.5e3, 1, 8.0e8, 0.5),
},
position: this._getPositionProperty(),
};
return satelliteEntity;
}
// 获取地心惯性坐标系坐标
getPositionEci(date: Date) {
const result = propagate(this.satrec, date);
// 检查position是否为对象且不是true
if (typeof result.position !== 'object' || result.position === null) {
return null;
}
return result.position;
}
}
export default SatelliteEntity;

View File

@ -0,0 +1,8 @@
export const TLE_LIST = [
`2025-045A
1 63157U 25045A 25069.35219743 .00000545 -65692-6 00000+0 0 9992
2 63157 19.0062 64.6364 7327661 179.7218 141.4162 2.26206155 28`,
`STARLINK-11371 [DTC]
1 62879U 25024A 25062.93300820 .00003305 00000+0 21841-4 0 9995
2 62879 42.9977 257.3937 0001725 269.2925 90.7748 15.77864921 5143`,
];

View File

@ -45,8 +45,6 @@ export async function demo_02_Track(viewer: Viewer) {
outlineWidth: 2,
pixelSize: 10,
},
// viewFrom: new Cartesian3(0, -1.5e7, 2.5e7),
// https://www.google.com/search?q=cesium%C2%A0viewFrom%C2%A0+trackedEntity
});
// 计算并绘制卫星轨迹

View File

@ -2,17 +2,28 @@
import type { Viewer } from 'cesium';
import { cesium_init } from './cesium-helper/00.cesium-init';
import { TLE_LIST } from './cesium-helper/_TLE_DATA';
import { demo_01_OrbitGeneration } from './cesium-helper/demo_01_OrbitGeneration';
import { demo_02_Track } from './cesium-helper/demo_02_Track';
import SatelliteEntity from './cesium-helper/SatelliteEntity';
let viewer: Viewer;
onMounted(async () => {
viewer = cesium_init(document.getElementById('cesiumContainer')!);
viewer = cesium_init(document.querySelector('#cesiumContainer')!);
Object.assign(globalThis, { viewer });
(({ run }) => (run ? demo_01_OrbitGeneration(viewer) : null))({ run: false });
(({ run }) => (run ? demo_02_Track(viewer) : null))({ run: true });
(({ run }) => (run ? demo_02_Track(viewer) : null))({ run: false });
// demo_01_OrbitGeneration(viewer);
// demo_02_Track(viewer);
TLE_LIST.forEach((tle) => {
const satellite = new SatelliteEntity(tle);
const cesiumSateEntity = satellite.createSatelliteEntity();
/* let result = */ viewer.entities.add(cesiumSateEntity);
});
});
</script>

View File

@ -34,4 +34,3 @@ async function handleConfirmAsync(e: MouseEvent) {
</ACard>
</ACard>
</template>
./HAPopconfirm.vue