Replace per-frame propagation probe with analytical mean anomaly delta
In check_maneuver_trigger() (true-anomaly branch), eliminate the
propagate_orbital_elements() look-ahead probe that was called every
frame for pending maneuvers. Replace with direct analytical computation
of dt_needed from mean anomaly delta.
Benefits:
- Eliminates ~24k redundant Kepler solves per Hohmann transfer wait
period (DT=10s, 244k s wait time)
- More precise: no discretization error from single-step propagation
- Simpler logic: removed angle_between check, wraparound detection
- Removes dead angle_between() helper function
Elliptical orbits only — added TODO for parabolic/hyperbolic support.
All 154 tests pass (240,445 assertions).
### 2026-04-20: Eliminated Redundant Propagation in `check_maneuver_trigger()`
Replaced the per-frame propagation probe in `check_maneuver_trigger()` (true-anomaly branch) with a direct analytical calculation using mean anomaly delta.
**What changed:**
- Removed `propagate_orbital_elements()` call from `check_maneuver_trigger()` — eliminates ~24k redundant Kepler solves per Hohmann transfer wait period
- Removed dead `angle_between()` static helper
- Replaced the `angle_between`, `future_diff`, and `wraparound_crossing` checks with a cleaner `dt_needed <= 0.0` guard
- Added TODO comment noting elliptical-orbits-only limitation
**Impact:**
- Same correctness, fewer function calls, simpler logic
- All 154 tests pass (240,445 assertions)
- For a Hohmann transfer with ~244,000s wait time and DT=10s: ~24,400 fewer `propagate_orbital_elements()` calls
**Remaining:** See Issue 1 below — still has a TODO for parabolic/hyperbolic orbit support.
---
## Objective
Audit all call sites of `propagate_orbital_elements()` for spacecraft and trace the `update_simulation()` call chain through `execute_pending_maneuvers()` and `update_spacecraft_physics()` to identify inefficiencies and confusing branching.
@ -52,16 +73,20 @@ update_simulation()
### Issue 1: Redundant Propagation for True-Anomaly Triggers
**Location:** `src/maneuver.cpp`, line 147 in `check_maneuver_trigger()`
**Status:** RESOLVED — eliminated in favor of analytical mean anomaly delta calculation.
For every frame that a true-anomaly maneuver is pending, `propagate_orbital_elements()` is called as a "look-ahead" probe to determine if the target angle is approaching.
Previously, for every frame that a true-anomaly maneuver was pending, `propagate_orbital_elements()` was called as a "look-ahead" probe to determine if the target angle was approaching.
**Impact:** For a Hohmann transfer with a ~244,000s wait time and DT=10s, this results in ~24,400 redundant propagations — each one solving Kepler's equation — before the maneuver even fires. The spacecraft's orbit state is not modified, but the computational cost is paid every single frame.
**Resolution:** Replaced with direct analytical computation of `dt_needed` from mean anomaly delta. The analytical solution is more precise (no discretization error) and eliminates ~24k redundant Kepler solves per Hohmann transfer wait period at DT=10s.
**Remaining:** The current implementation only handles elliptical orbits. TODO comment added for parabolic (Barker's equation) and hyperbolic branches.
### Issue 2: Mixed Concerns in `execute_pending_maneuvers()`
@ -153,6 +178,8 @@ When no sub-step is needed, the maneuver path is: propagate → convert → burn
## Call Sites Summary
### Before fix (5 call sites)
| Location | Function | Context | dt value |
|----------|----------|---------|----------|
| `simulation.cpp:287` | `update_bodies_physics()` | Normal body propagation | `sim->dt` |
@ -161,4 +188,13 @@ When no sub-step is needed, the maneuver path is: propagate → convert → burn