diff --git a/src/config_loader.cpp b/src/config_loader.cpp index 182a819..d9b024b 100644 --- a/src/config_loader.cpp +++ b/src/config_loader.cpp @@ -171,7 +171,7 @@ bool load_system_config(SimulationState* sim, const char* filepath) { toml_free(result); return false; } - + // Load maneuvers from the same config file (before freeing TOML data) if (!load_maneuvers_from_toml(sim, result)) { toml_free(result); @@ -265,7 +265,7 @@ static bool parse_toml_spacecraft(toml_datum_t craft_table, Spacecraft* craft) { craft->local_velocity = {0.0, 0.0, 0.0}; } craft->velocity = craft->local_velocity; - + return true; } @@ -276,12 +276,12 @@ static bool parse_toml_maneuver(toml_datum_t maneuver_table, Maneuver* maneuver, } strncpy(maneuver->name, name.u.s, 63); maneuver->name[63] = '\0'; - + toml_datum_t spacecraft_name = toml_get(maneuver_table, "spacecraft_name"); if (spacecraft_name.type != TOML_STRING) { return false; } - + int craft_idx = -1; for (int i = 0; i < sim->craft_count; i++) { if (strcmp(sim->spacecraft[i].name, spacecraft_name.u.s) == 0) { @@ -289,20 +289,20 @@ static bool parse_toml_maneuver(toml_datum_t maneuver_table, Maneuver* maneuver, break; } } - + if (craft_idx < 0) { printf("Error: Maneuver '%s' references non-existent spacecraft '%s'\n", maneuver->name, spacecraft_name.u.s); return false; } - + maneuver->craft_index = craft_idx; - + toml_datum_t trigger_type_str = toml_get(maneuver_table, "trigger_type"); if (trigger_type_str.type != TOML_STRING) { return false; } - + if (strcmp(trigger_type_str.u.s, "time") == 0) { maneuver->trigger_type = TRIGGER_TIME; } else if (strcmp(trigger_type_str.u.s, "true_anomaly") == 0) { @@ -312,18 +312,18 @@ static bool parse_toml_maneuver(toml_datum_t maneuver_table, Maneuver* maneuver, trigger_type_str.u.s, maneuver->name); return false; } - + toml_datum_t trigger_value = toml_get(maneuver_table, "trigger_value"); if (trigger_value.type != TOML_FP64 && trigger_value.type != TOML_INT64) { return false; } maneuver->trigger_value = trigger_value.type == TOML_FP64 ? trigger_value.u.fp64 : (double)trigger_value.u.int64; - + toml_datum_t direction_str = toml_get(maneuver_table, "direction"); if (direction_str.type != TOML_STRING) { return false; } - + if (strcmp(direction_str.u.s, "prograde") == 0) { maneuver->direction = BURN_PROGRADE; } else if (strcmp(direction_str.u.s, "retrograde") == 0) { @@ -341,16 +341,16 @@ static bool parse_toml_maneuver(toml_datum_t maneuver_table, Maneuver* maneuver, direction_str.u.s, maneuver->name); return false; } - + toml_datum_t delta_v = toml_get(maneuver_table, "delta_v"); if (delta_v.type != TOML_FP64 && delta_v.type != TOML_INT64) { return false; } maneuver->delta_v = delta_v.type == TOML_FP64 ? delta_v.u.fp64 : (double)delta_v.u.int64; - + maneuver->executed = false; maneuver->executed_time = 0.0; - + return true; } @@ -359,18 +359,18 @@ static bool load_maneuvers_from_toml(SimulationState* sim, toml_result_t result) if (maneuvers.type != TOML_ARRAY) { return true; } - + int maneuver_count = maneuvers.u.arr.size; if (maneuver_count == 0) { return true; } - + if (maneuver_count > sim->max_maneuvers) { printf("Error: Too many maneuvers (%d) for simulation (max: %d)\n", maneuver_count, sim->max_maneuvers); return false; } - + for (int i = 0; i < maneuver_count; i++) { Maneuver maneuver; toml_datum_t maneuver_table = maneuvers.u.arr.elem[i]; @@ -378,7 +378,7 @@ static bool load_maneuvers_from_toml(SimulationState* sim, toml_result_t result) printf("Error: Failed to parse maneuver at index %d\n", i); return false; } - + for (int j = 0; j < sim->maneuver_count; j++) { if (strcmp(sim->maneuvers[j].name, maneuver.name) == 0) { printf("Error: Duplicate maneuver name '%s' found at index %d\n", @@ -386,11 +386,11 @@ static bool load_maneuvers_from_toml(SimulationState* sim, toml_result_t result) return false; } } - + sim->maneuvers[sim->maneuver_count] = maneuver; sim->maneuver_count++; } - + printf("Loaded %d maneuvers from %s\n", maneuver_count, sim->config_name); return true; } diff --git a/src/maneuver.cpp b/src/maneuver.cpp index 224b47e..5fa1eae 100644 --- a/src/maneuver.cpp +++ b/src/maneuver.cpp @@ -55,9 +55,9 @@ Vec3 get_burn_direction_vector(BurnDirection direction, Vec3 local_pos, Vec3 loc void apply_impulsive_burn(Spacecraft* craft, BurnDirection direction, double delta_v) { Vec3 dir = get_burn_direction_vector(direction, craft->local_position, craft->local_velocity); - + Vec3 delta_v_vec = vec3_scale(dir, delta_v); - + craft->local_velocity = vec3_add(craft->local_velocity, delta_v_vec); } @@ -74,36 +74,36 @@ bool check_maneuver_trigger(Maneuver* maneuver, Spacecraft* craft, SimulationSta switch (maneuver->trigger_type) { case TRIGGER_TIME: return sim->time >= maneuver->trigger_value; - + case TRIGGER_TRUE_ANOMALY: { Vec3 r = craft->local_position; Vec3 v = craft->local_velocity; - + double r_mag = vec3_magnitude(r); double v_mag = vec3_magnitude(v); - + if (r_mag < 1.0) { return false; } - + Vec3 r_unit = vec3_scale(r, 1.0 / r_mag); - + Vec3 h = vec3_cross(r, v); double h_mag = vec3_magnitude(h); - + if (h_mag < 1e-10) { return false; } - + Vec3 h_unit = vec3_scale(h, 1.0 / h_mag); - + Vec3 e_vec = {0.0, 0.0, 0.0}; double mu = 0.0; - + if (craft->parent_index >= 0 && craft->parent_index < sim->body_count) { CelestialBody* parent = &sim->bodies[craft->parent_index]; mu = G * parent->mass; - + Vec3 v_cross_h = vec3_cross(v, h); Vec3 v_cross_h_over_mu = vec3_scale(v_cross_h, 1.0 / mu); Vec3 r_over_mag = vec3_scale(r, 1.0 / r_mag); @@ -111,58 +111,58 @@ bool check_maneuver_trigger(Maneuver* maneuver, Spacecraft* craft, SimulationSta } else { return false; } - + double e_mag = vec3_magnitude(e_vec); - + if (e_mag < 1e-10) { Vec3 v_unit = vec3_scale(v, 1.0 / v_mag); double cos_nu = vec3_dot(r_unit, v_unit); cos_nu = fmax(-1.0, fmin(1.0, cos_nu)); double nu = acos(cos_nu); - + double target_nu = maneuver->trigger_value; while (target_nu < 0) target_nu += 2.0 * M_PI; while (target_nu >= 2.0 * M_PI) target_nu -= 2.0 * M_PI; - + double nu_normalized = nu; while (nu_normalized < 0) nu_normalized += 2.0 * M_PI; while (nu_normalized >= 2.0 * M_PI) nu_normalized -= 2.0 * M_PI; - + double angle_diff = fabs(nu_normalized - target_nu); if (angle_diff > M_PI) { angle_diff = 2.0 * M_PI - angle_diff; } - + return angle_diff < 0.01; } - + double cos_nu = vec3_dot(e_vec, r) / (e_mag * r_mag); cos_nu = fmax(-1.0, fmin(1.0, cos_nu)); double nu = acos(cos_nu); - + Vec3 r_cross_v = vec3_cross(r, v); double r_cross_v_dot_e = vec3_dot(r_cross_v, e_vec); - + if (r_cross_v_dot_e < 0) { nu = 2.0 * M_PI - nu; } - + double target_nu = maneuver->trigger_value; while (target_nu < 0) target_nu += 2.0 * M_PI; while (target_nu >= 2.0 * M_PI) target_nu -= 2.0 * M_PI; - + double nu_normalized = nu; while (nu_normalized < 0) nu_normalized += 2.0 * M_PI; while (nu_normalized >= 2.0 * M_PI) nu_normalized -= 2.0 * M_PI; - + double angle_diff = fabs(nu_normalized - target_nu); if (angle_diff > M_PI) { angle_diff = 2.0 * M_PI - angle_diff; } - + return angle_diff < 0.01; } - + default: return false; } diff --git a/src/simulation.cpp b/src/simulation.cpp index 020f034..b508095 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -11,19 +11,19 @@ SimulationState* create_simulation(int max_bodies, int max_craft, int max_maneuvers, double time_step) { SimulationState* sim = (SimulationState*)malloc(sizeof(SimulationState)); sim->bodies = (CelestialBody*)malloc(sizeof(CelestialBody) * max_bodies); - + if (max_craft > 0) { sim->spacecraft = (Spacecraft*)malloc(sizeof(Spacecraft) * max_craft); } else { sim->spacecraft = NULL; } - + if (max_maneuvers > 0) { sim->maneuvers = (Maneuver*)malloc(sizeof(Maneuver) * max_maneuvers); } else { sim->maneuvers = NULL; } - + sim->body_count = 0; sim->max_bodies = max_bodies; sim->craft_count = 0; diff --git a/src/simulation.h b/src/simulation.h index 276d696..e598d13 100644 --- a/src/simulation.h +++ b/src/simulation.h @@ -27,15 +27,15 @@ struct SimulationState { CelestialBody* bodies; int body_count; int max_bodies; - + Spacecraft* spacecraft; int craft_count; int max_craft; - + Maneuver* maneuvers; int maneuver_count; int max_maneuvers; - + double time; double dt; char config_name[256]; diff --git a/tests/test_maneuver_planning.cpp b/tests/test_maneuver_planning.cpp index 4afc84f..4598566 100644 --- a/tests/test_maneuver_planning.cpp +++ b/tests/test_maneuver_planning.cpp @@ -61,18 +61,18 @@ TEST_CASE("True anomaly trigger executes at correct angle", "[maneuver][trigger] REQUIRE(!sim->maneuvers[1].executed); double first_burn_velocity = 0.0; - + const double FIRST_BURN_TIME = 3600.0; while (sim->time < FIRST_BURN_TIME) { update_simulation(sim); } - + first_burn_velocity = vec3_magnitude(sim->spacecraft[0].local_velocity); const double TARGET_ANOMALY = 3.14159; (void)TARGET_ANOMALY; double max_sim_time = FIRST_BURN_TIME + 72000.0; - + while (sim->time < max_sim_time) { update_simulation(sim); if (sim->maneuvers[1].executed) { @@ -83,11 +83,11 @@ TEST_CASE("True anomaly trigger executes at correct angle", "[maneuver][trigger] REQUIRE(sim->maneuvers[1].executed); double second_burn_velocity = vec3_magnitude(sim->spacecraft[0].local_velocity); - double second_burn_kinetic_energy = 0.5 * sim->spacecraft[0].mass * + double second_burn_kinetic_energy = 0.5 * sim->spacecraft[0].mass * second_burn_velocity * second_burn_velocity; - double first_burn_kinetic_energy = 0.5 * sim->spacecraft[0].mass * + double first_burn_kinetic_energy = 0.5 * sim->spacecraft[0].mass * first_burn_velocity * first_burn_velocity; - + REQUIRE(second_burn_kinetic_energy > first_burn_kinetic_energy); destroy_simulation(sim); @@ -132,13 +132,13 @@ TEST_CASE("Duplicate maneuver names fail config load", "[maneuver][config][error Maneuver duplicate_maneuver = sim->maneuvers[0]; sim->maneuvers[sim->maneuver_count] = duplicate_maneuver; - + (void)sim->maneuver_count; sim->maneuver_count++; - bool is_duplicate = (std::string(sim->maneuvers[0].name) == + bool is_duplicate = (std::string(sim->maneuvers[0].name) == std::string(sim->maneuvers[2].name)); - + REQUIRE(is_duplicate); destroy_simulation(sim);