@ -59,36 +59,86 @@ static bool parse_toml_body(toml_datum_t body_table, CelestialBody* body) {
toml_datum_t mass = toml_get ( body_table , " mass " ) ;
toml_datum_t mass = toml_get ( body_table , " mass " ) ;
toml_datum_t radius = toml_get ( body_table , " radius " ) ;
toml_datum_t radius = toml_get ( body_table , " radius " ) ;
toml_datum_t parent_idx = toml_get ( body_table , " parent_index " ) ;
toml_datum_t parent_idx = toml_get ( body_table , " parent_index " ) ;
toml_datum_t eccentricity = toml_get ( body_table , " eccentricity " ) ;
toml_datum_t semi_major = toml_get ( body_table , " semi_major_axis " ) ;
if ( mass . type ! = TOML_FP64 | | radius . type ! = TOML_FP64 | |
if ( mass . type ! = TOML_FP64 | | radius . type ! = TOML_FP64 | |
parent_idx . type ! = TOML_INT64 | |
parent_idx . type ! = TOML_INT64 ) {
eccentricity . type ! = TOML_FP64 | |
semi_major . type ! = TOML_FP64 ) {
return false ;
return false ;
}
}
body - > mass = mass . u . fp64 ;
body - > mass = mass . u . fp64 ;
body - > radius = radius . u . fp64 ;
body - > radius = radius . u . fp64 ;
body - > parent_index = ( int ) ( parent_idx . type = = TOML_INT64 ? parent_idx . u . int64 : ( int ) parent_idx . u . fp64 ) ;
body - > parent_index = ( int ) ( parent_idx . type = = TOML_INT64 ? parent_idx . u . int64 : ( int ) parent_idx . u . fp64 ) ;
body - > orbit . eccentricity = eccentricity . u . fp64 ;
body - > orbit . semi_major_axis = semi_major . u . fp64 ;
// Extract position vector
// Parse orbit table
toml_datum_t position = toml_get ( body_table , " position " ) ;
toml_datum_t orbit_table = toml_get ( body_table , " orbit " ) ;
if ( position . type ! = TOML_TABLE | | ! extract_vec3_from_table ( position , & body - > global_position ) ) {
if ( orbit_table . type ! = TOML_TABLE ) {
printf ( " Error: Body '%s' missing required 'orbit' table \n " , body - > name ) ;
return false ;
}
// Initialize orbital elements with defaults
body - > orbit . semi_major_axis = 0.0 ;
body - > orbit . eccentricity = 0.0 ;
body - > orbit . inclination = 0.0 ;
body - > orbit . longitude_of_ascending_node = 0.0 ;
body - > orbit . argument_of_periapsis = 0.0 ;
body - > orbit . true_anomaly = 0.0 ;
// Parse semi_major_axis (required) or altitude (convenience)
toml_datum_t semi_major = toml_get ( orbit_table , " semi_major_axis " ) ;
toml_datum_t altitude = toml_get ( orbit_table , " altitude " ) ;
if ( semi_major . type = = TOML_FP64 ) {
body - > orbit . semi_major_axis = semi_major . u . fp64 ;
} else if ( altitude . type = = TOML_FP64 ) {
// altitude will be added to parent radius in initialization
body - > orbit . semi_major_axis = altitude . u . fp64 ;
} else {
printf ( " Error: Body '%s' must have either 'semi_major_axis' or 'altitude' in orbit table \n " , body - > name ) ;
return false ;
return false ;
}
}
// Parse eccentricity (optional, default 0.0)
toml_datum_t eccentricity = toml_get ( orbit_table , " eccentricity " ) ;
if ( eccentricity . type = = TOML_FP64 ) {
body - > orbit . eccentricity = eccentricity . u . fp64 ;
}
// Parse true_anomaly (optional, default 0.0)
toml_datum_t true_anomaly = toml_get ( orbit_table , " true_anomaly " ) ;
if ( true_anomaly . type = = TOML_FP64 ) {
body - > orbit . true_anomaly = true_anomaly . u . fp64 ;
}
// Parse inclination (optional, default 0.0)
toml_datum_t inclination = toml_get ( orbit_table , " inclination " ) ;
if ( inclination . type = = TOML_FP64 ) {
body - > orbit . inclination = inclination . u . fp64 ;
}
// Parse longitude_of_ascending_node (optional, default 0.0)
toml_datum_t raan = toml_get ( orbit_table , " longitude_of_ascending_node " ) ;
if ( raan . type = = TOML_FP64 ) {
body - > orbit . longitude_of_ascending_node = raan . u . fp64 ;
}
// Parse argument_of_periapsis (optional, default 0.0)
toml_datum_t aop = toml_get ( orbit_table , " argument_of_periapsis " ) ;
if ( aop . type = = TOML_FP64 ) {
body - > orbit . argument_of_periapsis = aop . u . fp64 ;
}
// Extract color
// Extract color
toml_datum_t color = toml_get ( body_table , " color " ) ;
toml_datum_t color = toml_get ( body_table , " color " ) ;
if ( color . type ! = TOML_TABLE | | ! extract_color_from_table ( color , body - > color ) ) {
if ( color . type ! = TOML_TABLE | | ! extract_color_from_table ( color , body - > color ) ) {
return false ;
return false ;
}
}
// Initialize velocity (will be calculated later)
// Initialize velocity and position (will be calculated later from orbital elements)
body - > global_position = { 0.0 , 0.0 , 0.0 } ;
body - > global_velocity = { 0.0 , 0.0 , 0.0 } ;
body - > global_velocity = { 0.0 , 0.0 , 0.0 } ;
body - > local_position = { 0.0 , 0.0 , 0.0 } ;
body - > local_velocity = { 0.0 , 0.0 , 0.0 } ;
body - > soi_radius = 0.0 ;
body - > soi_radius = 0.0 ;
return true ;
return true ;
@ -161,6 +211,35 @@ bool load_system_config(SimulationState* sim, const char* filepath) {
}
}
}
}
// Validate orbital elements
for ( int i = 0 ; i < body_count ; i + + ) {
CelestialBody * body = & sim - > bodies [ i ] ;
// Validate semi_major_axis
if ( fabs ( body - > orbit . semi_major_axis ) < 1e-10 ) {
printf ( " Error: Body '%s' has invalid semi_major_axis: %.2e (must not be zero) \n " ,
body - > name , body - > orbit . semi_major_axis ) ;
toml_free ( result ) ;
return false ;
}
// Validate eccentricity
if ( body - > orbit . eccentricity < 0.0 ) {
printf ( " Error: Body '%s' has invalid eccentricity: %.3f (must be >= 0) \n " ,
body - > name , body - > orbit . eccentricity ) ;
toml_free ( result ) ;
return false ;
}
// For elliptical orbits (e < 1), semi_major_axis must be positive
if ( body - > orbit . eccentricity < 1.0 & & body - > orbit . semi_major_axis < = 0.0 ) {
printf ( " Error: Body '%s' has elliptical orbit but non-positive semi_major_axis: %.2e \n " ,
body - > name , body - > orbit . semi_major_axis ) ;
toml_free ( result ) ;
return false ;
}
}
sim - > body_count = body_count ;
sim - > body_count = body_count ;
strncpy ( sim - > config_name , filepath , sizeof ( sim - > config_name ) - 1 ) ;
strncpy ( sim - > config_name , filepath , sizeof ( sim - > config_name ) - 1 ) ;
@ -217,10 +296,6 @@ static bool load_spacecraft_from_toml(SimulationState* sim, toml_result_t result
return false ;
return false ;
}
}
CelestialBody * parent = & sim - > bodies [ craft . parent_index ] ;
craft . global_position = vec3_add ( parent - > global_position , craft . local_position ) ;
craft . global_velocity = vec3_add ( parent - > global_velocity , craft . local_velocity ) ;
int idx = add_spacecraft ( sim , & craft ) ;
int idx = add_spacecraft ( sim , & craft ) ;
if ( idx < 0 ) {
if ( idx < 0 ) {
printf ( " Error: Failed to add spacecraft to simulation \n " ) ;
printf ( " Error: Failed to add spacecraft to simulation \n " ) ;
@ -228,6 +303,32 @@ static bool load_spacecraft_from_toml(SimulationState* sim, toml_result_t result
}
}
}
}
// Validate spacecraft orbital elements
for ( int i = 0 ; i < sim - > craft_count ; i + + ) {
Spacecraft * craft = & sim - > spacecraft [ i ] ;
// Validate semi_major_axis
if ( fabs ( craft - > orbit . semi_major_axis ) < 1e-10 ) {
printf ( " Error: Spacecraft '%s' has invalid semi_major_axis: %.2e (must not be zero) \n " ,
craft - > name , craft - > orbit . semi_major_axis ) ;
return false ;
}
// Validate eccentricity
if ( craft - > orbit . eccentricity < 0.0 ) {
printf ( " Error: Spacecraft '%s' has invalid eccentricity: %.3f (must be >= 0) \n " ,
craft - > name , craft - > orbit . eccentricity ) ;
return false ;
}
// For elliptical orbits (e < 1), semi_major_axis must be positive
if ( craft - > orbit . eccentricity < 1.0 & & craft - > orbit . semi_major_axis < = 0.0 ) {
printf ( " Error: Spacecraft '%s' has elliptical orbit but non-positive semi_major_axis: %.2e \n " ,
craft - > name , craft - > orbit . semi_major_axis ) ;
return false ;
}
}
printf ( " Loaded %d spacecraft from %s \n " , craft_count , sim - > config_name ) ;
printf ( " Loaded %d spacecraft from %s \n " , craft_count , sim - > config_name ) ;
return true ;
return true ;
}
}
@ -250,21 +351,70 @@ static bool parse_toml_spacecraft(toml_datum_t craft_table, Spacecraft* craft) {
craft - > mass = mass . u . fp64 ;
craft - > mass = mass . u . fp64 ;
craft - > parent_index = ( int ) ( parent_idx . type = = TOML_INT64 ? parent_idx . u . int64 : ( int ) parent_idx . u . fp64 ) ;
craft - > parent_index = ( int ) ( parent_idx . type = = TOML_INT64 ? parent_idx . u . int64 : ( int ) parent_idx . u . fp64 ) ;
toml_datum_t position = toml_get ( craft_table , " position " ) ;
// Parse orbit table
if ( position . type ! = TOML_TABLE | | ! extract_vec3_from_table ( position , & craft - > local_position ) ) {
toml_datum_t orbit_table = toml_get ( craft_table , " orbit " ) ;
if ( orbit_table . type ! = TOML_TABLE ) {
printf ( " Error: Spacecraft '%s' missing required 'orbit' table \n " , craft - > name ) ;
return false ;
return false ;
}
}
craft - > global_position = craft - > local_position ;
toml_datum_t velocity = toml_get ( craft_table , " velocity " ) ;
// Initialize orbital elements with defaults
if ( velocity . type = = TOML_TABLE ) {
craft - > orbit . semi_major_axis = 0.0 ;
if ( ! extract_vec3_from_table ( velocity , & craft - > local_velocity ) ) {
craft - > orbit . eccentricity = 0.0 ;
craft - > orbit . inclination = 0.0 ;
craft - > orbit . longitude_of_ascending_node = 0.0 ;
craft - > orbit . argument_of_periapsis = 0.0 ;
craft - > orbit . true_anomaly = 0.0 ;
// Parse semi_major_axis (required) or altitude (convenience)
toml_datum_t semi_major = toml_get ( orbit_table , " semi_major_axis " ) ;
toml_datum_t altitude = toml_get ( orbit_table , " altitude " ) ;
if ( semi_major . type = = TOML_FP64 ) {
craft - > orbit . semi_major_axis = semi_major . u . fp64 ;
} else if ( altitude . type = = TOML_FP64 ) {
// altitude will be added to parent radius in initialization
craft - > orbit . semi_major_axis = altitude . u . fp64 ;
} else {
printf ( " Error: Spacecraft '%s' must have either 'semi_major_axis' or 'altitude' in orbit table \n " , craft - > name ) ;
return false ;
return false ;
}
}
} else {
craft - > local_velocity = { 0.0 , 0.0 , 0.0 } ;
// Parse eccentricity (optional, default 0.0)
toml_datum_t eccentricity = toml_get ( orbit_table , " eccentricity " ) ;
if ( eccentricity . type = = TOML_FP64 ) {
craft - > orbit . eccentricity = eccentricity . u . fp64 ;
}
// Parse true_anomaly (optional, default 0.0)
toml_datum_t true_anomaly = toml_get ( orbit_table , " true_anomaly " ) ;
if ( true_anomaly . type = = TOML_FP64 ) {
craft - > orbit . true_anomaly = true_anomaly . u . fp64 ;
}
}
craft - > global_velocity = craft - > local_velocity ;
// Parse inclination (optional, default 0.0)
toml_datum_t inclination = toml_get ( orbit_table , " inclination " ) ;
if ( inclination . type = = TOML_FP64 ) {
craft - > orbit . inclination = inclination . u . fp64 ;
}
// Parse longitude_of_ascending_node (optional, default 0.0)
toml_datum_t raan = toml_get ( orbit_table , " longitude_of_ascending_node " ) ;
if ( raan . type = = TOML_FP64 ) {
craft - > orbit . longitude_of_ascending_node = raan . u . fp64 ;
}
// Parse argument_of_periapsis (optional, default 0.0)
toml_datum_t aop = toml_get ( orbit_table , " argument_of_periapsis " ) ;
if ( aop . type = = TOML_FP64 ) {
craft - > orbit . argument_of_periapsis = aop . u . fp64 ;
}
// Initialize position and velocity (will be calculated later from orbital elements)
craft - > global_position = { 0.0 , 0.0 , 0.0 } ;
craft - > global_velocity = { 0.0 , 0.0 , 0.0 } ;
craft - > local_position = { 0.0 , 0.0 , 0.0 } ;
craft - > local_velocity = { 0.0 , 0.0 , 0.0 } ;
return true ;
return true ;
}
}