Browse Source

Merge maneuver execution into single spacecraft propagation pass

Consolidate execute_pending_maneuvers() into update_spacecraft_physics()
so every spacecraft goes through exactly one propagation path.

Changes:
- Remove spacecraft_handled_this_frame[256] static array
- Remove reset_spacecraft_tracking() function
- Remove execute_pending_maneuvers() function
- Check maneuver triggers before propagation in update_spacecraft_physics
- Propagate to burn time, execute burn, propagate remainder (same order
  as old code)
- Remove execute_pending_maneuvers declaration from simulation.h

Benefits:
- Single propagation call per spacecraft per frame (was 2 paths)
- No static array with magic number
- Simpler call chain: no separate maneuver pass
- Enables sub-step interpolation for true-anomaly triggers
- Sets up foundation for interpolated time triggers

Adds TODO in update_spacecraft_physics about testing interpolated burns.

All 154 tests pass (240,445 assertions).
main
cinnaboot 3 months ago
parent
commit
22727bbe22
  1. 83
      src/simulation.cpp
  2. 1
      src/simulation.h

83
src/simulation.cpp

@ -8,15 +8,6 @@
#include <cstdio>
#include <cmath>
// FIXME: I'm not a fan of this
static bool spacecraft_handled_this_frame[256];
static void reset_spacecraft_tracking(int max_craft) {
for (int i = 0; i < max_craft && i < 256; i++) {
spacecraft_handled_this_frame[i] = false;
}
}
// Create a new simulation
SimulationState* create_simulation(int max_bodies, int max_craft, int max_maneuvers, double time_step) {
SimulationState* sim = (SimulationState*)malloc(sizeof(SimulationState));
@ -172,10 +163,8 @@ void update_soi(CelestialBody* body, CelestialBody* parent, double semi_major_ax
}
void update_simulation(SimulationState* sim) {
reset_spacecraft_tracking(sim->max_craft);
update_bodies_physics(sim);
compute_global_coordinates(sim);
execute_pending_maneuvers(sim);
update_spacecraft_physics(sim);
compute_spacecraft_globals(sim);
sim->time += sim->dt;
@ -298,10 +287,6 @@ void update_spacecraft_physics(SimulationState* sim) {
continue;
}
if (spacecraft_handled_this_frame[i]) {
continue;
}
CelestialBody* parent = &sim->bodies[craft->parent_index];
Vec3 expected_pos, expected_vel;
@ -312,46 +297,46 @@ void update_spacecraft_physics(SimulationState* sim) {
craft->orbit = cartesian_to_orbital_elements(craft->local_position, craft->local_velocity, parent->mass);
}
craft->orbit = propagate_orbital_elements(craft->orbit, sim->dt, parent->mass);
orbital_elements_to_cartesian(craft->orbit, parent->mass, &craft->local_position, &craft->local_velocity);
}
}
void execute_pending_maneuvers(SimulationState* sim) {
for (int i = 0; i < sim->maneuver_count; i++) {
Maneuver* maneuver = &sim->maneuvers[i];
if (maneuver->executed) {
continue;
}
if (maneuver->craft_index < 0 || maneuver->craft_index >= sim->craft_count) {
continue;
}
Spacecraft* craft = &sim->spacecraft[maneuver->craft_index];
if (craft->parent_index < 0 || craft->parent_index >= sim->body_count) {
continue;
// Check if any pending maneuver fires this frame. If so, propagate
// to the burn time, execute the burn, then propagate the remaining
// timestep. This enables sub-step interpolation for true-anomaly
// triggers and sets up future interpolated time triggers.
// TODO: Test interpolated burns for TRIGGER_TIME — currently only
// TRIGGER_TRUE_ANOMALY provides sub-step timing via scheduled_dt.
// For time triggers, scheduled_dt is always 0, so the burn applies
// at sim->time (step boundary). Could compute dt_to_burn =
// trigger_value - (sim->time - sim->dt) for exact placement.
bool maneuver_fired = false;
double burn_dt = 0.0;
Maneuver* fired_maneuver = NULL;
for (int j = 0; j < sim->maneuver_count; j++) {
Maneuver* maneuver = &sim->maneuvers[j];
if (maneuver->executed) {
continue;
}
if (maneuver->craft_index != i) {
continue;
}
if (check_maneuver_trigger(maneuver, craft, sim)) {
burn_dt = maneuver->scheduled_dt;
fired_maneuver = maneuver;
maneuver_fired = true;
break;
}
}
if (check_maneuver_trigger(maneuver, craft, sim)) {
CelestialBody* parent = &sim->bodies[craft->parent_index];
double dt_to_burn = maneuver->scheduled_dt;
if (dt_to_burn > 0.0) {
craft->orbit = propagate_orbital_elements(craft->orbit, dt_to_burn, parent->mass);
orbital_elements_to_cartesian(craft->orbit, parent->mass, &craft->local_position, &craft->local_velocity);
}
if (maneuver_fired) {
craft->orbit = propagate_orbital_elements(craft->orbit, burn_dt, parent->mass);
orbital_elements_to_cartesian(craft->orbit, parent->mass, &craft->local_position, &craft->local_velocity);
execute_maneuver(maneuver, craft, sim, sim->time + dt_to_burn);
execute_maneuver(fired_maneuver, craft, sim, sim->time + burn_dt);
double remaining_dt = sim->dt - dt_to_burn;
double remaining_dt = sim->dt - burn_dt;
craft->orbit = propagate_orbital_elements(craft->orbit, remaining_dt, parent->mass);
orbital_elements_to_cartesian(craft->orbit, parent->mass, &craft->local_position, &craft->local_velocity);
spacecraft_handled_this_frame[maneuver->craft_index] = true;
maneuver->scheduled_dt = 0.0;
} else {
craft->orbit = propagate_orbital_elements(craft->orbit, sim->dt, parent->mass);
orbital_elements_to_cartesian(craft->orbit, parent->mass, &craft->local_position, &craft->local_velocity);
}
}
}

1
src/simulation.h

@ -47,7 +47,6 @@ void compute_global_coordinates(SimulationState* sim);
// Simulation update helper functions
void update_bodies_physics(SimulationState* sim);
void update_spacecraft_physics(SimulationState* sim);
void execute_pending_maneuvers(SimulationState* sim);
void compute_spacecraft_globals(SimulationState* sim);
// Initialize orbital objects from orbital elements

Loading…
Cancel
Save