@ -81,22 +81,22 @@ int add_body_to_simulation(SimulationState* sim, CelestialBody* body) {
if ( body - > parent_index > = 0 & & body - > parent_index < sim - > body_count ) {
if ( body - > parent_index > = 0 & & body - > parent_index < sim - > body_count ) {
CelestialBody * parent = & sim - > bodies [ body - > parent_index ] ;
CelestialBody * parent = & sim - > bodies [ body - > parent_index ] ;
sim - > bodies [ new_idx ] . local_position = vec3_sub ( body - > position , parent - > position ) ;
sim - > bodies [ new_idx ] . local_position = vec3_sub ( body - > global_ position, parent - > global_ position) ;
sim - > bodies [ new_idx ] . local_velocity = vec3_sub ( body - > velocity , parent - > velocity ) ;
sim - > bodies [ new_idx ] . local_velocity = vec3_sub ( body - > global_ velocity, parent - > global_ velocity) ;
} else {
} else {
sim - > bodies [ new_idx ] . local_position = body - > position ;
sim - > bodies [ new_idx ] . local_position = body - > global_ position;
sim - > bodies [ new_idx ] . local_velocity = body - > velocity ;
sim - > bodies [ new_idx ] . local_velocity = body - > global_ velocity;
}
}
if ( body - > parent_index > = 0 & & body - > parent_index < sim - > body_count ) {
if ( body - > parent_index > = 0 & & body - > parent_index < sim - > body_count ) {
CelestialBody * parent = & sim - > bodies [ body - > parent_index ] ;
CelestialBody * parent = & sim - > bodies [ body - > parent_index ] ;
update_soi ( & sim - > bodies [ new_idx ] , parent , body - > semi_major_axis ) ;
update_soi ( & sim - > bodies [ new_idx ] , parent , body - > orbit . semi_major_axis ) ;
} else {
} else {
sim - > bodies [ new_idx ] . soi_radius = 1e15 ;
sim - > bodies [ new_idx ] . soi_radius = 1e15 ;
}
}
sim - > bodies [ new_idx ] . position = body - > position ;
sim - > bodies [ new_idx ] . global_ position = body - > global_ position;
sim - > bodies [ new_idx ] . velocity = body - > velocity ;
sim - > bodies [ new_idx ] . global_ velocity = body - > global_ velocity;
return new_idx ;
return new_idx ;
}
}
@ -116,7 +116,7 @@ int find_dominant_body(SimulationState* sim, int body_index) {
}
}
CelestialBody * parent = & sim - > bodies [ parent_idx ] ;
CelestialBody * parent = & sim - > bodies [ parent_idx ] ;
double distance = vec3_distance ( body - > position , parent - > position ) ;
double distance = vec3_distance ( body - > global_ position, parent - > global_ position) ;
// Stay with parent if within SOI, otherwise go to Sun
// Stay with parent if within SOI, otherwise go to Sun
if ( distance < parent - > soi_radius ) {
if ( distance < parent - > soi_radius ) {
@ -134,7 +134,7 @@ int find_dominant_body(SimulationState* sim, int body_index) {
if ( i = = body_index ) continue ;
if ( i = = body_index ) continue ;
CelestialBody * potential = & sim - > bodies [ i ] ;
CelestialBody * potential = & sim - > bodies [ i ] ;
double distance = vec3_distance ( body - > position , potential - > position ) ;
double distance = vec3_distance ( body - > global_ position, potential - > global_ position) ;
// If within SOI and closer than current, switch to this body
// If within SOI and closer than current, switch to this body
if ( distance < potential - > soi_radius & & distance < min_distance ) {
if ( distance < potential - > soi_radius & & distance < min_distance ) {
@ -170,15 +170,15 @@ void update_simulation(SimulationState* sim) {
// Calculate orbital velocity using vis-viva equation
// Calculate orbital velocity using vis-viva equation
// Returns velocity vector for body relative to parent
// Returns velocity vector for body relative to parent
static Vec3 calc_orbital_velocity ( CelestialBody * body , CelestialBody * parent ) {
static Vec3 calc_orbital_velocity ( CelestialBody * body , CelestialBody * parent ) {
Vec3 r = vec3_sub ( body - > position , parent - > position ) ;
Vec3 r = vec3_sub ( body - > global_ position, parent - > global_ position) ;
double distance = vec3_magnitude ( r ) ;
double distance = vec3_magnitude ( r ) ;
double e = body - > eccentricity ;
double e = body - > orbit . eccentricity ;
double a = body - > semi_major_axis ;
double a = body - > orbit . semi_major_axis ;
double v_squared ;
double v_squared ;
if ( fabs ( e ) < 0.0001 ) {
if ( fabs ( e ) < 0.0001 ) {
v_squared = G * parent - > mass / a ;
v_squared = G * parent - > mass / a ;
} else if ( fabs ( e - 1.0 ) < 0.0001 ) {
} else if ( fabs ( e - 1.0 ) < 0.0001 ) {
v_squared = 2.0 * G * parent - > mass / distance ;
v_squared = 2.0 * G * parent - > mass / distance ;
} else {
} else {
v_squared = G * parent - > mass * ( 2.0 / distance - 1.0 / a ) ;
v_squared = G * parent - > mass * ( 2.0 / distance - 1.0 / a ) ;
@ -199,7 +199,7 @@ static Vec3 calc_orbital_velocity(CelestialBody* body, CelestialBody* parent) {
vel_dir = vec3_normalize ( vel_dir ) ;
vel_dir = vec3_normalize ( vel_dir ) ;
Vec3 velocity = vec3_scale ( vel_dir , speed ) ;
Vec3 velocity = vec3_scale ( vel_dir , speed ) ;
return vec3_add ( velocity , parent - > velocity ) ;
return vec3_add ( velocity , parent - > global_ velocity) ;
}
}
// Calculate SOI radius for a single body
// Calculate SOI radius for a single body
@ -208,7 +208,7 @@ static Vec3 calc_orbital_velocity(CelestialBody* body, CelestialBody* parent) {
double calculate_soi_radius ( CelestialBody * body , CelestialBody * parent ) {
double calculate_soi_radius ( CelestialBody * body , CelestialBody * parent ) {
assert ( body ! = nullptr & & parent ! = nullptr ) ;
assert ( body ! = nullptr & & parent ! = nullptr ) ;
double mass_ratio = body - > mass / parent - > mass ;
double mass_ratio = body - > mass / parent - > mass ;
return body - > semi_major_axis * pow ( mass_ratio , 0.4 ) ; // 2/5 = 0.4
return body - > orbit . semi_major_axis * pow ( mass_ratio , 0.4 ) ; // 2/5 = 0.4
}
}
// Combined initialization - sets velocities, SOI radii, and local coordinates in single loop
// Combined initialization - sets velocities, SOI radii, and local coordinates in single loop
@ -220,14 +220,14 @@ void initialize_bodies(SimulationState* sim) {
// Set parent pointer if not root body
// Set parent pointer if not root body
if ( body - > parent_index > = 0 & & body - > parent_index < sim - > body_count ) {
if ( body - > parent_index > = 0 & & body - > parent_index < sim - > body_count ) {
parent = & sim - > bodies [ body - > parent_index ] ;
parent = & sim - > bodies [ body - > parent_index ] ;
body - > velocity = calc_orbital_velocity ( body , parent ) ;
body - > global_ velocity = calc_orbital_velocity ( body , parent ) ;
body - > local_position = vec3_sub ( body - > position , parent - > position ) ;
body - > local_position = vec3_sub ( body - > global_ position, parent - > global_ position) ;
body - > local_velocity = vec3_sub ( body - > velocity , parent - > velocity ) ;
body - > local_velocity = vec3_sub ( body - > global_ velocity, parent - > global_ velocity) ;
body - > soi_radius = calculate_soi_radius ( body , parent ) ;
body - > soi_radius = calculate_soi_radius ( body , parent ) ;
} else { // root body
} else { // root body
body - > velocity = { 0.0 , 0.0 , 0.0 } ;
body - > global_ velocity = { 0.0 , 0.0 , 0.0 } ;
body - > local_position = body - > position ;
body - > local_position = body - > global_ position;
body - > local_velocity = body - > velocity ;
body - > local_velocity = body - > global_ velocity;
// Root body (like Sun) has infinite SOI, use a large value
// Root body (like Sun) has infinite SOI, use a large value
body - > soi_radius = 1e15 ; // 1000 AU in meters
body - > soi_radius = 1e15 ; // 1000 AU in meters
@ -249,22 +249,22 @@ void update_bodies_physics(SimulationState* sim) {
if ( new_parent ! = body - > parent_index ) {
if ( new_parent ! = body - > parent_index ) {
if ( body - > parent_index > = 0 & & body - > parent_index < sim - > body_count ) {
if ( body - > parent_index > = 0 & & body - > parent_index < sim - > body_count ) {
CelestialBody * old_parent = & sim - > bodies [ body - > parent_index ] ;
CelestialBody * old_parent = & sim - > bodies [ body - > parent_index ] ;
body - > position = vec3_add ( body - > local_position , old_parent - > position ) ;
body - > global_ position = vec3_add ( body - > local_position , old_parent - > global_ position) ;
body - > velocity = vec3_add ( body - > local_velocity , old_parent - > velocity ) ;
body - > global_ velocity = vec3_add ( body - > local_velocity , old_parent - > global_ velocity) ;
} else {
} else {
body - > position = body - > local_position ;
body - > global_ position = body - > local_position ;
body - > velocity = body - > local_velocity ;
body - > global_ velocity = body - > local_velocity ;
}
}
body - > parent_index = new_parent ;
body - > parent_index = new_parent ;
if ( body - > parent_index > = 0 & & body - > parent_index < sim - > body_count ) {
if ( body - > parent_index > = 0 & & body - > parent_index < sim - > body_count ) {
CelestialBody * new_parent_body = & sim - > bodies [ body - > parent_index ] ;
CelestialBody * new_parent_body = & sim - > bodies [ body - > parent_index ] ;
body - > local_position = vec3_sub ( body - > position , new_parent_body - > position ) ;
body - > local_position = vec3_sub ( body - > global_ position, new_parent_body - > global_ position) ;
body - > local_velocity = vec3_sub ( body - > velocity , new_parent_body - > velocity ) ;
body - > local_velocity = vec3_sub ( body - > global_ velocity, new_parent_body - > global_ velocity) ;
} else {
} else {
body - > local_position = body - > position ;
body - > local_position = body - > global_ position;
body - > local_velocity = body - > velocity ;
body - > local_velocity = body - > global_ velocity;
}
}
}
}
@ -318,11 +318,11 @@ void compute_spacecraft_globals(SimulationState* sim) {
if ( craft - > parent_index > = 0 & & craft - > parent_index < sim - > body_count ) {
if ( craft - > parent_index > = 0 & & craft - > parent_index < sim - > body_count ) {
CelestialBody * parent = & sim - > bodies [ craft - > parent_index ] ;
CelestialBody * parent = & sim - > bodies [ craft - > parent_index ] ;
craft - > position = vec3_add ( parent - > position , craft - > local_position ) ;
craft - > global_ position = vec3_add ( parent - > global_ position, craft - > local_position ) ;
craft - > velocity = vec3_add ( parent - > velocity , craft - > local_velocity ) ;
craft - > global_ velocity = vec3_add ( parent - > global_ velocity, craft - > local_velocity ) ;
} else {
} else {
craft - > position = craft - > local_position ;
craft - > global_ position = craft - > local_position ;
craft - > velocity = craft - > local_velocity ;
craft - > global_ velocity = craft - > local_velocity ;
}
}
}
}
}
}
@ -332,34 +332,34 @@ void compute_global_coordinates(SimulationState* sim) {
CelestialBody * body = & sim - > bodies [ i ] ;
CelestialBody * body = & sim - > bodies [ i ] ;
if ( body - > parent_index = = - 1 ) {
if ( body - > parent_index = = - 1 ) {
body - > position = body - > local_position ;
body - > global_ position = body - > local_position ;
body - > velocity = body - > local_velocity ;
body - > global_ velocity = body - > local_velocity ;
} else if ( body - > parent_index > = 0 & & body - > parent_index < sim - > body_count ) {
} else if ( body - > parent_index > = 0 & & body - > parent_index < sim - > body_count ) {
CelestialBody * parent = & sim - > bodies [ body - > parent_index ] ;
CelestialBody * parent = & sim - > bodies [ body - > parent_index ] ;
body - > position = vec3_add ( body - > local_position , parent - > position ) ;
body - > global_ position = vec3_add ( body - > local_position , parent - > global_ position) ;
body - > velocity = vec3_add ( body - > local_velocity , parent - > velocity ) ;
body - > global_ velocity = vec3_add ( body - > local_velocity , parent - > global_ velocity) ;
}
}
}
}
}
}
OrbitalElement s calculate_orbital_elements ( CelestialBody * body , CelestialBody * primary ,
OrbitalMetric s calculate_orbital_elements ( CelestialBody * body , CelestialBody * primary ,
CelestialBody * optional_ref_body , double current_time ) {
CelestialBody * optional_ref_body , double current_time ) {
const double AU = 1.496e11 ;
const double AU = 1.496e11 ;
const double SECONDS_PER_DAY = 86400.0 ;
const double SECONDS_PER_DAY = 86400.0 ;
const double M_sun = primary - > mass ;
const double M_sun = primary - > mass ;
OrbitalElement s elem ;
OrbitalMetric s elem ;
elem . time_days = current_time / SECONDS_PER_DAY ;
elem . time_days = current_time / SECONDS_PER_DAY ;
Vec3 r_vec = vec3_sub ( body - > position , primary - > position ) ;
Vec3 r_vec = vec3_sub ( body - > global_ position, primary - > global_ position) ;
double r = vec3_magnitude ( r_vec ) ;
double r = vec3_magnitude ( r_vec ) ;
double v = vec3_magnitude ( body - > velocity ) ;
double v = vec3_magnitude ( body - > global_ velocity) ;
elem . distance_to_sun_au = r / AU ;
elem . distance_to_sun_au = r / AU ;
elem . velocity_magnitude = v ;
elem . velocity_magnitude = v ;
if ( optional_ref_body ) {
if ( optional_ref_body ) {
double dist_ref = vec3_distance ( body - > position , optional_ref_body - > position ) ;
double dist_ref = vec3_distance ( body - > global_ position, optional_ref_body - > global_ position) ;
elem . distance_to_ref_body_au = dist_ref / AU ;
elem . distance_to_ref_body_au = dist_ref / AU ;
} else {
} else {
elem . distance_to_ref_body_au = - 1.0 ;
elem . distance_to_ref_body_au = - 1.0 ;
@ -371,12 +371,12 @@ OrbitalElements calculate_orbital_elements(CelestialBody* body, CelestialBody* p
elem . semi_major_axis_au = - ( G * M_sun ) / ( 2.0 * elem . specific_energy ) / AU ;
elem . semi_major_axis_au = - ( G * M_sun ) / ( 2.0 * elem . specific_energy ) / AU ;
double v_squared = v * v ;
double v_squared = v * v ;
double r_dot_v = r_vec . x * body - > velocity . x + r_vec . y * body - > velocity . y + r_vec . z * body - > velocity . z ;
double r_dot_v = r_vec . x * body - > global_ velocity. x + r_vec . y * body - > global_ velocity. y + r_vec . z * body - > global_ velocity. z ;
Vec3 e_vec ;
Vec3 e_vec ;
e_vec . x = ( v_squared - G * M_sun / r ) * r_vec . x - r_dot_v * body - > velocity . x ;
e_vec . x = ( v_squared - G * M_sun / r ) * r_vec . x - r_dot_v * body - > global_ velocity. x ;
e_vec . y = ( v_squared - G * M_sun / r ) * r_vec . y - r_dot_v * body - > velocity . y ;
e_vec . y = ( v_squared - G * M_sun / r ) * r_vec . y - r_dot_v * body - > global_ velocity. y ;
e_vec . z = ( v_squared - G * M_sun / r ) * r_vec . z - r_dot_v * body - > velocity . z ;
e_vec . z = ( v_squared - G * M_sun / r ) * r_vec . z - r_dot_v * body - > global_ velocity. z ;
double e_mag = vec3_magnitude ( e_vec ) / ( G * M_sun ) ;
double e_mag = vec3_magnitude ( e_vec ) / ( G * M_sun ) ;
elem . eccentricity = e_mag ;
elem . eccentricity = e_mag ;