Extract large update_simulation function into focused helpers:
- update_bodies_physics() - Handle body RK4 and SOI transitions
- update_spacecraft_physics() - RK4 integration for spacecraft
- execute_pending_maneuvers() - Check triggers and execute burns
- compute_spacecraft_globals() - Global coords for spacecraft
Simplified update_simulation to call helpers sequentially:
1. Bodies physics
2. Bodies global coords
3. Spacecraft physics
4. Maneuver execution
5. Spacecraft global coords
6. Time step
Benefits:
- Single responsibility per function
- Cleaner, more readable code
- Easier to test individual components
- Net change: +96 lines (helper functions) -86 lines (removal)
All maneuver tests still passing.
Remove duplicate code blocks that were executing maneuvers twice.
Fix ensures correct update order:
1. Body RK4 updates
2. Body global coords
3. Spacecraft RK4 updates
4. Maneuver execution (once, with executed flag check)
5. Spacecraft global coords (from updated local_velocity)
This eliminates the redundant 'execute pending maneuvers' and 'compute spacecraft globals' blocks that were duplicated in the code.
Merge spacecraft management into simulation module:
- Move Spacecraft struct from maneuver.h to spacecraft.h
- Add spacecraft array to SimulationState (spacecraft, craft_count, max_craft)
- Remove separate SpacecraftState struct and related functions
- Update create_simulation() to require max_craft parameter
- Move spacecraft update logic into update_simulation()
- Make load_spacecraft_config() internal helper, called by load_system_config()
- Update all test files to use new API with 3-parameter create_simulation()
- Handle max_craft=0 case gracefully (no spacecraft allocation)
Test results: 26/27 passing (1 pre-existing SOI test unrelated to changes)
Add basic maneuvering API for spacecraft with impulsive delta-v burns in local frame:
- Add vec3_dot() function to physics module
- Create Spacecraft struct and SpacecraftState for separate spacecraft management
- Implement 6 burn directions: prograde, retrograde, normal, anti-normal, radial in/out
- Add RK4 propagation for spacecraft with update_spacecraft()
- Extend config loader to parse [[spacecraft]] TOML sections
- Add 6 test cases verifying burn physics and propagation stability
- Rename old mission_planning module to _old for future reference
Test results: 26/27 passing (1 pre-existing SOI test unrelated to changes)
- Deprecated initialize_spacecraft_leo() (now uses config-based init)
- Fixed retrograde velocity bug in simulation::calc_orbital_velocity()
- Fixed apply_transfer_burn() to correctly apply delta-v to local velocity
- Simplified test to validate burn formulas without long simulation
- Energy error: 0.011% (passes 5% tolerance)
- Net change: -20 lines
Updated docs to reflect that the spacecraft initialization bug has been
resolved by config validation.
docs/test_plan_invalid_parent_assignment.md:
- Changed status from "Implementation phase" to "Complete (Tests 1-3 resolved)"
- Updated bug diagnosis to show solution implemented
- Updated all test cases with actual results (Tests 1-3: ✅ PASS, Test 4: ❌ FAIL)
- Added implementation summary with commit references
- Updated test matrix to show actual results
- Updated future work section to reflect current status
docs/mission_planning.md:
- Marked FIXME as RESOLVED with solution details
- Updated spacecraft parameters to show corrected position
- Added note that delta-v issue remains pending
- Updated "position/velocity" line to reflect current implementation
Test Status:
- Test 1 (Earth→Spacecraft parent switch): ✅ RESOLVED
- Test 2 (Mass hierarchy): ✅ RESOLVED
- Test 3 (Config validation): ✅ RESOLVED
- Test 4 (Mutual SOI): ❌ PENDING (separate issue)
Added validation in config_loader to prevent bodies from starting too close
to their parent bodies (distance must be >= parent.radius + body.radius).
Changes:
- src/config_loader.cpp: Add parent-child distance validation before initialization
- tests/configs/earth_mars_simple.toml: Fix spacecraft position to LEO altitude
(Earth position + 6.571e6 m offset = 1.49606571e11 m)
- tests/test_invalid_parent_assignment.cpp: Update test 3 to use radius-based validation
- docs/mission_planning.md: Add TODO about spacecraft config pattern changes
Test results:
- Test 1: ✅ PASS (Earth no longer becomes child of spacecraft)
- Test 2: ✅ PASS (Mass hierarchy preserved)
- Test 3: ✅ PASS (Spacecraft at valid LEO position)
- Test 4: ❌ FAIL (mutual SOI bug, as expected)
This prevents the spacecraft initialization bug where Earth would incorrectly
become a child of the spacecraft due to distance=0.
Added comprehensive tests to capture parent-child relationship bugs:
- Test 1: Detect Earth becoming child of spacecraft (exact FIXME bug)
- Test 2: Validate mass hierarchy (massive bodies never have small parents)
- Test 3: Detect invalid config placeholder values (bodies at same position)
- Test 4: Mutual SOI edge case (similar-mass planets within SOI)
All tests fail as expected, documenting bugs for future fixes.
Tests 1-3 will pass after spacecraft separation fix.
Test 4 captures separate mutual SOI issue.
Files:
- docs/test_plan_invalid_parent_assignment.md (test plan)
- tests/test_invalid_parent_assignment.cpp (4 test cases)
- tests/configs/mutual_soi_close.toml (edge case config)
- Extract adaptive timestepping section from patched_conics_plan.md
- Add to mission_planning.md Future Work section (after Capture Burns)
- Problem: Fixed 60s timestep too coarse/fast for different orbital phases
- Solution: Adaptive timestep based on orbital period using Kepler's third law
- Implementation: calculate_adaptive_timestep() with 10s-600s clamping
- Delete obsolete patched_conics_plan.md (689 lines, superseded by implementation)
- Renumber sections 5-11 to accommodate new section 5
- Net reduction: ~645 lines of documentation
- Replace full function implementations with summaries
- Add references to actual source files for implementation details
- Replace full test code with test structure summary
- Replace full TOML config with config summary
- Reduced document from 744 to 459 lines (38% reduction)
- Improved maintainability: source code is now source of truth
- Old doc renamed to mission_planning.md.old for reference
- New doc (leospacecraft_impulse_burn_plan.md) renamed to mission_planning.md
- Updated version includes LEO spacecraft, impulse burn, test config, and future work
- Add spacecraft body to earth_mars_simple.toml config file
- Implement initialize_spacecraft_leo() to set circular LEO at 200km altitude
- Implement apply_transfer_burn() for Hohmann transfer impulse burn
- Implement calculate_phase_angle() for launch window verification
- Add comprehensive test case with SOI transition tracking
- Preserve debug printf statements from main branch investigation
- LEO initialization verified: position, velocity, energy all correct
- Issue identified: delta-v calculation doesn't account for spacecraft LEO phase
- Test completes 8/9 assertions (fails post-burn energy check)
- Session documented in docs/leospacecraft_impulse_burn_plan.md
Next: Fix apply_transfer_burn() to use vector-based delta-v instead of magnitude-based
Add completed camera follow features to implementation plan:
- Camera follow for selected bodies
- Distance preservation when switching bodies
- Proper orbital rotation using camera.up
Changes:
- Add previous_selected_body to RenderState
- Detect when selected_body_index changes
- Recalculate camera_offset when switching to new body
- Maintains same camera distance/orientation to new body
Technical details:
- Body selection change detected via previous_selected_body comparison
- When switching to new body:
* Calculate new body position
* Set camera target to new body
* Use existing camera_offset (maintains distance)
* Update camera.position = body_pos + offset
- Allows seamless transitions between bodies at same zoom level
Result: Camera maintains perspective when switching between
celestial bodies, no jarring distance changes.
Changes:
1. Remove all keyboard shortcuts (B, I, F keys)
2. UI panels always shown (body list, info, simulation info)
3. Selecting a body automatically enables camera follow
4. render_info() now uses GuiWindowBox style matching other UI
UI improvements:
- render_info() now uses GuiWindowBox for consistent styling
- Positioned at bottom-left with smaller window (200x280)
- Window close buttons disabled (panels always shown)
- Updated help text to reflect new workflow
User experience:
- Simpler interaction - just select body from list to follow it
- All information always visible
- Consistent UI styling across all panels
Fixes:
1. Camera now orbits horizontally (not vertically)
2. Uses camera.up instead of hardcoded global up vector
Technical changes:
- Remove hardcoded global up vector
- Use render_state->camera.up for rotation axis
- Rotate forward vector around camera's up vector
- This creates proper horizontal orbit around target
Rotation formula:
new_forward = forward * cos(angle) + cross(up, forward) * sin(angle)
Result: Camera orbits horizontally around target at any
camera position, using the camera's own up vector
for proper orientation-aware rotation.
Problems fixed:
1. Camera now maintains fixed distance to followed body
2. Camera uses proper up vector and cross products for rotation
Technical changes:
- Added camera_offset and was_following_body to RenderState
- Store offset when follow is first enabled
- Update camera position = body_pos + offset each frame
- Use cross products for proper orbital camera rotation:
- Calculate right vector from up x forward
- Rotate forward vector around right axis
- Update camera offset after each movement
- Zoom controls also update offset when following
Result: Camera maintains consistent perspective and distance
while tracking moving celestial bodies.
Features:
- Add camera_follow_body flag to RenderState
- Update update_camera() to follow selected body when enabled
- F key toggles camera follow (requires body selected)
- Camera still rotates and zooms around followed body
- Removed old focus_camera() function (superseded by new implementation)
- Updated help text to show F key for camera follow toggle
Technical details:
- Camera target updates to body position each frame when following
- Existing rotation/zoom controls work relative to new target position
- Maintains orbital camera control pattern
Issue: GuiListView() always returns 0 (known raygui bug), causing
body selection to never work.
Fix:
- Added body_list_scroll and body_list_active to RenderState for persistence
- Check body_list_active parameter changes instead of return value
- Initialize active state to -1 in main.cpp
Reference: https://github.com/raysan5/raygui/issues/448
- Mark all UI implementation phases as completed in ui_implementation_plan.md
- Add UI body selection to completed items in implementation_plan.md
- Move ui_implementation_summary.md to docs/session_summaries/ for better organization