cosmo/ORBIT_GENERATION_SYSTEM.md

11 KiB
Raw Blame History

天体轨道生成系统文档

版本: 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 中定义了硬编码的轨道周期:

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年)
}

轨道颜色也是硬编码的:

DEFAULT_COLORS = {
    "199": "#8C7853",  # 水星 - 棕色
    "299": "#FFC649",  # 金星 - 黄色
    "399": "#4A90E2",  # 地球 - 蓝色
    "499": "#CD5C5C",  # 火星 - 红色
    # ... 其他天体
}

步骤2: 计算采样点数量

采样策略(orbit_service.py

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获取真实轨道数据

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 表:

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 表添加轨道参数字段:

    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

    @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 中传入:

    {
      "orbit_period_days": 90560.0,
      "orbit_color": "#8B7355"
    }
    
  2. 修改轨道生成API,优先从 extra_data 读取参数:

    # 优先从天体的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"
  • 如果不提供,则为所有行星和矮行星生成轨道

响应示例:

{
  "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"

响应示例:

{
  "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}

响应:

{
  "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_idcelestial_bodies.id (ON DELETE CASCADE)

前端使用

获取并渲染轨道

// 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_daysorbit_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) - 初始版本,基于现有代码分析