1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//! Mapping from a gravity source to its frame-tree nodes.
//!
//! Lifted out of `astrodyn_runner::simulation::types` (issue #71) so both
//! `astrodyn_runner` and ECS adapters (the `astrodyn_bevy` root crate) can build
//! source frames against a shared structure. Lives at the orchestration
//! layer (`astrodyn`) — `astrodyn_runner` is a peer consumer of `astrodyn`,
//! not a layer above it (CLAUDE.md three-layer rule).
use FrameId;
/// Maps a gravity source to its frame tree nodes.
///
/// Every gravity source has an inertial frame; sources with a planet rotation
/// model also have a planet-fixed (pfix) child frame. The orchestration helpers
/// in [`crate::frame_orchestration`] and [`crate::source_state`] take a
/// `&[SourceFrameIds]` slice keyed by the same source-index ordering the
/// caller uses for `GravityControls<usize>`.
///
/// Both `astrodyn_runner` and `astrodyn_bevy` always allocate a *distinct*
/// inertial frame node for every gravity source (matching JEOD's
/// `BasePlanet { inertial, pfix }` canonical structure — see
/// `models/environment/planet/include/base_planet.hh:109,121`). For sources
/// at the heliocentric origin (the central body), the inertial frame node
/// is a child of root with identity rotation and zero position — the
/// structural separation is preserved even when the inertial frame is
/// numerically equivalent to root. `JEOD_INV: RF.13` (PR #566) guarantees
/// that composition walks through such identity intermediate frames
/// preserve f64 bits, so the structural alignment between runner and Bevy
/// is bit-safe.