@ -84,24 +84,45 @@ static bool parse_toml_body(toml_datum_t body_table, CelestialBody* body) {
body - > orbit . argument_of_periapsis = 0.0 ;
body - > orbit . argument_of_periapsis = 0.0 ;
body - > orbit . true_anomaly = 0.0 ;
body - > orbit . true_anomaly = 0.0 ;
// Parse semi_major_axis (required ) or altitude (convenience)
// Parse semi_major_axis (for elliptical/hyperbolic) or semi_latus_rectum (for parabolic ) or altitude (convenience)
toml_datum_t semi_major = toml_get ( orbit_table , " semi_major_axis " ) ;
toml_datum_t semi_major = toml_get ( orbit_table , " semi_major_axis " ) ;
toml_datum_t semi_latus = toml_get ( orbit_table , " semi_latus_rectum " ) ;
toml_datum_t altitude = toml_get ( orbit_table , " altitude " ) ;
toml_datum_t altitude = toml_get ( orbit_table , " altitude " ) ;
// Parse eccentricity first to determine which parameter is required
toml_datum_t eccentricity = toml_get ( orbit_table , " eccentricity " ) ;
if ( eccentricity . type ! = TOML_FP64 ) {
printf ( " Error: Body '%s' missing required 'eccentricity' in orbit table \n " , body - > name ) ;
return false ;
}
body - > orbit . eccentricity = eccentricity . u . fp64 ;
bool is_parabolic = ( fabs ( body - > orbit . eccentricity - 1.0 ) < 0.005 ) ;
if ( is_parabolic ) {
// Parabolic orbit - requires semi_latus_rectum
if ( semi_latus . type ! = TOML_FP64 ) {
printf ( " Error: Parabolic orbit for body '%s' requires 'semi_latus_rectum' (not 'semi_major_axis' or 'altitude') \n " , body - > name ) ;
return false ;
}
body - > orbit . semi_latus_rectum = semi_latus . u . fp64 ;
if ( semi_major . type = = TOML_FP64 | | altitude . type = = TOML_FP64 ) {
printf ( " Warning: Body '%s' has parabolic eccentricity, 'semi_latus_rectum' used instead of 'semi_major_axis' or 'altitude' \n " , body - > name ) ;
}
} else {
// Elliptical or hyperbolic - requires semi_major_axis or altitude
if ( semi_major . type = = TOML_FP64 ) {
if ( semi_major . type = = TOML_FP64 ) {
body - > orbit . semi_major_axis = semi_major . u . fp64 ;
body - > orbit . semi_major_axis = semi_major . u . fp64 ;
} else if ( altitude . type = = TOML_FP64 ) {
} else if ( altitude . type = = TOML_FP64 ) {
// altitude will be added to parent radius in initialization
// altitude will be added to parent radius in initialization
body - > orbit . semi_major_axis = altitude . u . fp64 ;
body - > orbit . semi_major_axis = altitude . u . fp64 ;
} else {
} else {
printf ( " Error: Body '%s' must have either 'semi_major_axis' or 'altitude' in orbit table \n " , body - > name ) ;
printf ( " Error: Body '%s' must have either 'semi_major_axis' or 'altitude' in orbit table (non-parabolic orbits) \n " , body - > name ) ;
return false ;
return false ;
}
}
if ( semi_latus . type = = TOML_FP64 ) {
// Parse eccentricity (optional, default 0.0)
printf ( " Warning: Body '%s' has non-parabolic eccentricity, 'semi_latus_rectum' ignored \n " , body - > name ) ;
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)
// Parse true_anomaly (optional, default 0.0)
@ -200,12 +221,7 @@ bool load_system_config(SimulationState* sim, const char* filepath) {
continue ;
continue ;
}
}
if ( body - > orbit . semi_major_axis = = 0.0 ) {
bool is_parabolic = ( fabs ( body - > orbit . eccentricity - 1.0 ) < 0.005 ) ;
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 ;
}
if ( body - > orbit . eccentricity < 0.0 ) {
if ( body - > orbit . eccentricity < 0.0 ) {
printf ( " Error: Body '%s' has invalid eccentricity: %.2e (must be >= 0) \n " ,
printf ( " Error: Body '%s' has invalid eccentricity: %.2e (must be >= 0) \n " ,
@ -214,6 +230,23 @@ bool load_system_config(SimulationState* sim, const char* filepath) {
return false ;
return false ;
}
}
if ( is_parabolic ) {
// For parabolic orbits, semi_latus_rectum must be positive
if ( body - > orbit . semi_latus_rectum < = 0.0 ) {
printf ( " Error: Body '%s' has parabolic orbit but non-positive semi_latus_rectum: %.2e \n " ,
body - > name , body - > orbit . semi_latus_rectum ) ;
toml_free ( result ) ;
return false ;
}
} else {
// For elliptical/hyperbolic orbits, semi_major_axis must be non-zero
if ( body - > orbit . semi_major_axis = = 0.0 ) {
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 ;
}
// For elliptical orbits (e < 1), semi_major_axis must be positive
// For elliptical orbits (e < 1), semi_major_axis must be positive
if ( body - > orbit . eccentricity < 1.0 & & body - > orbit . semi_major_axis < = 0.0 ) {
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 " ,
printf ( " Error: Body '%s' has elliptical orbit but non-positive semi_major_axis: %.2e \n " ,
@ -222,6 +255,7 @@ bool load_system_config(SimulationState* sim, const char* filepath) {
return false ;
return false ;
}
}
}
}
}
sim - > body_count = body_count ;
sim - > body_count = body_count ;
@ -295,25 +329,28 @@ static bool load_spacecraft_from_toml(SimulationState* sim, toml_result_t result
for ( int i = 0 ; i < sim - > craft_count ; i + + ) {
for ( int i = 0 ; i < sim - > craft_count ; i + + ) {
Spacecraft * craft = & sim - > spacecraft [ i ] ;
Spacecraft * craft = & sim - > spacecraft [ i ] ;
if ( craft - > parent_index > = 0 & & craft - > parent_index < sim - > body_count ) {
bool is_parabolic = ( fabs ( craft - > orbit . eccentricity - 1.0 ) < 0.005 ) ;
if ( ! is_parabolic & & 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 - > orbit . semi_major_axis + = parent - > radius ;
craft - > orbit . semi_major_axis + = parent - > radius ;
}
}
// Validate semi_major_axis
if ( is_parabolic ) {
// For parabolic orbits, semi_latus_rectum must be positive
if ( craft - > orbit . semi_latus_rectum < = 0.0 ) {
printf ( " Error: Spacecraft '%s' has parabolic orbit but non-positive semi_latus_rectum: %.2e \n " ,
craft - > name , craft - > orbit . semi_latus_rectum ) ;
return false ;
}
} else {
// For elliptical/hyperbolic orbits, validate semi_major_axis
if ( fabs ( craft - > orbit . semi_major_axis ) < 1e-10 ) {
if ( fabs ( craft - > orbit . semi_major_axis ) < 1e-10 ) {
printf ( " Error: Spacecraft '%s' has invalid semi_major_axis: %.2e (must not be zero) \n " ,
printf ( " Error: Spacecraft '%s' has invalid semi_major_axis: %.2e (must not be zero) \n " ,
craft - > name , craft - > orbit . semi_major_axis ) ;
craft - > name , craft - > orbit . semi_major_axis ) ;
return false ;
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
// For elliptical orbits (e < 1), semi_major_axis must be positive
if ( craft - > orbit . eccentricity < 1.0 & & craft - > orbit . semi_major_axis < = 0.0 ) {
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 " ,
printf ( " Error: Spacecraft '%s' has elliptical orbit but non-positive semi_major_axis: %.2e \n " ,
@ -322,6 +359,14 @@ static bool load_spacecraft_from_toml(SimulationState* sim, toml_result_t result
}
}
}
}
// 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 ;
}
}
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 ;
}
}
@ -359,24 +404,45 @@ static bool parse_toml_spacecraft(toml_datum_t craft_table, Spacecraft* craft) {
craft - > orbit . argument_of_periapsis = 0.0 ;
craft - > orbit . argument_of_periapsis = 0.0 ;
craft - > orbit . true_anomaly = 0.0 ;
craft - > orbit . true_anomaly = 0.0 ;
// Parse semi_major_axis (required ) or altitude (convenience)
// Parse semi_major_axis (for elliptical/hyperbolic) or semi_latus_rectum (for parabolic ) or altitude (convenience)
toml_datum_t semi_major = toml_get ( orbit_table , " semi_major_axis " ) ;
toml_datum_t semi_major = toml_get ( orbit_table , " semi_major_axis " ) ;
toml_datum_t semi_latus = toml_get ( orbit_table , " semi_latus_rectum " ) ;
toml_datum_t altitude = toml_get ( orbit_table , " altitude " ) ;
toml_datum_t altitude = toml_get ( orbit_table , " altitude " ) ;
// Parse eccentricity first to determine which parameter is required
toml_datum_t eccentricity = toml_get ( orbit_table , " eccentricity " ) ;
if ( eccentricity . type ! = TOML_FP64 ) {
printf ( " Error: Spacecraft '%s' missing required 'eccentricity' in orbit table \n " , craft - > name ) ;
return false ;
}
craft - > orbit . eccentricity = eccentricity . u . fp64 ;
bool is_parabolic = ( fabs ( craft - > orbit . eccentricity - 1.0 ) < 0.005 ) ;
if ( is_parabolic ) {
// Parabolic orbit - requires semi_latus_rectum
if ( semi_latus . type ! = TOML_FP64 ) {
printf ( " Error: Parabolic orbit for spacecraft '%s' requires 'semi_latus_rectum' (not 'semi_major_axis' or 'altitude') \n " , craft - > name ) ;
return false ;
}
craft - > orbit . semi_latus_rectum = semi_latus . u . fp64 ;
if ( semi_major . type = = TOML_FP64 | | altitude . type = = TOML_FP64 ) {
printf ( " Warning: Spacecraft '%s' has parabolic eccentricity, 'semi_latus_rectum' used instead of 'semi_major_axis' or 'altitude' \n " , craft - > name ) ;
}
} else {
// Elliptical or hyperbolic - requires semi_major_axis or altitude
if ( semi_major . type = = TOML_FP64 ) {
if ( semi_major . type = = TOML_FP64 ) {
craft - > orbit . semi_major_axis = semi_major . u . fp64 ;
craft - > orbit . semi_major_axis = semi_major . u . fp64 ;
} else if ( altitude . type = = TOML_FP64 ) {
} else if ( altitude . type = = TOML_FP64 ) {
// altitude will be added to parent radius in initialization
// altitude will be added to parent radius in initialization
craft - > orbit . semi_major_axis = altitude . u . fp64 ;
craft - > orbit . semi_major_axis = altitude . u . fp64 ;
} else {
} else {
printf ( " Error: Spacecraft '%s' must have either 'semi_major_axis' or 'altitude' in orbit table \n " , craft - > name ) ;
printf ( " Error: Spacecraft '%s' must have either 'semi_major_axis' or 'altitude' in orbit table (non-parabolic orbits) \n " , craft - > name ) ;
return false ;
return false ;
}
}
if ( semi_latus . type = = TOML_FP64 ) {
// Parse eccentricity (optional, default 0.0)
printf ( " Warning: Spacecraft '%s' has non-parabolic eccentricity, 'semi_latus_rectum' ignored \n " , craft - > name ) ;
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)
// Parse true_anomaly (optional, default 0.0)