🛰️ dtSpaceMap - 实时卫星追踪 3D 可视化平台

3d可视化.png

基于 Three.js 构建的实时卫星追踪 3D 可视化 Web 平台,支持 30,000+ 卫星对象同时渲染,帧率 ≥30fps。提供星座管理、碰撞预警、过境预测、TLE 解析、摄影炸弹、坐标转换等专业工具链。

架构概览

分层架构 (Layered Architecture)

分层架构图.png

通信架构 (Communication Architecture)

通信架构图.png

核心业务流程

1. 卫星数据同步与加载流程

mermaid
复制代码
graph TB A[用户点击分类加载] --> B{fetchLiveCategoryData} B --> C[Step 1: POST /api/public/sync/groups] C --> D{后端检查 sync_tracking} D -->|6小时内已同步| E[跳过拉取] D -->|未同步或过期| F[从 CelesTrak 拉取 TLE] F --> G[解析 TLE 文本] G --> H[批量写入数据库] H --> I[更新 sync_tracking 记录] E --> J[Step 2: GET /api/public/satellites/with-tle-by-groups] I --> J J --> K[从数据库加载卫星数据] K --> L{数据是否足够?} L -->|是| M[填充 Pinia Store] L -->|否| N[Step 3: 前端直连 CelesTrak 回退] N --> M M --> O[VisualizerView 桥接] O --> P[loadRealSatellites] P --> Q[创建 GPU InstancedMesh] Q --> R[初始化 SGP4 Web Worker] R --> S[实时渲染循环]

定时任务补充: XXL-JOB 每天凌晨 02:00 自动执行增量同步,检查 sync_tracking 表,跳过 6 小时内已同步的分组。用户再次加载同一分类时,命中 sync_tracking 记录直接返回数据库数据。

2. 用户认证与授权流程

mermaid
复制代码
graph TB A[用户访问受保护路由] --> B{Vue Router 导航守卫} B --> C{localStorage 有 accessToken?} C -->|否| D[重定向到 /login?redirect=原路径] C -->|是| E[放行进入页面] D --> F[用户填写登录表单] F --> G[POST /api/auth/login] G --> H{Spring Security 认证} H -->|失败| I[返回 401 + 错误信息] H -->|成功| J[生成 JWT accessToken + refreshToken] J --> K[返回令牌对] K --> L[前端存储到 localStorage] L --> M[重定向回原路径] N[Axios 请求拦截器] --> O{检测 token} O -->|存在| P[注入 Authorization Bearer 头] O -->|不存在| Q[放行匿名请求] R[Axios 响应拦截器] --> S{状态码 401?} S -->|是| T[清除本地 token] T --> U[跳转 /login] S -->|否| V[统一错误提示]

3. SGP4 轨道计算与 3D 渲染循环

mermaid
复制代码
graph TB subgraph 主线程 Main Thread A[requestAnimationFrame] --> B[计算帧间隔 dt] B --> C{时间是否播放?} C -->|是| D[推进仿真时间 simTime] C -->|否| E{自动旋转?} E -->|是| F[缓慢旋转地球] F --> G[updateSatellitePositions] D --> G G --> H[逐卫星计算轨道位置] H --> I[Billboard 朝向相机] I --> J[距离自适应缩放] J --> K[更新 InstancedMesh Matrix] K --> L{有选中卫星?} L -->|是| M[更新高亮环/波纹/探照灯动画] M --> N[更新拖尾轨迹] L -->|否| O[checkHover 射线检测] O --> P{命中卫星?} P -->|是| Q[显示 hover 光环 + 标签 + 轨道] P -->|否| R[清除 hover 特效] N --> S[renderer.render] R --> S Q --> S S --> A end subgraph SGP4 Worker 线程 W1[接收 init 消息] --> W2[twoline2satrec 解析 TLE] W2 --> W3[存储 satrec 对象] W3 --> W4[postMessage initialized] W4 --> W5{每秒接收 propagate 消息} W5 --> W6[sgp4 批量传播计算] W6 --> W7[ECI → 大地坐标转换] W7 --> W8[postMessage 位置结果] W8 --> W5 end subgraph 真实数据模式 T1[loadRealSatellites] --> T2[createRealSatellites] T2 --> T3[initSgp4Worker] T3 --> W1 T3 --> T4[usingRealData = true] T4 --> T5[每秒 requestWorkerPositions] T5 --> W5 W8 --> T6[updateRealSatPositions] T6 --> K end

4. 卫星交互操作流程

mermaid
复制代码
graph TB A[用户操作] --> B{操作类型} B -->|鼠标悬停| C[mousemove 事件] C --> D[更新 mouse 坐标] D --> E[checkHover 节流 35ms] E --> F[Raycaster 检测 allSatMeshes] F --> G{命中 InstancedMesh?} G -->|是| H[instanceToNorad 查找 satData] H --> I{与选中卫星相同?} I -->|否| J[显示 hover 光环 + 标签 + hover 轨道] I -->|是| K[保持选中高亮, 隐藏 hover] J --> K G -->|否| L[清除 hover 特效] B -->|鼠标点击| M[click 事件] M --> N[Raycaster 检测] N --> O{命中卫星?} O -->|是| P[设置 selectedSatellite] P --> Q[高亮轨道 activeOrbitLine] Q --> R[placeHighlight 多层脉冲环] R --> S[createRippleEffect 波纹扩散] S --> T[createSpotlightEffect 探照灯] T --> U[showLabelFor 名称标签] U --> V[聚焦动画 focusOnSatellite] V --> W[更新 Pinia Store] W --> X[弹出 SatelliteDetail 面板] O -->|否| Y[clearSelection 清除所有特效] B -->|空格键| Z[切换全局搜索面板] Z --> AA[输入关键词] AA --> AB[本地/后端搜索卫星] AB --> AC[选择卫星 → 触发点击流程]

技术栈

前端

技术说明版本
Vue 3渐进式框架 (Composition API)^3.4.27
TypeScript类型安全^5.4.5
Vite构建工具^5.2.0
Pinia状态管理^2.1.7
Three.js3D 渲染引擎^0.165.0
Element PlusUI 组件库 (暗色主题)^2.7.0
ECharts数据可视化图表^5.5.0
satellite.jsSGP4/SDP4 轨道计算^5.0.0
ootk航天轨道计算库^7.0.3
AxiosHTTP 客户端^1.7.2
Vue Router路由管理^4.3.2
vue-i18n国际化^9.13.0

后端

技术说明版本
Spring Boot应用框架3.2.5
Java运行环境17
MyBatis FlexORM 框架1.9.3
PostgreSQL关系数据库14+
Redis缓存7+
Flyway数据库迁移10.11.1
Spring Security认证授权6.x
JWT (jjwt)令牌认证0.12.5
XXL-JOB分布式定时调度2.4.1
Knife4jAPI 文档4.5.0
HutoolJava 工具库5.8.28
MapStruct对象映射1.5.5
Lombok代码简化1.18.32
Spring AIAI 集成1.0.0-M4

运维

技术说明
Docker容器化部署
Docker Compose本地编排 (PostgreSQL + Redis)
GitHub ActionsCI/CD 流水线
Prometheus + Grafana监控告警
Spring Boot Actuator应用健康检查

快速开始

环境要求

  • Node.js 20+
  • Java 17+ (推荐 Temurin)
  • PostgreSQL 14+
  • Redis 7+
  • Docker & Docker Compose (可选)

方式一:本地开发

bash
复制代码
# 1. 启动基础服务 (PostgreSQL + Redis) cd docker cp .env.example .env docker-compose up -d # 2. 启动后端 cd ../backend mvn spring-boot:run # 后端启动后 Flyway 会自动执行数据库迁移 # 3. 启动前端 cd ../frontend npm install npm run dev

方式二:Docker 全容器化

bash
复制代码
# 在 docker 目录下启动所有服务 cd docker docker-compose -f docker-compose.yml -f ../docker-compose.override.yml up -d

核心功能

3D 可视化引擎

  • Three.js 3D 地球渲染:PBR 材质、程序化纹理、实时云图覆盖 (Matt Eason's Cloud Service)
  • GPU 实例化渲染:30,000+ 卫星对象同时渲染,帧率保持 ≥30fps
  • 倾角着色系统:按赤道/低/中/高/逆行倾角带使用不同颜色区分
  • 星空背景:12,000 星点粒子系统 + 3,000 科技感动态粒子背景
  • 多渲染风格:Classic / Map / 4K 切换
  • 时间控制系统:暂停/加速/回溯,模拟时间推进
  • 大气光晕:双层 ShaderMaterial 大气散射效果
  • 经纬网格与赤道环:辅助空间定位
  • 沉浸式模式:全屏无装饰浏览

卫星数据管理

  • CelesTrak 数据同步:XXL-JOB 定时任务自动拉取 TLE 数据,增量/全量两种模式
  • DB 优先加载策略:首次从 CelesTrak 获取后存入数据库,后续直接从数据库加载
  • 六大分类加载:特殊兴趣、气象与地球资源、通信、北斗、导航、科学卫星
  • 实时 SGP4 传播:Web Worker 分片计算(satellite.js v5),不阻塞主线程
  • 卫星搜索与筛选:按名称/NORAD ID 搜索,按轨道类型过滤
  • 卫星分类筛选:按倾角带过滤卫星显示

专业工具链

工具说明路由
TLE 解析器两行根数解析与轨道参数计算/tools/tle
过境预测基于用户经纬度的卫星过境时间预测/tools/transit
碰撞预警卫星间接近事件预警分析/tools/collision
摄影炸弹预测卫星过境拍摄窗口/tools/photo
坐标转换多坐标系之间的转换工具/tools/coord
多源轨道可视化SP3/RINEX/OEM 文件上传与多源轨道对比/multi-source-orbit

数据同步机制

系统采用 DB 优先 + CelesTrak 回退 的数据加载策略,具体流程详见上方「核心业务流程 → 卫星数据同步与加载流程」Mermaid 流程图。

关键策略要点:

  • 同步间隔控制sync_tracking 表记录每分组最后同步时间,6 小时间隔内不再重复拉取
  • DB 优先:首次加载时后端从 CelesTrak 拉取 → 写入数据库 → 后续直接从 DB 加载
  • 定时增量同步:XXL-JOB 每天凌晨 02:00 自动增量同步,跳过未过期分组
  • 三级降级:后端同步 → 数据库加载 → 前端直连 CelesTrak(后端不可用时自动降级)

关键代码示例

1. Three.js 3D 引擎 — GPU 实例化卫星渲染

核心渲染引擎使用 THREE.InstancedMesh 实现数万颗卫星的高效渲染,按倾角带分组着色。

typescript
复制代码
// frontend/src/composables/useThreeScene.ts (简化) // 创建 GPU 实例化卫星(按倾角带分组) for (const [bandKey, band] of Object.entries(bands)) { // 可见卫星点 const visibleGeo = new THREE.CircleGeometry(0.01, 16) const visibleMat = new THREE.MeshBasicMaterial({ color: band.color, side: THREE.DoubleSide }) const visibleInstanced = new THREE.InstancedMesh(visibleGeo, visibleMat, typeCount) // 不可见的检测网格(用于射线拾取) const hitGeo = new THREE.SphereGeometry(0.04, 8, 8) const hitMat = new THREE.MeshBasicMaterial({ visible: false }) const hitInstanced = new THREE.InstancedMesh(hitGeo, hitMat, typeCount) const dummy = new THREE.Object3D() for (let i = 0; i < typeCount; i++) { // 根据轨道参数计算3D坐标 const x = alt * (Math.cos(ra) * Math.cos(ma) - Math.sin(ra) * Math.sin(ma) * Math.cos(inc)) const y = alt * Math.sin(ma) * Math.sin(inc) const z = alt * (Math.sin(ra) * Math.cos(ma) + Math.cos(ra) * Math.sin(ma) * Math.cos(inc)) dummy.position.set(x, y, z) dummy.updateMatrix() visibleInstanced.setMatrixAt(i, dummy.matrix) hitInstanced.setMatrixAt(i, dummy.matrix) } scene.add(visibleInstanced) scene.add(hitInstanced) }

2. 大气散射 Shader — 边缘光晕效果

使用自定义 ShaderMaterial 实现菲涅尔效应的大气光晕,增强视觉真实感。

glsl
复制代码
// vertexShader varying vec3 vNormal; varying vec3 vWorldPos; void main() { vec4 worldPos = modelMatrix * vec4(position, 1.0); vWorldPos = worldPos.xyz; vNormal = normalize(mat3(modelMatrix) * normal); gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } // fragmentShader varying vec3 vNormal; varying vec3 vWorldPos; uniform vec3 uSunDir; void main() { vec3 viewDir = normalize(cameraPosition - vWorldPos); vec3 normal = normalize(vNormal); float fresnel = 1.0 - abs(dot(viewDir, normal)); fresnel = pow(fresnel, 3.0); float sunFac = dot(normal, normalize(uSunDir)) * 0.5 + 0.5; vec3 glowColor = mix(vec3(0.2, 0.5, 1.0), vec3(0.1, 0.7, 1.0), fresnel); float alpha = fresnel * 0.5 * (0.3 + sunFac * 0.7); gl_FragColor = vec4(glowColor, alpha); }

3. CelesTrak TLE 数据服务 — 多分组拉取与解析

支持从多个 CelesTrak 分组拉取 TLE 数据,去重后提取轨道参数供 SGP4 计算。

typescript
复制代码
// frontend/src/services/satelliteService.ts (简化) export async function fetchAllSatellites(): Promise<SatelliteBasic[]> { const groups = ['active', 'stations', 'visual', 'weather', 'starlink', 'oneweb', 'gps', 'beidou', 'galileo', 'cubesat', 'geo'] const results: SatelliteBasic[] = [] const seenNoradIds = new Set<number>() for (const group of groups) { const records = await fetchTleData(group) for (const sat of records.map(extractSatInfo)) { if (!seenNoradIds.has(sat.noradId)) { seenNoradIds.add(sat.noradId) results.push(sat) } } } return results } // 从 TLE 行解析轨道参数 export function extractSatInfo(record: TleRecord): SatelliteBasic { return { noradId: parseInt(record.noradId), name: record.name, inclination: parseFloat(record.line2.substring(8, 16)), // 轨道倾角 raan: parseFloat(record.line2.substring(17, 25)), // 升交点赤经 eccentricity: parseFloat('0.' + record.line2.substring(26, 33)), // 偏心率 argPerigee: parseFloat(record.line2.substring(34, 42)), // 近地点幅角 meanAnomaly: parseFloat(record.line2.substring(43, 51)), // 平近点角 meanMotion: parseFloat(record.line2.substring(52, 63)), // 每天圈数 // ... 更多参数 } }

页面路由一览

路径页面描述
/VisualizerView3D 可视化主视图
/loginLoginView用户登录
/registerRegisterView用户注册
/dashboardDashboardView数据仪表盘(需认证)
/constellationsConstellationListView星座列表
/constellations/:idConstellationDetailView星座详情
/toolsToolView专业工具入口
/tools/collisionCollisionWarningView碰撞预警
/tools/transitTransitPredictionView过境预测
/tools/tleTleParserViewTLE 解析器
/tools/photoPhotoBombView摄影炸弹
/tools/coordCoordConvertView坐标转换
/multi-source-orbitMultiSourceOrbitView多源数据轨道可视化
/settingsUserSettingsView用户设置(需认证)
/admin/usersAdminUsersView用户管理(需认证)
/infoInfoView关于项目
/creditsCreditsView致谢名单

API 概览

认证接口 (/api/auth)

端点方法说明
/auth/loginPOST登录 (返回 JWT)
/auth/registerPOST注册
/auth/refreshPOST刷新令牌
/auth/meGET当前用户信息及权限

受保护接口 (/api/satellites, /api/user, /api/tools, /api/orbit)

需携带 Authorization: Bearer <token> 头访问。

用户接口 (/api/user)

端点说明
/user/preferences用户偏好设置 (GET/PUT)
/user/bookmarks卫星书签管理 (GET/POST/DELETE)
/user/profile个人资料 (GET/PUT)
/user/admin/*管理员用户管理接口

工具接口 (/api/tools)

端点说明
/tools/collisions碰撞事件列表 (分页)
/tools/collisions/satellite/{noradId}指定卫星碰撞事件
/tools/pass-predictor过境预测计算

多源轨道接口 (/api/orbit)

端点说明
/orbit/all预置模拟轨道列表
/orbit/kepler开普勒轨道生成
/orbit/state_vector_custom自定义状态向量生成
/orbit/determineIOD 轨道确定
/orbit/upload/sp3SP3 文件上传解析
/orbit/upload/rinexRINEX 文件上传解析
/orbit/upload/tleTLE 文本上传解析

Docker 部署

基础设施

yaml
复制代码
# docker-compose.yml (核心) services: postgres: # PostgreSQL 14, 端口 5432 redis: # Redis 7, 端口 6379

构建镜像

bash
复制代码
# 后端 docker build -t dtspacemap-backend ./backend # 前端 (Nginx 静态服务) docker build -t dtspacemap-frontend ./frontend

CI/CD (GitHub Actions)

流水线包含三个阶段:

  1. Backend Build & Test:JDK 17 + Maven 编译和测试
  2. Frontend Build & Lint:Node.js 20 + ESLint 检查 + TypeScript 编译
  3. Build Docker Images:main 分支合并后自动构建镜像

开发规范

  • Git 提交:遵循 Conventional Commits (feat:, fix:, refactor:)
  • 代码风格:前端 ESLint + Prettier,后端遵循阿里 Java 规范
  • API 设计:RESTful 规范,统一 Result<T> 响应格式
  • 数据库变更:通过 Flyway 迁移脚本管理,禁止手动修改
0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
czheng
下载 APP