|
|
|
|
@ -29,43 +29,14 @@ static bool extract_color_from_table(toml_datum_t table, float* color) {
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool parse_toml_body(toml_datum_t body_table, CelestialBody* body) { |
|
|
|
|
// Extract string fields
|
|
|
|
|
toml_datum_t name = toml_get(body_table, "name"); |
|
|
|
|
if (name.type != TOML_STRING) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
strncpy(body->name, name.u.s, 63); |
|
|
|
|
body->name[63] = '\0'; |
|
|
|
|
|
|
|
|
|
// Extract numeric fields
|
|
|
|
|
toml_datum_t mass = toml_get(body_table, "mass"); |
|
|
|
|
toml_datum_t radius = toml_get(body_table, "radius"); |
|
|
|
|
toml_datum_t parent_idx = toml_get(body_table, "parent_index"); |
|
|
|
|
|
|
|
|
|
if (mass.type != TOML_FP64 || radius.type != TOML_FP64 || |
|
|
|
|
parent_idx.type != TOML_INT64) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
body->mass = mass.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); |
|
|
|
|
|
|
|
|
|
// Parse orbit table
|
|
|
|
|
toml_datum_t orbit_table = toml_get(body_table, "orbit"); |
|
|
|
|
if (orbit_table.type != TOML_TABLE) { |
|
|
|
|
printf("Error: Body '%s' missing required 'orbit' table\n", body->name); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool parse_toml_orbit(toml_datum_t orbit_table, OrbitalElements* orbit, const char* object_name) { |
|
|
|
|
// 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; |
|
|
|
|
orbit->semi_major_axis = 0.0; |
|
|
|
|
orbit->eccentricity = 0.0; |
|
|
|
|
orbit->inclination = 0.0; |
|
|
|
|
orbit->longitude_of_ascending_node = 0.0; |
|
|
|
|
orbit->argument_of_periapsis = 0.0; |
|
|
|
|
orbit->true_anomaly = 0.0; |
|
|
|
|
|
|
|
|
|
// Parse semi_major_axis (for elliptical/hyperbolic) or semi_latus_rectum (for parabolic)
|
|
|
|
|
toml_datum_t semi_major = toml_get(orbit_table, "semi_major_axis"); |
|
|
|
|
@ -74,58 +45,95 @@ static bool parse_toml_body(toml_datum_t body_table, CelestialBody* body) {
|
|
|
|
|
// 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); |
|
|
|
|
printf("Error: Object '%s' missing required 'eccentricity' in orbit table\n", object_name); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
body->orbit.eccentricity = eccentricity.u.fp64; |
|
|
|
|
orbit->eccentricity = eccentricity.u.fp64; |
|
|
|
|
|
|
|
|
|
bool is_parabolic = (fabs(body->orbit.eccentricity - 1.0) < 0.005); |
|
|
|
|
bool is_parabolic = (fabs(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')\n", body->name); |
|
|
|
|
printf("Error: Parabolic orbit for object '%s' requires 'semi_latus_rectum' (not 'semi_major_axis')\n", object_name); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
body->orbit.semi_latus_rectum = semi_latus.u.fp64; |
|
|
|
|
orbit->semi_latus_rectum = semi_latus.u.fp64; |
|
|
|
|
if (semi_major.type == TOML_FP64) { |
|
|
|
|
printf("Warning: Body '%s' has parabolic eccentricity, 'semi_latus_rectum' used instead of 'semi_major_axis'\n", body->name); |
|
|
|
|
printf("Warning: Object '%s' has parabolic eccentricity, 'semi_latus_rectum' used instead of 'semi_major_axis'\n", object_name); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// Elliptical or hyperbolic - requires semi_major_axis
|
|
|
|
|
if (semi_major.type == TOML_FP64) { |
|
|
|
|
body->orbit.semi_major_axis = semi_major.u.fp64; |
|
|
|
|
orbit->semi_major_axis = semi_major.u.fp64; |
|
|
|
|
} else { |
|
|
|
|
printf("Error: Body '%s' must have 'semi_major_axis' in orbit table (non-parabolic orbits)\n", body->name); |
|
|
|
|
printf("Error: Object '%s' must have 'semi_major_axis' in orbit table (non-parabolic orbits)\n", object_name); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
if (semi_latus.type == TOML_FP64) { |
|
|
|
|
printf("Warning: Body '%s' has non-parabolic eccentricity, 'semi_latus_rectum' ignored\n", body->name); |
|
|
|
|
printf("Warning: Object '%s' has non-parabolic eccentricity, 'semi_latus_rectum' ignored\n", object_name); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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; |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
orbit->argument_of_periapsis = aop.u.fp64; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool parse_toml_body(toml_datum_t body_table, CelestialBody* body) { |
|
|
|
|
// Extract string fields
|
|
|
|
|
toml_datum_t name = toml_get(body_table, "name"); |
|
|
|
|
if (name.type != TOML_STRING) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
strncpy(body->name, name.u.s, 63); |
|
|
|
|
body->name[63] = '\0'; |
|
|
|
|
|
|
|
|
|
// Extract numeric fields
|
|
|
|
|
toml_datum_t mass = toml_get(body_table, "mass"); |
|
|
|
|
toml_datum_t radius = toml_get(body_table, "radius"); |
|
|
|
|
toml_datum_t parent_idx = toml_get(body_table, "parent_index"); |
|
|
|
|
|
|
|
|
|
if (mass.type != TOML_FP64 || radius.type != TOML_FP64 || |
|
|
|
|
parent_idx.type != TOML_INT64) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
body->mass = mass.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); |
|
|
|
|
|
|
|
|
|
// Parse orbit table
|
|
|
|
|
toml_datum_t orbit_table = toml_get(body_table, "orbit"); |
|
|
|
|
if (orbit_table.type != TOML_TABLE) { |
|
|
|
|
printf("Error: Body '%s' missing required 'orbit' table\n", body->name); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!parse_toml_orbit(orbit_table, &body->orbit, body->name)) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Extract color
|
|
|
|
|
@ -275,74 +283,9 @@ static bool parse_toml_spacecraft(toml_datum_t craft_table, Spacecraft* craft) {
|
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Initialize orbital elements with defaults
|
|
|
|
|
craft->orbit.semi_major_axis = 0.0; |
|
|
|
|
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 (for elliptical/hyperbolic) or semi_latus_rectum (for parabolic)
|
|
|
|
|
toml_datum_t semi_major = toml_get(orbit_table, "semi_major_axis"); |
|
|
|
|
toml_datum_t semi_latus = toml_get(orbit_table, "semi_latus_rectum"); |
|
|
|
|
|
|
|
|
|
// 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); |
|
|
|
|
if (!parse_toml_orbit(orbit_table, &craft->orbit, 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')\n", craft->name); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
craft->orbit.semi_latus_rectum = semi_latus.u.fp64; |
|
|
|
|
if (semi_major.type == TOML_FP64) { |
|
|
|
|
printf("Warning: Spacecraft '%s' has parabolic eccentricity, 'semi_latus_rectum' used instead of 'semi_major_axis'\n", craft->name); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// Elliptical or hyperbolic - requires semi_major_axis
|
|
|
|
|
if (semi_major.type == TOML_FP64) { |
|
|
|
|
craft->orbit.semi_major_axis = semi_major.u.fp64; |
|
|
|
|
} else { |
|
|
|
|
printf("Error: Spacecraft '%s' must have 'semi_major_axis' in orbit table (non-parabolic orbits)\n", craft->name); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
if (semi_latus.type == TOML_FP64) { |
|
|
|
|
printf("Warning: Spacecraft '%s' has non-parabolic eccentricity, 'semi_latus_rectum' ignored\n", craft->name); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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}; |
|
|
|
|
|