Swap order in update_simulation() to check maneuvers before physics update.
This ensures triggers fire at the correct position instead of after the
spacecraft has moved past the trigger point.
Also fix test config to avoid interference between time-based and true
anomaly triggers.
Added user experience improvements:
- Keyboard shortcuts: ESC to cancel, ENTER to confirm
- Enhanced error messages with detailed descriptions
- Hohmann tab input validation
- Error message display in Hohmann tab
- Edge case handling for all input scenarios
- Clear error messages when tab switches
Keyboard shortcuts work for all dialog tabs and delete confirmation.
Added complete Hohmann transfer calculation and UI:
- Spacecraft, Transfer Parent, Current Body, Target Body selectors
- Calculate Transfer button with real-time calculation
- Results panel showing dv1, dv2, transfer time, semi-major axis
- Create Both Burns / Create Burn 1 Only buttons
- Auto-generated maneuver names with format 'Hohmann Burn N (Source→Target)'
- Proper field initialization and validation
Fixed body selector logic with separate current_body_index field.
Wrapped GuiDropdownBox calls in render_maneuver_create_tab() with validity checks:
- Direction dropdown: Only renders when craft_index is valid
- Trigger dropdown: Only renders when craft_index is valid
- Prevents accessing invalid array indices
- Makes UI more robust
Dropdowns now only appear when spacecraft is properly selected.
Added automatic name generation for new maneuvers:
- generate_maneuver_name() creates sensible names (e.g., 'Prograde #1', 'Retrograde @ ν=3.14 #2')
- Names based on burn direction, trigger type, and burn number
- User can still manually edit names if desired
- Validation now allows empty names (for auto-generation)
- Integrates with existing create_maneuver_from_dialog() workflow
Users can create maneuvers faster with auto-generated names, or override with custom names.
Fixed segfault at ui_renderer.cpp:503 by adding proper initialization:
- All ManeuverDialogState fields initialized in main()
- Dialog opening resets fields to safe defaults
- trigger_type_active, direction_active, delta_v now initialized to valid values
- name, error_message initialized to empty strings
- Preview and error flags initialized to false
Dialog now opens and runs without crashing.
Implemented complete Create tab workflow for maneuver management dialog:
- render_maneuver_create_tab() with all input widgets
- update_orbital_preview() using preview_burn_result()
- render_orbital_preview() for displaying burn results
- validate_maneuver_inputs() for input validation
- create_maneuver_from_dialog() using add_maneuver_to_simulation()
- update_maneuver_from_dialog() for editing existing maneuvers
- Dialog opens/closes from maneuver list button
- Real-time orbital preview with color-coded validation
All tests pass. Phase 1 (Foundation) and Phase 2 (Create Tab) complete.
Implement first 7 priority functions for maneuver UI controls:
- add_maneuver_to_simulation(): Add maneuvers dynamically
- remove_maneuver_by_index(): Remove maneuvers from simulation
- create_maneuver(): Helper to construct maneuver structs
- get_burn_direction_name(): Get descriptive strings for directions
- preview_burn_result(): Preview orbital elements after burn
- calculate_hohmann_transfer(): Calculate optimal two-burn transfer
- validate_burn_parameters(): Validate burn parameters
See docs/planning/maneuver_ui_controls.md for full implementation plan.
- Function was never called anywhere in the codebase
- Functionality now handled by propagate_orbital_elements() with proper Newton-Raphson iteration
- Removes dead code and simplifies the API
- Switch spacecraft and bodies from RK4 to analytical propagation using propagate_orbital_elements()
- Fixed three bugs in hyperbolic orbit propagation (formula errors and insufficient Newton-Raphson iterations)
- Add orbital element reconstruction after burns and SOI transitions
- Zero energy drift for circular, elliptical, parabolic, and hyperbolic orbits
- All 132 tests passing (240,294 assertions)
- Add solve_barker_equation() function using cubic formula: D + D³/3 = M
- Integrate Barker's equation into propagate_orbital_elements() for parabolic orbits
- Add comprehensive test suite (11 tests, 239 assertions) following TDD
- Use cbrt() for cube root (handles negative numbers properly)
- Parabolic propagation now uses exact analytical solution instead of iterative solver
- All 93 tests passing (239,872 assertions)
- Add 16 minimal comments documenting formulas in orbital_mechanics.cpp
- Fix parabolic test to use orbital_elements_to_cartesian() instead of manual velocity
- Tighten parabolic test tolerance from 1e10 to 1e3 (7 orders of magnitude)
- Reduce parabolic test error from 6.5% to machine precision
- Add near-parabolic detection for |1-e| < 0.01
- Use cosine/sine formulation with atan2() to preserve quadrant
- Avoid catastrophic cancellation in sqrt((1+e)/(1-e)) factor
- Clamp values to [-1,1] to handle precision issues
- Maintain original formula for well-behaved orbits
- Add PARABOLIC_TOLERANCE = 1e-3 constant for consistent detection
- Replace inconsistent thresholds (0.005, 0.98, 1.02) across 5 files
- Refactor orbital_elements_to_cartesian() to use semi-latus rectum as primary parameter
- Eliminate 3 separate code branches with unified formulas for all orbit types
- Improve numerical stability for parabolic and near-parabolic orbits
- Reduce code complexity: -23 lines net
- Convert 64 test assertions from Approx() to WithinAbs() in 2 new test files
- Add WithinAbs() testing guidelines to AGENTS.md
- Fix cartesian_to_orbital_elements(): eccentricity vector calculation,
true anomaly normalization, parabolic semi-latus rectum handling
- Add 2 new test files for edge cases and quadrature points
New modular API:
- solve_kepler_elliptical(M, e): Newton-Raphson for E - e·sin(E) = M
- solve_kepler_hyperbolic(M, e): Solver for H - e·sinh(H) = M
- eccentric_to_true_anomaly(E, e): Convert eccentric to true anomaly
- hyperbolic_to_true_anomaly(H, e): Convert hyperbolic to true anomaly
- mean_anomaly_to_true_anomaly(M, e): Unified wrapper (dispatches based on e)
Changes:
- Renamed solve_kepler_equation() → solve_kepler_elliptical() for clarity
- Extracted KEPLER_TOLERANCE and KEPLER_MAX_ITERATIONS constants
- Separated hyperbolic solver logic from combined function
- Fixed test_newton_raphson_convergence to verify Kepler's equation
(instead of incorrectly expecting E ≈ M for small e)
- Added TODO comment for future cartesian_to_orbital_elements refactoring
New validation function validate_true_anomaly_ranges() checks that
hyperbolic orbits (e > 1) have true anomalies within physically valid
range: |ν| < arccos(-1/e)
This prevents configs from specifying starting positions that would
cause negative radius values (1 + e·cos(ν) ≤ 0).
Bug: r_dot_e was incorrectly divided by mu instead of r_mag*e_mag,
causing cos_nu values of ~7.5e6 (far outside [-1,1]) which made acos() return NaN.
Fix: Calculate cos_nu correctly as r_dot_e/(r_mag*e_mag) and clamp
to [-1, 1] to handle floating-point precision errors.
This fixes all cartesian <-> orbital elements round-trip conversion tests.
Added 6 test files for Newton-Raphson solver and analytical propagation:
- test_cartesian_to_elements_basic.cpp: Tests state vector ↔ orbital elements conversion
- test_newton_raphson_convergence.cpp: Tests Newton-Raphson solver convergence behavior
- test_analytical_propagation_apsides.cpp: Tests propagation through orbital apsides
- test_analytical_propagation_timesteps.cpp: Tests propagation with various timesteps
- test_extreme_eccentricity.cpp: Tests near-parabolic and hyperbolic orbits
- test_precision_boundaries.cpp: Tests exact boundary value handling
Implemented core orbital mechanics functions:
- solve_kepler_equation(): Newton-Raphson solver with 1e-10 tolerance
- get_initial_trial_value(): Series expansion initial guess
- cartesian_to_orbital_elements(): State vectors to orbital elements conversion
- propagate_orbital_elements(): Analytical propagation using Kepler's equation
Updated test plan document with current progress and remaining tests.
Test status: 66 passed, 14 failed (out of 80 test cases)
- Failing tests are expected: implementation needs debugging
- Config validation issues fixed by adjusting orbital parameters
- Remove unconditional reset of ui_state.selected_craft_index in render_body_list_ui()
- Only reset ui_state.selected_craft_index to -1 when body is selected
- This prevents panel from disappearing in subsequent frames when spacecraft remains selected
- Ensure camera is always at least INITIAL_DISTANCE_RADIUS_MULTIPLIER (100x) away from target body's radius
- get_initial_camera_distance() returns max(average_children_distance, body_radius * 100) when children exist
- get_initial_camera_distance() returns body_radius * 100 when no children
- Prevents camera clipping when switching from Sun (large radius) to Earth (small radius) with close children
- Remove selected_craft_index from RenderState, move to UIState
- Camera now always targets bodies (directly selected or parent of selected spacecraft)
- UI handles all spacecraft selection logic
- Remove ~30 lines of duplicate/special-case code from renderer
- Update all renderer functions to single body-focused path
- Update UI rendering functions to use ui_state->selected_craft_index
- Add orbital element fields to OrbitTracker struct (inclination, RAAN, argument_of_periapsis)
- Create create_orbit_tracker_3d() for initializing with orbital elements
- Modify update_orbit_tracker() to use inverse rotation matrix for angle calculation
- Transform 3D position back to orbital plane before computing angle
- Update Molniya period test to use 3D tracker and relaxed tolerance (30 min)
- Remove remaining [!mayfail] tags
All 47 test cases now pass with 239,431 assertions