diff --git a/src/config_loader.cpp b/src/config_loader.cpp index 85f02d3..a6aad15 100644 --- a/src/config_loader.cpp +++ b/src/config_loader.cpp @@ -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};