405 lines
11 KiB
Markdown
405 lines
11 KiB
Markdown
# 天体轨道生成系统文档
|
||
|
||
**版本**: 1.0
|
||
**最后更新**: 2025-12-10
|
||
|
||
---
|
||
|
||
## 概述
|
||
|
||
Cosmo项目中的行星和矮行星轨道采用**预计算**方式存储在数据库中,而不是实时计算。这样做的好处是:
|
||
|
||
1. **性能优化** - 前端无需实时计算复杂的椭圆轨道
|
||
2. **NASA数据** - 使用真实的NASA JPL Horizons API数据
|
||
3. **精确性** - 考虑了引力摄动等真实天文因素
|
||
|
||
---
|
||
|
||
## 轨道生成逻辑
|
||
|
||
### 1. 适用天体类型
|
||
|
||
轨道生成功能仅适用于以下两种天体类型:
|
||
|
||
- **行星 (planet)** - 八大行星
|
||
- **矮行星 (dwarf_planet)** - 冥王星、谷神星、阋神星等
|
||
|
||
### 2. 生成流程
|
||
|
||
#### 步骤1: 确定轨道参数
|
||
|
||
在 `backend/app/api/celestial_orbit.py` 中定义了硬编码的轨道周期:
|
||
|
||
```python
|
||
ORBITAL_PERIODS = {
|
||
# 行星 - 一个完整公转周期
|
||
"199": 88.0, # 水星 (88天)
|
||
"299": 224.7, # 金星
|
||
"399": 365.25, # 地球 (1年)
|
||
"499": 687.0, # 火星
|
||
"599": 4333.0, # 木星 (11.86年)
|
||
"699": 10759.0, # 土星 (29.46年)
|
||
"799": 30687.0, # 天王星 (84.01年)
|
||
"899": 60190.0, # 海王星 (164.79年)
|
||
|
||
# 矮行星 - 一个完整公转周期
|
||
"999": 90560.0, # 冥王星 (247.94年)
|
||
"2000001": 1680.0, # 谷神星 (4.6年)
|
||
"136199": 203500.0,# 阋神星 (557年)
|
||
"136108": 104000.0,# 妊神星 (285年)
|
||
"136472": 112897.0,# 鸟神星 (309年)
|
||
}
|
||
```
|
||
|
||
轨道颜色也是硬编码的:
|
||
|
||
```python
|
||
DEFAULT_COLORS = {
|
||
"199": "#8C7853", # 水星 - 棕色
|
||
"299": "#FFC649", # 金星 - 黄色
|
||
"399": "#4A90E2", # 地球 - 蓝色
|
||
"499": "#CD5C5C", # 火星 - 红色
|
||
# ... 其他天体
|
||
}
|
||
```
|
||
|
||
#### 步骤2: 计算采样点数量
|
||
|
||
采样策略(`orbit_service.py`):
|
||
|
||
```python
|
||
MIN_POINTS = 100 # 最少100个点,保证椭圆光滑
|
||
MAX_POINTS = 1000 # 最多1000个点,避免数据过大
|
||
|
||
if period_days < 3650: # < 10年
|
||
# 行星:约每天1个点,最少100个
|
||
num_points = max(MIN_POINTS, min(int(period_days), 365))
|
||
else: # >= 10年
|
||
# 外行星和矮行星:每月采样一次
|
||
num_points = min(int(period_days / 30), MAX_POINTS)
|
||
```
|
||
|
||
**示例**:
|
||
- 地球 (365.25天) → 365个采样点
|
||
- 冥王星 (90560天 ≈ 248年) → 1000个采样点(每90天一个)
|
||
|
||
#### 步骤3: 查询NASA Horizons API
|
||
|
||
调用NASA JPL Horizons API获取真实轨道数据:
|
||
|
||
```python
|
||
positions = await horizons_service.get_body_positions(
|
||
body_id=body_id,
|
||
start_time=start_time,
|
||
end_time=end_time,
|
||
step=f"{step_days}d"
|
||
)
|
||
```
|
||
|
||
**特殊处理**:
|
||
- 短周期天体(<150年):从当前时间开始
|
||
- 长周期天体(≥150年):从1900年开始(避免超出NASA数据范围)
|
||
|
||
#### 步骤4: 存储到数据库
|
||
|
||
将轨道点存储到 `orbits` 表:
|
||
|
||
```sql
|
||
CREATE TABLE orbits (
|
||
body_id VARCHAR(50) PRIMARY KEY,
|
||
points JSONB NOT NULL, -- [{"x": 1.0, "y": 0.5, "z": 0.0}, ...]
|
||
num_points INTEGER, -- 点的数量
|
||
period_days DOUBLE PRECISION, -- 轨道周期(天)
|
||
color VARCHAR(20), -- 轨道线颜色
|
||
created_at TIMESTAMP,
|
||
updated_at TIMESTAMP
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 当前问题与解决方案
|
||
|
||
### 问题1: 新增天体后轨道不自动生成
|
||
|
||
**现状**:管理员在天体管理界面新增矮行星后,需要手动执行以下步骤:
|
||
|
||
1. 到"NASA数据下载"页面
|
||
2. 点击"生成轨道"按钮
|
||
3. 系统遍历所有行星/矮行星,调用NASA API生成轨道
|
||
|
||
**问题**:
|
||
- 流程繁琐,容易遗忘
|
||
- 无法针对单个天体生成
|
||
- 新增天体时轨道参数(周期、颜色)是硬编码的
|
||
|
||
### 问题2: 轨道参数硬编码
|
||
|
||
**现状**:轨道周期和颜色定义在 `celestial_orbit.py` 中,无法灵活配置。
|
||
|
||
**问题**:
|
||
- 新增矮行星必须修改代码添加周期和颜色
|
||
- 无法为自定义天体生成轨道
|
||
- 缺乏数据库层面的配置灵活性
|
||
|
||
---
|
||
|
||
## 解决方案设计
|
||
|
||
### 方案A: 自动触发轨道生成(推荐)
|
||
|
||
**实现思路**:
|
||
|
||
1. **数据库扩展** - 在 `celestial_bodies` 表添加轨道参数字段:
|
||
```sql
|
||
ALTER TABLE celestial_bodies ADD COLUMN orbit_period_days DOUBLE PRECISION;
|
||
ALTER TABLE celestial_bodies ADD COLUMN orbit_color VARCHAR(20);
|
||
ALTER TABLE celestial_bodies ADD COLUMN auto_generate_orbit BOOLEAN DEFAULT FALSE;
|
||
```
|
||
|
||
2. **创建天体时自动生成** - 修改 `POST /celestial` API:
|
||
```python
|
||
@router.post("")
|
||
async def create_celestial_body(body_data, db):
|
||
# 1. 创建天体
|
||
new_body = await celestial_body_service.create_body(body_data.dict(), db)
|
||
|
||
# 2. 如果是行星/矮行星且设置了轨道参数,自动生成轨道
|
||
if new_body.type in ["planet", "dwarf_planet"] and new_body.orbit_period_days:
|
||
await orbit_service.generate_orbit(
|
||
body_id=new_body.id,
|
||
body_name=new_body.name_zh or new_body.name,
|
||
period_days=new_body.orbit_period_days,
|
||
color=new_body.orbit_color or "#CCCCCC",
|
||
session=db,
|
||
horizons_service=horizons_service
|
||
)
|
||
```
|
||
|
||
3. **前端界面调整** - 在天体新增表单中添加:
|
||
- 轨道周期输入框(天)
|
||
- 轨道颜色选择器
|
||
- "自动生成轨道"复选框
|
||
|
||
**优点**:
|
||
- ✅ 无需手动操作,完全自动化
|
||
- ✅ 轨道参数可配置
|
||
- ✅ 新增天体立即可用
|
||
|
||
**缺点**:
|
||
- ⚠️ 创建天体时可能耗时较长(等待NASA API响应)
|
||
- ⚠️ 需要修改数据库结构
|
||
|
||
### 方案B: 异步后台生成
|
||
|
||
**实现思路**:
|
||
|
||
1. 创建天体时立即返回,在后台异步生成轨道
|
||
2. 使用Celery或FastAPI BackgroundTasks
|
||
3. 前端显示"轨道生成中..."状态
|
||
|
||
**优点**:
|
||
- ✅ 用户体验好,不会阻塞
|
||
- ✅ 可以批量生成
|
||
|
||
**缺点**:
|
||
- ⚠️ 需要引入任务队列(增加系统复杂度)
|
||
- ⚠️ 需要轮询检查生成状态
|
||
|
||
### 方案C: 手动触发但优化流程(最简单)
|
||
|
||
**实现思路**:
|
||
|
||
1. 在天体列表页添加"生成轨道"按钮(每行一个)
|
||
2. 点击后调用 `POST /celestial/admin/orbits/generate?body_ids={id}`
|
||
3. 使用天体的 `extra_data` 字段存储轨道参数
|
||
|
||
**优点**:
|
||
- ✅ 实现简单,无需修改数据库
|
||
- ✅ 灵活可控
|
||
|
||
**缺点**:
|
||
- ⚠️ 仍需手动操作
|
||
|
||
---
|
||
|
||
## 推荐实施步骤
|
||
|
||
### Phase 1: 快速修复(方案C)
|
||
|
||
1. **修改 `CelestialBodyCreate` 模型**,允许在 `extra_data` 中传入:
|
||
```json
|
||
{
|
||
"orbit_period_days": 90560.0,
|
||
"orbit_color": "#8B7355"
|
||
}
|
||
```
|
||
|
||
2. **修改轨道生成API**,优先从 `extra_data` 读取参数:
|
||
```python
|
||
# 优先从天体的extra_data读取,其次从硬编码字典读取
|
||
extra_data = body.extra_data or {}
|
||
period = extra_data.get("orbit_period_days") or ORBITAL_PERIODS.get(body.id)
|
||
color = extra_data.get("orbit_color") or DEFAULT_COLORS.get(body.id, "#CCCCCC")
|
||
```
|
||
|
||
3. **前端添加按钮** - 在天体管理列表每行添加"生成轨道"操作按钮
|
||
|
||
### Phase 2: 自动化(方案A)
|
||
|
||
1. 添加数据库迁移,新增轨道参数字段
|
||
2. 修改创建天体API,支持自动生成
|
||
3. 前端表单添加轨道参数输入
|
||
|
||
---
|
||
|
||
## API接口文档
|
||
|
||
### 生成轨道
|
||
|
||
**端点**: `POST /celestial/admin/orbits/generate`
|
||
|
||
**查询参数**:
|
||
- `body_ids` (可选) - 逗号分隔的天体ID列表,如 "999,2000001"
|
||
- 如果不提供,则为所有行星和矮行星生成轨道
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"message": "Generated 2 orbits (0 failed)",
|
||
"results": [
|
||
{
|
||
"body_id": "999",
|
||
"body_name": "冥王星",
|
||
"status": "success",
|
||
"num_points": 1000,
|
||
"period_days": 90560.0
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 获取轨道数据
|
||
|
||
**端点**: `GET /celestial/orbits`
|
||
|
||
**查询参数**:
|
||
- `body_type` (可选) - 过滤天体类型,如 "planet" 或 "dwarf_planet"
|
||
|
||
**响应示例**:
|
||
```json
|
||
{
|
||
"orbits": [
|
||
{
|
||
"body_id": "399",
|
||
"body_name": "地球",
|
||
"body_name_zh": "地球",
|
||
"points": [
|
||
{"x": 1.0, "y": 0.0, "z": 0.0},
|
||
{"x": 0.99, "y": 0.01, "z": 0.0},
|
||
...
|
||
],
|
||
"num_points": 365,
|
||
"period_days": 365.25,
|
||
"color": "#4A90E2",
|
||
"updated_at": "2025-12-10T10:30:00"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 删除轨道
|
||
|
||
**端点**: `DELETE /celestial/admin/orbits/{body_id}`
|
||
|
||
**响应**:
|
||
```json
|
||
{
|
||
"message": "Orbit for 999 deleted successfully"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 数据库结构
|
||
|
||
### orbits 表
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| body_id | VARCHAR(50) | 天体ID(主键,外键到celestial_bodies) |
|
||
| points | JSONB | 轨道点数组 [{"x", "y", "z"}, ...] |
|
||
| num_points | INTEGER | 轨道点数量 |
|
||
| period_days | DOUBLE PRECISION | 轨道周期(天) |
|
||
| color | VARCHAR(20) | 轨道线颜色(HEX) |
|
||
| created_at | TIMESTAMP | 创建时间 |
|
||
| updated_at | TIMESTAMP | 更新时间 |
|
||
|
||
**索引**:
|
||
- PRIMARY KEY: `body_id`
|
||
- FOREIGN KEY: `body_id` → `celestial_bodies.id` (ON DELETE CASCADE)
|
||
|
||
---
|
||
|
||
## 前端使用
|
||
|
||
### 获取并渲染轨道
|
||
|
||
```typescript
|
||
// 1. 获取轨道数据
|
||
const response = await request.get('/celestial/orbits?body_type=planet');
|
||
const orbits = response.data.orbits;
|
||
|
||
// 2. 渲染轨道线
|
||
orbits.forEach(orbit => {
|
||
const points = orbit.points.map(p => new Vector3(p.x, p.y, p.z));
|
||
const geometry = new BufferGeometry().setFromPoints(points);
|
||
const material = new LineBasicMaterial({ color: orbit.color });
|
||
const line = new Line(geometry, material);
|
||
scene.add(line);
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 常见问题
|
||
|
||
### Q1: 为什么不实时计算轨道?
|
||
|
||
**A**: 实时计算需要考虑多体引力、引力摄动等复杂因素,计算量大且不准确。预计算方式使用NASA真实数据,更准确且性能更好。
|
||
|
||
### Q2: 如何为新增的矮行星生成轨道?
|
||
|
||
**A**:
|
||
1. **短期方案**:在天体的 `extra_data` 中添加 `orbit_period_days` 和 `orbit_color`
|
||
2. **长期方案**:等待数据库迁移,使用独立字段存储轨道参数
|
||
|
||
### Q3: NASA Horizons API有哪些限制?
|
||
|
||
**A**:
|
||
- 时间范围:通常限制在1900-2200年之间
|
||
- 频率限制:建议每次查询间隔1秒
|
||
- 天体覆盖:只包含太阳系天体,不包括系外行星
|
||
|
||
### Q4: 轨道数据多久更新一次?
|
||
|
||
**A**: 理论上轨道是稳定的,无需频繁更新。建议:
|
||
- 行星:每年更新一次(考虑引力摄动)
|
||
- 矮行星:每5年更新一次
|
||
|
||
---
|
||
|
||
## 未来优化方向
|
||
|
||
1. **自动化轨道生成** - 创建天体时自动触发轨道生成
|
||
2. **轨道参数配置化** - 从数据库读取而非硬编码
|
||
3. **批量生成优化** - 并发调用NASA API,提升生成速度
|
||
4. **轨道缓存策略** - 避免重复生成相同天体的轨道
|
||
5. **支持更多天体** - 扩展到卫星、小行星等
|
||
|
||
---
|
||
|
||
**文档作者**: Claude Code AI
|
||
**版本历史**:
|
||
- v1.0 (2025-12-10) - 初始版本,基于现有代码分析
|