cosmo/ORBIT_GENERATION_SYSTEM.md

405 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 天体轨道生成系统文档
**版本**: 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. 使用CeleryFastAPI 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) - 初始版本,基于现有代码分析