14 KiB
Orbital Mechanics Simulation - Technical Reference
Overview
3D orbital mechanics simulation using 2-body gravitational model with sphere of influence (SOI) transitions. Built with C-style C++ and raylib.
Technical Constraints
- C-style C++ only: structs and functions, no classes or templates
- RK4 (Runge-Kutta 4th order) integration for physics
- Simple rotations (quaternions deferred)
- raylib for 3D visualization
- Single root body systems only (parent_index = -1 for exactly one body)
Core Data Structures
Vec3 (physics.h)
struct Vec3 {
double x, y, z;
};
CelestialBody (simulation.h)
struct CelestialBody {
char name[64];
double mass; // kg
double radius; // meters
Vec3 local_position; // position relative to parent (meters)
Vec3 local_velocity; // velocity relative to parent (m/s)
Vec3 position; // global position (meters from origin)
Vec3 velocity; // global velocity (m/s)
double soi_radius; // sphere of influence radius (meters)
int parent_index; // index of gravitational parent (-1 for root)
float color[3]; // RGB for rendering
double eccentricity; // orbital eccentricity (0 = circular)
double semi_major_axis; // meters
};
SimulationState (simulation.h)
struct SimulationState {
CelestialBody* bodies;
int body_count;
int max_bodies;
double time; // simulation time (seconds)
double dt; // time step (seconds)
};
RenderState (renderer.h)
struct RenderState {
Camera3D camera;
double distance_scale; // Scale factor for distances
double size_scale; // Scale factor for body sizes
bool show_info; // Display simulation info
};
OrbitalElements (simulation.h)
struct OrbitalElements {
double time_days;
double semi_major_axis_au;
double eccentricity;
double specific_energy;
double distance_to_sun_au;
double distance_to_ref_body_au;
double velocity_magnitude;
};
AccelerationContext (physics.h)
struct AccelerationContext {
SimulationState* sim;
CelestialBody* current_body;
int body_index;
};
OrbitalMetrics (test_utilities.h)
struct OrbitalMetrics {
double kinetic_energy;
double potential_energy;
double total_energy;
double orbital_radius;
double velocity_magnitude;
double angular_position;
};
OrbitTracker (test_utilities.h)
struct OrbitTracker {
double initial_angle;
double previous_angle;
int quadrant_transitions;
bool orbit_completed;
double time_at_completion;
int body_index;
double min_time_days;
};
Module Overview
Physics (physics.cpp/h)
Vector math and gravity calculations. RK4 (Runge-Kutta 4th order) integration with rk4_step(). Physics module is independent of simulation structures and accepts direct parameters for improved modularity.
Key functions:
rk4_step(Vec3* position, Vec3* velocity, double dt, double body_mass, double parent_mass)- RK4 integration using position/velocity pointersevaluate_acceleration(Vec3 relative_pos, double body_mass, double parent_mass)- computes gravitational acceleration from parent
Simulation (simulation.cpp/h)
Simulation state management and updates. SOI detection using Hill sphere: r_soi = a * (m/M)^(2/5).
Key functions:
find_dominant_body()- determines which body has gravitational dominanceupdate_soi()- calculates sphere of influence radius using Hill sphereupdate_simulation()- runs one physics step: finds dominant parent, calculates gravity, applies RK4 integrationinitialize_local_coordinates()- converts global to local coordinates on loadcompute_global_coordinates()- converts local to global coordinates after update- Dynamic parent switching when bodies cross SOI boundaries (with hysteresis)
Update Order:
- Root bodies updated first (in their own frame = global)
- Global coordinates computed for roots
- Child bodies updated in parent's local frame
- Global coordinates computed for all children
Config Loader (config_loader.cpp/h)
TOML-based config parser using tomlc17 library. Auto-calculates circular orbit velocities and SOI radii.
Key functions:
parse_toml_body()- parses individual body entriescalculate_initial_velocities()- sets circular orbit velocities using vis-viva equationcalculate_soi_radii()- computes sphere of influence for all bodies
Config format details:
- TOML array of tables:
[[bodies]] - Comments start with
# parent_index = -1indicates root body (star)- Supports nested orbits (planets with moons)
Config format (TOML):
[[bodies]]
name = "Sun"
mass = 1.989e30
radius = 6.96e8
position = { x = 0.0, y = 0.0, z = 0.0 }
parent_index = -1
color = { r = 1.0, g = 1.0, b = 0.0 }
eccentricity = 0.0
semi_major_axis = 0.0
[[bodies]]
name = "Earth"
mass = 5.972e24
radius = 6.371e6
position = { x = 1.496e11, y = 0.0, z = 0.0 }
parent_index = 0
color = { r = 0.0, g = 0.5, b = 1.0 }
eccentricity = 0.0
semi_major_axis = 1.496e11
Renderer (renderer.cpp/h)
Raylib 3D visualization with logarithmic distance scaling and size scaling for visibility.
Orbit rendering:
- Elliptical orbits: e < 0.98
- Parabolic orbits: 0.98 ≤ e ≤ 1.02 (uses escape trajectory formula)
- Hyperbolic orbits: e > 1.02 (shows asymptotic behavior)
render_parabolic_orbit()renders escape paths with true anomaly range: -π0.95 to π0.95
Test Utilities (test_utilities.cpp/h)
Test helper functions for orbital mechanics validation.
Key functions:
calculate_kinetic_energy()- computes kinetic energy of a bodycalculate_potential_energy_pair()- computes gravitational potential energy between two bodiescalculate_system_total_energy()- sums total energy of entire systemcalculate_orbital_metrics()- returns comprehensive orbital state metricscreate_orbit_tracker()- initializes orbit completion trackingupdate_orbit_tracker()- tracks orbital progress and detects completioncompare_double()/compare_vec3()- floating-point comparison with tolerance
Local Coordinate Frames (simulation.cpp/h)
Hierarchical coordinate system for improved numerical precision in nested orbits.
Key functions:
initialize_local_coordinates()- initializes local frame positions/velocities from global coordinatescompute_global_coordinates()- computes global positions/velocities from local frames
Benefits:
- Eliminates large offsets in floating-point calculations (moon at 3.8×10⁸ m instead of 1.5×10¹¹ m)
- Isolates moon orbits from planetary perturbations
- Maintains full floating-point precision for small orbital changes
- Improved Earth-Moon orbital stability (20% drift → stable)
Implementation Details:
- Dual coordinate storage: both local and global coordinates maintained
- Parent bodies treated as origin in child's reference frame during integration
- RK4 integration operates on local coordinates
- Global coordinates computed after each physics step for rendering and SOI checks
Main Program (main.cpp)
GUI-only application with interactive 3D visualization.
- Initializes simulation with MAX_BODIES=100, TIME_STEP=60 seconds
- Runs 100 physics steps per frame (adjustable with speed multiplier)
- Game loop: input handling → camera update → physics update (if not paused) → rendering
- Supports speed multiplier (2x/0.5x per keypress, min 0.125x)
- Default config:
tests/configs/solar_system.toml
Controls:
- Arrow keys: Rotate and zoom camera
- Space: Pause/Resume
- +/-: Speed up/slow down simulation
- I: Toggle info display
- ESC: Quit
Build System
Makefile Targets
make- Build raylib (first time) and compile sources toorbit_simmake rebuild- Clean and rebuildmake clean- Remove build artifactsmake clean-all- Clean everything including raylibmake run- Build and run the simulationmake test- Run full automated test suitemake test-build- Build test executable
Dependencies
- g++ (C++14)
- raylib (built automatically from
ext/raylib/src) - tomlc17 (included in
ext/tomlc17/src) - Catch2 (for testing)
- libX11, libGL, libpthread (system libraries)
Test Infrastructure
- Framework: Catch2 for unit testing
- Test Configs:
tests/configs/contains test scenariossolar_system.toml- Full solar system with moonsearth_circular.toml,mars_circular.toml- Simple orbital testsparabolic_comet.toml- Parabolic orbit (e=1.0)hyperbolic_comet.toml- Hyperbolic orbit (e>1.0)soi_transition.toml- SOI crossing test (3-body system)
- Test Files:
test_energy.cpp- Energy conservation validationtest_moon_orbits.cpp- Moon orbital stability teststest_orbital_period.cpp- Orbital period verificationtest_parabolic_orbit.cpp- Parabolic orbit teststest_hyperbolic_orbit.cpp- Hyperbolic orbit teststest_soi_transition.cpp- SOI transition validation
Orbit Types
Elliptical Orbits (0 ≤ e < 1)
- Standard planetary and moon orbits
- Eccentricity e = 0 (circular) to e < 1 (elliptical)
- Total energy is negative (bound to parent)
- Velocity follows vis-viva equation:
v² = GM(2/r - 1/a)
Parabolic Orbits (e = 1)
- Escape trajectories with exactly escape velocity
- Total energy is zero (marginally unbound)
- Escape velocity:
v² = 2GM/r - Rendered using true anomaly range: -π0.95 to π0.95
- Used for comets on escape trajectories
Hyperbolic Orbits (e > 1)
- Fast escape trajectories exceeding escape velocity
- Total energy is positive (unbound)
- Asymptotic velocity:
v∞ = √(2GM/|a|)where a < 0 - Shows open curve with asymptotic behavior
- Used for high-speed comets and interstellar objects
Data Flow
Initialization Sequence
- Configuration file →
load_system_config()→ populatesSimulationState calculate_initial_velocities()→ sets circular orbit velocities for all bodiescalculate_soi_radii()→ computes sphere of influence for each body
Main Simulation Loop
update_simulation()→ for each body:find_dominant_body()→ determine gravitational parent based on SOIevaluate_acceleration()→ compute gravitational force from parentrk4_step()→ update position/velocity using Runge-Kutta 4th order
render_simulation()→ for each body:scale_position()→ convert to render coordinates using logarithmic scalingscale_radius()→ convert to render size using exponential scalingrender_body()→ draw sphere with color
SOI Transition Mechanics
- Bodies dynamically switch gravitational parents when crossing SOI boundaries
- Uses 0.5x distance hysteresis to prevent oscillation between parents
find_dominant_body()checks all bodies and selects most dominant influence
Implementation Status
✅ Completed
- Phase 1-4: Core physics, simulation, config loading, and rendering
- Raylib integration with 3D camera
- Distance and size scaling for visualization
- TOML config file system with solar system configs (includes Sun + 8 planets + 6 moons)
- RK4 (Runge-Kutta 4th order) integration for improved accuracy
- Time scaling controls (speed up/slow down simulation)
- Pause/resume functionality
- Orbital elements calculation
- Hierarchical coordinate frames (local + global storage)
- Parent-first update order for stability
- Parabolic orbit support (e=1.0)
- Hyperbolic orbit support (e>1.0)
- Physics module refactoring (parameter-based signatures)
- Comprehensive test suite (8 test files, 39+ assertions)
- Build system with automated testing
- UI body selection and information display (raygui integration)
- Camera follow feature for selected bodies
- Camera follow improvements: distance preservation and proper orbital rotation
🔨 Remaining/Future Work
- More accurate integration methods (Newton-Raphson propagation)
- Reference frame switching
- SOI transition frame transformations (Phase 3 of hierarchical frames)
- Io and Titan orbital stability tuning
Technical Notes
Code Style and Architecture
- C-style C++: structs and functions only, no classes or templates
- All headers use include guards
- Memory management uses malloc/free
- Layer separation: Physics, Simulation, Configuration, Rendering layers
- Physics module is independent of simulation structures (parameter-based signatures)
Scaling for Visualization
- Distance: logarithmic/power-law scaling for solar system scale
- Size: minimum visible radius to prevent tiny bodies from disappearing
- Origin at Sun for simplicity
- Both distance_scale and size_scale are configurable in RenderState
Physics Considerations
- Timestep: 60 seconds for solar system scale
- Circular orbit velocity:
v = sqrt(G * M / r) - Physics steps per frame: 100 (default) with speed multiplier adjustment
- Simulation time per frame: 60s * 100 = 6000 seconds at 1x speed
- SOI (Sphere of Influence) uses Hill sphere approximation:
r_soi = a * (m/M)^(2/5) - SOI transitions use 0.5x distance hysteresis to prevent oscillation
- Parabolic orbits use escape velocity:
v² = 2GM/r - Hyperbolic orbits have positive total energy and asymptotic velocity
Future Enhancements
- More accurate integration methods (Newton-Raphson propagation)
- Reference frame switching
- 3D orbital visualization with inclination
- SOI transition frame transformations (Phase 3 of hierarchical frames)
- Camera focus on selected body
- Visual highlighting of selected body in 3D view
- Enhanced UI features (search, multiple selection, orbital metrics)