|
|
|
|
@ -9,64 +9,16 @@
|
|
|
|
|
|
|
|
|
|
// Configuration defaults - edit to change default run mode
|
|
|
|
|
#define DEFAULT_CONFIG_FILE "configs/test_simple.toml" |
|
|
|
|
#define DEFAULT_HEADLESS 0 // 0 = GUI mode, 1 = headless mode
|
|
|
|
|
#define DEFAULT_READABLE 1 // 0 = scientific notation, 1 = human-readable (AU, km/s)
|
|
|
|
|
#define DEFAULT_SIM_DAYS 365 // Default simulation duration for headless mode
|
|
|
|
|
|
|
|
|
|
// Unit conversion constants
|
|
|
|
|
const double AU = 1.496e11; // 1 AU in meters
|
|
|
|
|
const double KM = 1000.0; // 1 km in meters
|
|
|
|
|
|
|
|
|
|
// Helper functions for human-readable output
|
|
|
|
|
void print_position_readable(const char* name, Vec3 pos) { |
|
|
|
|
double dist_au = vec3_magnitude(pos) / AU; |
|
|
|
|
double x_au = pos.x / AU; |
|
|
|
|
double y_au = pos.y / AU; |
|
|
|
|
double z_au = pos.z / AU; |
|
|
|
|
|
|
|
|
|
// Calculate polar coordinates (angle in XY plane)
|
|
|
|
|
double angle_rad = atan2(pos.y, pos.x); |
|
|
|
|
double angle_deg = angle_rad * 180.0 / M_PI; |
|
|
|
|
if (angle_deg < 0.0) angle_deg += 360.0; // Convert to 0-360 range
|
|
|
|
|
|
|
|
|
|
printf("%s:\n", name); |
|
|
|
|
printf(" Position: (%.6f, %.6f, %.6f) AU\n", x_au, y_au, z_au); |
|
|
|
|
printf(" Polar (XY plane): r=%.6f AU, θ=%.2f°\n", dist_au, angle_deg); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void print_velocity_readable(const char* name, Vec3 vel) { |
|
|
|
|
double speed_km_s = vec3_magnitude(vel) / KM; |
|
|
|
|
printf(" Velocity magnitude: %.3f km/s\n", speed_km_s); |
|
|
|
|
printf(" Velocity: (%.3f, %.3f, %.3f) km/s\n", |
|
|
|
|
vel.x / KM, vel.y / KM, vel.z / KM); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void print_body_readable(CelestialBody* body) { |
|
|
|
|
print_position_readable(body->name, body->position); |
|
|
|
|
print_velocity_readable(body->name, body->velocity); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct ProgramArgs { |
|
|
|
|
const char* config_file; |
|
|
|
|
bool headless; |
|
|
|
|
bool readable; |
|
|
|
|
int sim_duration_days; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
void parse_command_line_args(int argc, char** argv, ProgramArgs* args) { |
|
|
|
|
args->config_file = DEFAULT_CONFIG_FILE; |
|
|
|
|
args->headless = DEFAULT_HEADLESS; |
|
|
|
|
args->readable = DEFAULT_READABLE; |
|
|
|
|
args->sim_duration_days = DEFAULT_SIM_DAYS; |
|
|
|
|
|
|
|
|
|
for (int i = 1; i < argc; i++) { |
|
|
|
|
if (strcmp(argv[i], "--headless") == 0 || strcmp(argv[i], "-h") == 0) { |
|
|
|
|
args->headless = true; |
|
|
|
|
} else if (strcmp(argv[i], "--readable") == 0 || strcmp(argv[i], "-r") == 0) { |
|
|
|
|
args->readable = true; |
|
|
|
|
} else if (strcmp(argv[i], "--days") == 0 && i + 1 < argc) { |
|
|
|
|
args->sim_duration_days = atoi(argv[++i]); |
|
|
|
|
} else if (argv[i][0] != '-') { |
|
|
|
|
if (argv[i][0] != '-') { |
|
|
|
|
args->config_file = argv[i]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -75,110 +27,6 @@ void parse_command_line_args(int argc, char** argv, ProgramArgs* args) {
|
|
|
|
|
void print_startup_info(const ProgramArgs* args) { |
|
|
|
|
printf("=== Orbital Mechanics Simulation ===\n"); |
|
|
|
|
printf("Loading configuration: %s\n", args->config_file); |
|
|
|
|
if (args->headless) { |
|
|
|
|
printf("Mode: Headless (terminal output only)\n"); |
|
|
|
|
printf("Duration: %d days\n", args->sim_duration_days); |
|
|
|
|
if (args->readable) { |
|
|
|
|
printf("Output: Human-readable units (AU, km/s)\n"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void run_headless_simulation(SimulationState* sim, const ProgramArgs* args) { |
|
|
|
|
const double SECONDS_PER_DAY = 86400.0; |
|
|
|
|
const double total_time = args->sim_duration_days * SECONDS_PER_DAY; |
|
|
|
|
const double output_interval = SECONDS_PER_DAY; |
|
|
|
|
double next_output_time = 0.0; |
|
|
|
|
|
|
|
|
|
CelestialBody* initial_state = (CelestialBody*)malloc(sim->body_count * sizeof(CelestialBody)); |
|
|
|
|
int* previous_parents = (int*)malloc(sim->body_count * sizeof(int)); |
|
|
|
|
for (int i = 0; i < sim->body_count; i++) { |
|
|
|
|
initial_state[i] = sim->bodies[i]; |
|
|
|
|
previous_parents[i] = sim->bodies[i].parent_index; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
printf("\n=== Initial State ===\n"); |
|
|
|
|
for (int i = 0; i < sim->body_count; i++) { |
|
|
|
|
CelestialBody* body = &sim->bodies[i]; |
|
|
|
|
if (args->readable) { |
|
|
|
|
print_body_readable(body); |
|
|
|
|
} else { |
|
|
|
|
printf("%s:\n", body->name); |
|
|
|
|
printf(" Position: (%.3e, %.3e, %.3e) m\n", |
|
|
|
|
body->position.x, body->position.y, body->position.z); |
|
|
|
|
printf(" Velocity: (%.3e, %.3e, %.3e) m/s\n", |
|
|
|
|
body->velocity.x, body->velocity.y, body->velocity.z); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
printf("\n=== Running Simulation ===\n"); |
|
|
|
|
while (sim->time < total_time) { |
|
|
|
|
update_simulation(sim); |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < sim->body_count; i++) { |
|
|
|
|
int current_parent = sim->bodies[i].parent_index; |
|
|
|
|
if (current_parent != previous_parents[i]) { |
|
|
|
|
printf("\n*** PARENT CHANGE at Day %.1f ***\n", sim->time / SECONDS_PER_DAY); |
|
|
|
|
printf(" Body: %s\n", sim->bodies[i].name); |
|
|
|
|
printf(" Old parent: %d", previous_parents[i]); |
|
|
|
|
if (previous_parents[i] >= 0) printf(" (%s)", sim->bodies[previous_parents[i]].name); |
|
|
|
|
printf("\n"); |
|
|
|
|
printf(" New parent: %d", current_parent); |
|
|
|
|
if (current_parent >= 0) printf(" (%s)", sim->bodies[current_parent].name); |
|
|
|
|
printf("\n\n"); |
|
|
|
|
previous_parents[i] = current_parent; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (sim->time >= next_output_time) { |
|
|
|
|
printf("Day %.1f: ", sim->time / SECONDS_PER_DAY); |
|
|
|
|
for (int i = 0; i < sim->body_count && i < 3; i++) { |
|
|
|
|
Vec3 pos = sim->bodies[i].position; |
|
|
|
|
double dist = vec3_magnitude(pos); |
|
|
|
|
if (args->readable) { |
|
|
|
|
double angle_rad = atan2(pos.y, pos.x); |
|
|
|
|
double angle_deg = angle_rad * 180.0 / M_PI; |
|
|
|
|
if (angle_deg < 0.0) angle_deg += 360.0; |
|
|
|
|
printf("%s(r=%.4f AU, θ=%.1f°) ", sim->bodies[i].name, dist / AU, angle_deg); |
|
|
|
|
} else { |
|
|
|
|
printf("%s=%.3e m ", sim->bodies[i].name, dist); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
printf("\n"); |
|
|
|
|
next_output_time += output_interval; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
printf("\n=== Initial State (Day 0.0) ===\n"); |
|
|
|
|
for (int i = 0; i < sim->body_count; i++) { |
|
|
|
|
CelestialBody* body = &initial_state[i]; |
|
|
|
|
if (args->readable) { |
|
|
|
|
print_body_readable(body); |
|
|
|
|
} else { |
|
|
|
|
printf("%s:\n", body->name); |
|
|
|
|
printf(" Position: (%.3e, %.3e, %.3e) m\n", |
|
|
|
|
body->position.x, body->position.y, body->position.z); |
|
|
|
|
printf(" Velocity: (%.3e, %.3e, %.3e) m/s\n", |
|
|
|
|
body->velocity.x, body->velocity.y, body->velocity.z); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
printf("\n=== Final State (Day %.1f) ===\n", sim->time / SECONDS_PER_DAY); |
|
|
|
|
for (int i = 0; i < sim->body_count; i++) { |
|
|
|
|
CelestialBody* body = &sim->bodies[i]; |
|
|
|
|
if (args->readable) { |
|
|
|
|
print_body_readable(body); |
|
|
|
|
} else { |
|
|
|
|
printf("%s:\n", body->name); |
|
|
|
|
printf(" Position: (%.3e, %.3e, %.3e) m\n", |
|
|
|
|
body->position.x, body->position.y, body->position.z); |
|
|
|
|
printf(" Velocity: (%.3e, %.3e, %.3e) m/s\n", |
|
|
|
|
body->velocity.x, body->velocity.y, body->velocity.z); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
free(initial_state); |
|
|
|
|
free(previous_parents); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void run_gui_simulation(SimulationState* sim) { |
|
|
|
|
@ -249,11 +97,7 @@ int main(int argc, char** argv) {
|
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (args.headless) { |
|
|
|
|
run_headless_simulation(sim, &args); |
|
|
|
|
} else { |
|
|
|
|
run_gui_simulation(sim); |
|
|
|
|
} |
|
|
|
|
run_gui_simulation(sim); |
|
|
|
|
|
|
|
|
|
destroy_simulation(sim); |
|
|
|
|
return 0; |
|
|
|
|
|