cosmo/ORBIT_GENERATION_SYSTEM.md

405 lines
11 KiB
Markdown
Raw Normal View History

2025-12-10 08:49:16 +00:00
# 天体轨道生成系统文档
**版本**: 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) - 初始版本,基于现有代码分析