Browse Source

Phase 2: Update data structures with global_position/global_velocity

- Rename CelestialBody/Spacecraft position/velocity to global_*
- Add OrbitalElements struct to both bodies and spacecraft
- Rename old OrbitalElements to OrbitalMetrics (for output/analysis)
- Update all references throughout codebase
- Preserve parent_index in outer structs (not in OrbitalElements)
- Build succeeds with only unused variable warning
main
cinnaboot 6 months ago
parent
commit
121f1b9d29
  1. 13
      docs/unified_orbital_elements_plan.md
  2. 18
      src/config_loader.cpp
  3. 22
      src/renderer.cpp
  4. 90
      src/simulation.cpp
  5. 27
      src/simulation.h
  6. 14
      src/spacecraft.h
  7. 12
      src/ui_renderer.cpp

13
docs/unified_orbital_elements_plan.md

@ -199,29 +199,30 @@ struct Spacecraft {
- Unit tests for parabolic/hyperbolic conversion - Unit tests for parabolic/hyperbolic conversion
- Verify velocity magnitudes match vis-viva equation - Verify velocity magnitudes match vis-viva equation
### Phase 2: Update Data Structures ### Phase 2: Update Data Structures ✅ COMPLETE
4. **Modify `CelestialBody` struct (simulation.h)** 4. **Modify `CelestialBody` struct (simulation.h)**
- Add `OrbitalElements orbit` field - Add `OrbitalElements orbit` field
- Rename `position``global_position` - Rename `position``global_position`
- Rename `velocity``global_velocity` - Rename `velocity``global_velocity`
- Keep `local_position`, `local_velocity`, `soi_radius`, `parent_index`, `color` - Keep `local_position`, `local_velocity`, `soi_radius`, `parent_index`, `color`
5. **Modify `Spacecraft` struct (spacecraft.h)** 5. **Modify `Spacecraft` struct (spacecraft.h)**
- Add `OrbitalElements orbit` field - Add `OrbitalElements orbit` field
- Rename `position``global_position` - Rename `position``global_position`
- Rename `velocity``global_velocity` - Rename `velocity``global_velocity`
- Keep `local_position`, `local_velocity`, `parent_index`, `mass`, `name` - Keep `local_position`, `local_velocity`, `parent_index`, `mass`, `name`
6. **Update all references to position/velocity throughout codebase** 6. **Update all references to position/velocity throughout codebase**
- `simulation.cpp`: Update all `body->position``body->global_position` - `simulation.cpp`: Update all `body->position``body->global_position`
- `simulation.cpp`: Update all `body->velocity``body->global_velocity` - `simulation.cpp`: Update all `body->velocity``body->global_velocity`
- `simulation.cpp`: Update all `craft->position``craft->global_position` - `simulation.cpp`: Update all `craft->position``craft->global_position`
- `simulation.cpp`: Update all `craft->velocity``craft->global_velocity` - `simulation.cpp`: Update all `craft->velocity``craft->global_velocity`
- `renderer.cpp`: Update references (mostly OK, uses `position` and `velocity` params) - Rename old `OrbitalElements` to `OrbitalMetrics` (for output/analysis)
- `renderer.cpp`: Update references
- `ui_renderer.cpp`: Update references for display - `ui_renderer.cpp`: Update references for display
- `config_loader.cpp`: Update parsing logic - `config_loader.cpp`: Update parsing logic
- `maneuver.cpp`: Update if needed - `maneuver.cpp`: No changes needed
### Phase 3: Update Config Parser ### Phase 3: Update Config Parser

18
src/config_loader.cpp

@ -72,12 +72,12 @@ static bool parse_toml_body(toml_datum_t body_table, CelestialBody* body) {
body->mass = mass.u.fp64; body->mass = mass.u.fp64;
body->radius = radius.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); body->parent_index = (int)(parent_idx.type == TOML_INT64 ? parent_idx.u.int64 : (int)parent_idx.u.fp64);
body->eccentricity = eccentricity.u.fp64; body->orbit.eccentricity = eccentricity.u.fp64;
body->semi_major_axis = semi_major.u.fp64; body->orbit.semi_major_axis = semi_major.u.fp64;
// Extract position vector // Extract position vector
toml_datum_t position = toml_get(body_table, "position"); toml_datum_t position = toml_get(body_table, "position");
if (position.type != TOML_TABLE || !extract_vec3_from_table(position, &body->position)) { if (position.type != TOML_TABLE || !extract_vec3_from_table(position, &body->global_position)) {
return false; return false;
} }
@ -88,7 +88,7 @@ static bool parse_toml_body(toml_datum_t body_table, CelestialBody* body) {
} }
// Initialize velocity (will be calculated later) // Initialize velocity (will be calculated later)
body->velocity = {0.0, 0.0, 0.0}; body->global_velocity = {0.0, 0.0, 0.0};
body->soi_radius = 0.0; body->soi_radius = 0.0;
return true; return true;
@ -147,7 +147,7 @@ bool load_system_config(SimulationState* sim, const char* filepath) {
CelestialBody* body = &sim->bodies[i]; CelestialBody* body = &sim->bodies[i];
CelestialBody* parent = &sim->bodies[body->parent_index]; CelestialBody* parent = &sim->bodies[body->parent_index];
double distance = vec3_distance(body->position, parent->position); double distance = vec3_distance(body->global_position, parent->global_position);
double min_distance = parent->radius + body->radius; double min_distance = parent->radius + body->radius;
if (distance < min_distance) { if (distance < min_distance) {
@ -218,8 +218,8 @@ static bool load_spacecraft_from_toml(SimulationState* sim, toml_result_t result
} }
CelestialBody* parent = &sim->bodies[craft.parent_index]; CelestialBody* parent = &sim->bodies[craft.parent_index];
craft.position = vec3_add(parent->position, craft.local_position); craft.global_position = vec3_add(parent->global_position, craft.local_position);
craft.velocity = vec3_add(parent->velocity, craft.local_velocity); craft.global_velocity = vec3_add(parent->global_velocity, craft.local_velocity);
int idx = add_spacecraft(sim, &craft); int idx = add_spacecraft(sim, &craft);
if (idx < 0) { if (idx < 0) {
@ -254,7 +254,7 @@ static bool parse_toml_spacecraft(toml_datum_t craft_table, Spacecraft* craft) {
if (position.type != TOML_TABLE || !extract_vec3_from_table(position, &craft->local_position)) { if (position.type != TOML_TABLE || !extract_vec3_from_table(position, &craft->local_position)) {
return false; return false;
} }
craft->position = craft->local_position; craft->global_position = craft->local_position;
toml_datum_t velocity = toml_get(craft_table, "velocity"); toml_datum_t velocity = toml_get(craft_table, "velocity");
if (velocity.type == TOML_TABLE) { if (velocity.type == TOML_TABLE) {
@ -264,7 +264,7 @@ static bool parse_toml_spacecraft(toml_datum_t craft_table, Spacecraft* craft) {
} else { } else {
craft->local_velocity = {0.0, 0.0, 0.0}; craft->local_velocity = {0.0, 0.0, 0.0};
} }
craft->velocity = craft->local_velocity; craft->global_velocity = craft->local_velocity;
return true; return true;
} }

22
src/renderer.cpp

@ -105,12 +105,12 @@ void update_camera(RenderState* render_state, SimulationState* sim) {
// Just started following - store current offset // Just started following - store current offset
if (render_state->selected_body_index >= 0 && render_state->selected_body_index < sim->body_count) { if (render_state->selected_body_index >= 0 && render_state->selected_body_index < sim->body_count) {
CelestialBody* body = &sim->bodies[render_state->selected_body_index]; CelestialBody* body = &sim->bodies[render_state->selected_body_index];
Vector3 body_pos = sim_to_render(body->position, render_state->distance_scale); Vector3 body_pos = sim_to_render(body->global_position, render_state->distance_scale);
render_state->camera.target = body_pos; render_state->camera.target = body_pos;
render_state->camera_offset = Vector3Subtract(render_state->camera.position, body_pos); render_state->camera_offset = Vector3Subtract(render_state->camera.position, body_pos);
} else if (render_state->selected_craft_index >= 0 && render_state->selected_craft_index < sim->craft_count) { } else if (render_state->selected_craft_index >= 0 && render_state->selected_craft_index < sim->craft_count) {
Spacecraft* craft = &sim->spacecraft[render_state->selected_craft_index]; Spacecraft* craft = &sim->spacecraft[render_state->selected_craft_index];
Vector3 craft_pos = sim_to_render(craft->position, render_state->distance_scale); Vector3 craft_pos = sim_to_render(craft->global_position, render_state->distance_scale);
render_state->camera.target = craft_pos; render_state->camera.target = craft_pos;
render_state->camera_offset = Vector3Subtract(render_state->camera.position, craft_pos); render_state->camera_offset = Vector3Subtract(render_state->camera.position, craft_pos);
} }
@ -122,12 +122,12 @@ void update_camera(RenderState* render_state, SimulationState* sim) {
render_state->selected_body_index != render_state->previous_selected_body && render_state->selected_body_index != render_state->previous_selected_body &&
render_state->selected_body_index < sim->body_count) { render_state->selected_body_index < sim->body_count) {
// Body selection changed - recalculate offset to maintain distance // Body selection changed - recalculate offset to maintain distance
Vector3 body_pos = sim_to_render(sim->bodies[render_state->selected_body_index].position, render_state->distance_scale); Vector3 body_pos = sim_to_render(sim->bodies[render_state->selected_body_index].global_position, render_state->distance_scale);
render_state->camera.target = body_pos; render_state->camera.target = body_pos;
render_state->camera.position = Vector3Add(body_pos, render_state->camera_offset); render_state->camera.position = Vector3Add(body_pos, render_state->camera_offset);
} else if (render_state->selected_craft_index >= 0 && sim->craft_count > 0) { } else if (render_state->selected_craft_index >= 0 && sim->craft_count > 0) {
// Spacecraft selected - update camera to follow it // Spacecraft selected - update camera to follow it
Vector3 craft_pos = sim_to_render(sim->spacecraft[render_state->selected_craft_index].position, render_state->distance_scale); Vector3 craft_pos = sim_to_render(sim->spacecraft[render_state->selected_craft_index].global_position, render_state->distance_scale);
render_state->camera.target = craft_pos; render_state->camera.target = craft_pos;
render_state->camera.position = Vector3Add(craft_pos, render_state->camera_offset); render_state->camera.position = Vector3Add(craft_pos, render_state->camera_offset);
} }
@ -137,7 +137,7 @@ void update_camera(RenderState* render_state, SimulationState* sim) {
if (render_state->camera_follow_body && render_state->selected_body_index >= 0 && if (render_state->camera_follow_body && render_state->selected_body_index >= 0 &&
render_state->selected_body_index < sim->body_count) { render_state->selected_body_index < sim->body_count) {
CelestialBody* body = &sim->bodies[render_state->selected_body_index]; CelestialBody* body = &sim->bodies[render_state->selected_body_index];
Vector3 body_pos = sim_to_render(body->position, render_state->distance_scale); Vector3 body_pos = sim_to_render(body->global_position, render_state->distance_scale);
render_state->camera.target = body_pos; render_state->camera.target = body_pos;
render_state->camera.position = Vector3Add(body_pos, render_state->camera_offset); render_state->camera.position = Vector3Add(body_pos, render_state->camera_offset);
} }
@ -146,7 +146,7 @@ void update_camera(RenderState* render_state, SimulationState* sim) {
if (render_state->camera_follow_body && render_state->selected_craft_index >= 0 && if (render_state->camera_follow_body && render_state->selected_craft_index >= 0 &&
render_state->selected_craft_index < sim->craft_count) { render_state->selected_craft_index < sim->craft_count) {
Spacecraft* craft = &sim->spacecraft[render_state->selected_craft_index]; Spacecraft* craft = &sim->spacecraft[render_state->selected_craft_index];
Vector3 craft_pos = sim_to_render(craft->position, render_state->distance_scale); Vector3 craft_pos = sim_to_render(craft->global_position, render_state->distance_scale);
render_state->camera.target = craft_pos; render_state->camera.target = craft_pos;
render_state->camera.position = Vector3Add(craft_pos, render_state->camera_offset); render_state->camera.position = Vector3Add(craft_pos, render_state->camera_offset);
} }
@ -255,7 +255,7 @@ float scale_radius(double radius, double scale) {
// Render a single celestial body // Render a single celestial body
void render_body(CelestialBody* body, RenderState* render_state) { void render_body(CelestialBody* body, RenderState* render_state) {
Vector3 position = sim_to_render(body->position, render_state->distance_scale); Vector3 position = sim_to_render(body->global_position, render_state->distance_scale);
float radius = scale_radius(body->radius, render_state->size_scale); float radius = scale_radius(body->radius, render_state->size_scale);
Color color = { Color color = {
@ -269,7 +269,7 @@ void render_body(CelestialBody* body, RenderState* render_state) {
} }
void render_spacecraft_screen_space(Spacecraft* craft, RenderState* render_state) { void render_spacecraft_screen_space(Spacecraft* craft, RenderState* render_state) {
Vector3 render_pos = sim_to_render(craft->position, render_state->distance_scale); Vector3 render_pos = sim_to_render(craft->global_position, render_state->distance_scale);
Vector2 screen_pos = GetWorldToScreen(render_pos, render_state->camera); Vector2 screen_pos = GetWorldToScreen(render_pos, render_state->camera);
int screen_width = GetScreenWidth(); int screen_width = GetScreenWidth();
@ -304,7 +304,7 @@ void render_maneuver_marker_screen_space(Spacecraft* craft, Maneuver* maneuver,
return; return;
} }
Vector3 render_pos = sim_to_render(craft->position, render_state->distance_scale); Vector3 render_pos = sim_to_render(craft->global_position, render_state->distance_scale);
Vector2 screen_pos = GetWorldToScreen(render_pos, render_state->camera); Vector2 screen_pos = GetWorldToScreen(render_pos, render_state->camera);
int screen_width = GetScreenWidth(); int screen_width = GetScreenWidth();
@ -543,7 +543,7 @@ void render_simulation(SimulationState* sim, RenderState* render_state) {
CelestialBody* body = &sim->bodies[i]; CelestialBody* body = &sim->bodies[i];
if (body->parent_index >= 0 && body->parent_index < sim->body_count) { if (body->parent_index >= 0 && body->parent_index < sim->body_count) {
CelestialBody* parent = &sim->bodies[body->parent_index]; CelestialBody* parent = &sim->bodies[body->parent_index];
render_orbit(body->position, body->local_velocity, parent->position, render_orbit(body->global_position, body->local_velocity, parent->global_position,
parent->mass, get_body_orbit_color(body), render_state); parent->mass, get_body_orbit_color(body), render_state);
} }
} }
@ -553,7 +553,7 @@ void render_simulation(SimulationState* sim, RenderState* render_state) {
Spacecraft* craft = &sim->spacecraft[i]; Spacecraft* craft = &sim->spacecraft[i];
if (craft->parent_index >= 0 && craft->parent_index < sim->body_count) { if (craft->parent_index >= 0 && craft->parent_index < sim->body_count) {
CelestialBody* parent = &sim->bodies[craft->parent_index]; CelestialBody* parent = &sim->bodies[craft->parent_index];
render_orbit(craft->position, craft->local_velocity, parent->position, render_orbit(craft->global_position, craft->local_velocity, parent->global_position,
parent->mass, (Color){0, 255, 255, 128}, render_state); parent->mass, (Color){0, 255, 255, 128}, render_state);
} }
} }

90
src/simulation.cpp

@ -81,22 +81,22 @@ int add_body_to_simulation(SimulationState* sim, CelestialBody* body) {
if (body->parent_index >= 0 && body->parent_index < sim->body_count) { if (body->parent_index >= 0 && body->parent_index < sim->body_count) {
CelestialBody* parent = &sim->bodies[body->parent_index]; CelestialBody* parent = &sim->bodies[body->parent_index];
sim->bodies[new_idx].local_position = vec3_sub(body->position, parent->position); sim->bodies[new_idx].local_position = vec3_sub(body->global_position, parent->global_position);
sim->bodies[new_idx].local_velocity = vec3_sub(body->velocity, parent->velocity); sim->bodies[new_idx].local_velocity = vec3_sub(body->global_velocity, parent->global_velocity);
} else { } else {
sim->bodies[new_idx].local_position = body->position; sim->bodies[new_idx].local_position = body->global_position;
sim->bodies[new_idx].local_velocity = body->velocity; sim->bodies[new_idx].local_velocity = body->global_velocity;
} }
if (body->parent_index >= 0 && body->parent_index < sim->body_count) { if (body->parent_index >= 0 && body->parent_index < sim->body_count) {
CelestialBody* parent = &sim->bodies[body->parent_index]; CelestialBody* parent = &sim->bodies[body->parent_index];
update_soi(&sim->bodies[new_idx], parent, body->semi_major_axis); update_soi(&sim->bodies[new_idx], parent, body->orbit.semi_major_axis);
} else { } else {
sim->bodies[new_idx].soi_radius = 1e15; sim->bodies[new_idx].soi_radius = 1e15;
} }
sim->bodies[new_idx].position = body->position; sim->bodies[new_idx].global_position = body->global_position;
sim->bodies[new_idx].velocity = body->velocity; sim->bodies[new_idx].global_velocity = body->global_velocity;
return new_idx; return new_idx;
} }
@ -116,7 +116,7 @@ int find_dominant_body(SimulationState* sim, int body_index) {
} }
CelestialBody* parent = &sim->bodies[parent_idx]; CelestialBody* parent = &sim->bodies[parent_idx];
double distance = vec3_distance(body->position, parent->position); double distance = vec3_distance(body->global_position, parent->global_position);
// Stay with parent if within SOI, otherwise go to Sun // Stay with parent if within SOI, otherwise go to Sun
if (distance < parent->soi_radius) { if (distance < parent->soi_radius) {
@ -134,7 +134,7 @@ int find_dominant_body(SimulationState* sim, int body_index) {
if (i == body_index) continue; if (i == body_index) continue;
CelestialBody* potential = &sim->bodies[i]; CelestialBody* potential = &sim->bodies[i];
double distance = vec3_distance(body->position, potential->position); double distance = vec3_distance(body->global_position, potential->global_position);
// If within SOI and closer than current, switch to this body // If within SOI and closer than current, switch to this body
if (distance < potential->soi_radius && distance < min_distance) { if (distance < potential->soi_radius && distance < min_distance) {
@ -170,10 +170,10 @@ void update_simulation(SimulationState* sim) {
// Calculate orbital velocity using vis-viva equation // Calculate orbital velocity using vis-viva equation
// Returns velocity vector for body relative to parent // Returns velocity vector for body relative to parent
static Vec3 calc_orbital_velocity(CelestialBody* body, CelestialBody* parent) { static Vec3 calc_orbital_velocity(CelestialBody* body, CelestialBody* parent) {
Vec3 r = vec3_sub(body->position, parent->position); Vec3 r = vec3_sub(body->global_position, parent->global_position);
double distance = vec3_magnitude(r); double distance = vec3_magnitude(r);
double e = body->eccentricity; double e = body->orbit.eccentricity;
double a = body->semi_major_axis; double a = body->orbit.semi_major_axis;
double v_squared; double v_squared;
if (fabs(e) < 0.0001) { if (fabs(e) < 0.0001) {
@ -199,7 +199,7 @@ static Vec3 calc_orbital_velocity(CelestialBody* body, CelestialBody* parent) {
vel_dir = vec3_normalize(vel_dir); vel_dir = vec3_normalize(vel_dir);
Vec3 velocity = vec3_scale(vel_dir, speed); Vec3 velocity = vec3_scale(vel_dir, speed);
return vec3_add(velocity, parent->velocity); return vec3_add(velocity, parent->global_velocity);
} }
// Calculate SOI radius for a single body // Calculate SOI radius for a single body
@ -208,7 +208,7 @@ static Vec3 calc_orbital_velocity(CelestialBody* body, CelestialBody* parent) {
double calculate_soi_radius(CelestialBody* body, CelestialBody* parent) { double calculate_soi_radius(CelestialBody* body, CelestialBody* parent) {
assert(body != nullptr && parent != nullptr); assert(body != nullptr && parent != nullptr);
double mass_ratio = body->mass / parent->mass; double mass_ratio = body->mass / parent->mass;
return body->semi_major_axis * pow(mass_ratio, 0.4); // 2/5 = 0.4 return body->orbit.semi_major_axis * pow(mass_ratio, 0.4); // 2/5 = 0.4
} }
// Combined initialization - sets velocities, SOI radii, and local coordinates in single loop // Combined initialization - sets velocities, SOI radii, and local coordinates in single loop
@ -220,14 +220,14 @@ void initialize_bodies(SimulationState* sim) {
// Set parent pointer if not root body // Set parent pointer if not root body
if (body->parent_index >= 0 && body->parent_index < sim->body_count) { if (body->parent_index >= 0 && body->parent_index < sim->body_count) {
parent = &sim->bodies[body->parent_index]; parent = &sim->bodies[body->parent_index];
body->velocity = calc_orbital_velocity(body, parent); body->global_velocity = calc_orbital_velocity(body, parent);
body->local_position = vec3_sub(body->position, parent->position); body->local_position = vec3_sub(body->global_position, parent->global_position);
body->local_velocity = vec3_sub(body->velocity, parent->velocity); body->local_velocity = vec3_sub(body->global_velocity, parent->global_velocity);
body->soi_radius = calculate_soi_radius(body, parent); body->soi_radius = calculate_soi_radius(body, parent);
} else { // root body } else { // root body
body->velocity = {0.0, 0.0, 0.0}; body->global_velocity = {0.0, 0.0, 0.0};
body->local_position = body->position; body->local_position = body->global_position;
body->local_velocity = body->velocity; body->local_velocity = body->global_velocity;
// Root body (like Sun) has infinite SOI, use a large value // Root body (like Sun) has infinite SOI, use a large value
body->soi_radius = 1e15; // 1000 AU in meters body->soi_radius = 1e15; // 1000 AU in meters
@ -249,22 +249,22 @@ void update_bodies_physics(SimulationState* sim) {
if (new_parent != body->parent_index) { if (new_parent != body->parent_index) {
if (body->parent_index >= 0 && body->parent_index < sim->body_count) { if (body->parent_index >= 0 && body->parent_index < sim->body_count) {
CelestialBody* old_parent = &sim->bodies[body->parent_index]; CelestialBody* old_parent = &sim->bodies[body->parent_index];
body->position = vec3_add(body->local_position, old_parent->position); body->global_position = vec3_add(body->local_position, old_parent->global_position);
body->velocity = vec3_add(body->local_velocity, old_parent->velocity); body->global_velocity = vec3_add(body->local_velocity, old_parent->global_velocity);
} else { } else {
body->position = body->local_position; body->global_position = body->local_position;
body->velocity = body->local_velocity; body->global_velocity = body->local_velocity;
} }
body->parent_index = new_parent; body->parent_index = new_parent;
if (body->parent_index >= 0 && body->parent_index < sim->body_count) { if (body->parent_index >= 0 && body->parent_index < sim->body_count) {
CelestialBody* new_parent_body = &sim->bodies[body->parent_index]; CelestialBody* new_parent_body = &sim->bodies[body->parent_index];
body->local_position = vec3_sub(body->position, new_parent_body->position); body->local_position = vec3_sub(body->global_position, new_parent_body->global_position);
body->local_velocity = vec3_sub(body->velocity, new_parent_body->velocity); body->local_velocity = vec3_sub(body->global_velocity, new_parent_body->global_velocity);
} else { } else {
body->local_position = body->position; body->local_position = body->global_position;
body->local_velocity = body->velocity; body->local_velocity = body->global_velocity;
} }
} }
@ -318,11 +318,11 @@ void compute_spacecraft_globals(SimulationState* sim) {
if (craft->parent_index >= 0 && craft->parent_index < sim->body_count) { if (craft->parent_index >= 0 && craft->parent_index < sim->body_count) {
CelestialBody* parent = &sim->bodies[craft->parent_index]; CelestialBody* parent = &sim->bodies[craft->parent_index];
craft->position = vec3_add(parent->position, craft->local_position); craft->global_position = vec3_add(parent->global_position, craft->local_position);
craft->velocity = vec3_add(parent->velocity, craft->local_velocity); craft->global_velocity = vec3_add(parent->global_velocity, craft->local_velocity);
} else { } else {
craft->position = craft->local_position; craft->global_position = craft->local_position;
craft->velocity = craft->local_velocity; craft->global_velocity = craft->local_velocity;
} }
} }
} }
@ -332,34 +332,34 @@ void compute_global_coordinates(SimulationState* sim) {
CelestialBody* body = &sim->bodies[i]; CelestialBody* body = &sim->bodies[i];
if (body->parent_index == -1) { if (body->parent_index == -1) {
body->position = body->local_position; body->global_position = body->local_position;
body->velocity = body->local_velocity; body->global_velocity = body->local_velocity;
} else if (body->parent_index >= 0 && body->parent_index < sim->body_count) { } else if (body->parent_index >= 0 && body->parent_index < sim->body_count) {
CelestialBody* parent = &sim->bodies[body->parent_index]; CelestialBody* parent = &sim->bodies[body->parent_index];
body->position = vec3_add(body->local_position, parent->position); body->global_position = vec3_add(body->local_position, parent->global_position);
body->velocity = vec3_add(body->local_velocity, parent->velocity); body->global_velocity = vec3_add(body->local_velocity, parent->global_velocity);
} }
} }
} }
OrbitalElements calculate_orbital_elements(CelestialBody* body, CelestialBody* primary, OrbitalMetrics calculate_orbital_elements(CelestialBody* body, CelestialBody* primary,
CelestialBody* optional_ref_body, double current_time) { CelestialBody* optional_ref_body, double current_time) {
const double AU = 1.496e11; const double AU = 1.496e11;
const double SECONDS_PER_DAY = 86400.0; const double SECONDS_PER_DAY = 86400.0;
const double M_sun = primary->mass; const double M_sun = primary->mass;
OrbitalElements elem; OrbitalMetrics elem;
elem.time_days = current_time / SECONDS_PER_DAY; elem.time_days = current_time / SECONDS_PER_DAY;
Vec3 r_vec = vec3_sub(body->position, primary->position); Vec3 r_vec = vec3_sub(body->global_position, primary->global_position);
double r = vec3_magnitude(r_vec); double r = vec3_magnitude(r_vec);
double v = vec3_magnitude(body->velocity); double v = vec3_magnitude(body->global_velocity);
elem.distance_to_sun_au = r / AU; elem.distance_to_sun_au = r / AU;
elem.velocity_magnitude = v; elem.velocity_magnitude = v;
if (optional_ref_body) { if (optional_ref_body) {
double dist_ref = vec3_distance(body->position, optional_ref_body->position); double dist_ref = vec3_distance(body->global_position, optional_ref_body->global_position);
elem.distance_to_ref_body_au = dist_ref / AU; elem.distance_to_ref_body_au = dist_ref / AU;
} else { } else {
elem.distance_to_ref_body_au = -1.0; elem.distance_to_ref_body_au = -1.0;
@ -371,12 +371,12 @@ OrbitalElements calculate_orbital_elements(CelestialBody* body, CelestialBody* p
elem.semi_major_axis_au = -(G * M_sun) / (2.0 * elem.specific_energy) / AU; elem.semi_major_axis_au = -(G * M_sun) / (2.0 * elem.specific_energy) / AU;
double v_squared = v * v; double v_squared = v * v;
double r_dot_v = r_vec.x * body->velocity.x + r_vec.y * body->velocity.y + r_vec.z * body->velocity.z; double r_dot_v = r_vec.x * body->global_velocity.x + r_vec.y * body->global_velocity.y + r_vec.z * body->global_velocity.z;
Vec3 e_vec; Vec3 e_vec;
e_vec.x = (v_squared - G * M_sun / r) * r_vec.x - r_dot_v * body->velocity.x; e_vec.x = (v_squared - G * M_sun / r) * r_vec.x - r_dot_v * body->global_velocity.x;
e_vec.y = (v_squared - G * M_sun / r) * r_vec.y - r_dot_v * body->velocity.y; e_vec.y = (v_squared - G * M_sun / r) * r_vec.y - r_dot_v * body->global_velocity.y;
e_vec.z = (v_squared - G * M_sun / r) * r_vec.z - r_dot_v * body->velocity.z; e_vec.z = (v_squared - G * M_sun / r) * r_vec.z - r_dot_v * body->global_velocity.z;
double e_mag = vec3_magnitude(e_vec) / (G * M_sun); double e_mag = vec3_magnitude(e_vec) / (G * M_sun);
elem.eccentricity = e_mag; elem.eccentricity = e_mag;

27
src/simulation.h

@ -2,6 +2,7 @@
#define BODIES_H #define BODIES_H
#include "physics.h" #include "physics.h"
#include "orbital_mechanics.h"
struct Spacecraft; struct Spacecraft;
struct Maneuver; struct Maneuver;
@ -11,15 +12,21 @@ struct CelestialBody {
char name[64]; char name[64];
double mass; // kg double mass; // kg
double radius; // meters double radius; // meters
Vec3 local_position; // position relative to parent (meters)
Vec3 local_velocity; // velocity relative to parent (m/s)
Vec3 position; // global position (meters from origin)
Vec3 velocity; // global velocity (m/s)
double soi_radius; // sphere of influence radius (meters)
int parent_index; // index of gravitational parent (-1 for root body like Sun) int parent_index; // index of gravitational parent (-1 for root body like Sun)
float color[3]; // RGB color for rendering float color[3]; // RGB color for rendering
double eccentricity; // orbital eccentricity (0 = circular, <1 = elliptical)
double semi_major_axis; // meters // Orbital elements from config (Keplerian elements)
OrbitalElements orbit;
// Global frame (from origin)
Vec3 global_position; // meters from origin
Vec3 global_velocity; // m/s
// Local frame (relative to parent)
Vec3 local_position; // meters from parent
Vec3 local_velocity; // m/s relative to parent
double soi_radius; // sphere of influence radius (meters)
}; };
// Simulation state // Simulation state
@ -67,8 +74,8 @@ void compute_spacecraft_globals(SimulationState* sim);
// Combined initialization - sets velocities, SOI radii, and local coordinates in single loop // Combined initialization - sets velocities, SOI radii, and local coordinates in single loop
void initialize_bodies(SimulationState* sim); void initialize_bodies(SimulationState* sim);
// Orbital elements calculation // Orbital elements calculation (for output/analysis)
struct OrbitalElements { struct OrbitalMetrics {
double time_days; double time_days;
double semi_major_axis_au; double semi_major_axis_au;
double eccentricity; double eccentricity;
@ -78,7 +85,7 @@ struct OrbitalElements {
double velocity_magnitude; double velocity_magnitude;
}; };
OrbitalElements calculate_orbital_elements(CelestialBody* body, CelestialBody* primary, OrbitalMetrics calculate_orbital_elements(CelestialBody* body, CelestialBody* primary,
CelestialBody* optional_ref_body, double current_time); CelestialBody* optional_ref_body, double current_time);
#endif #endif

14
src/spacecraft.h

@ -2,15 +2,23 @@
#define SPACECRAFT_H #define SPACECRAFT_H
#include "physics.h" #include "physics.h"
#include "orbital_mechanics.h"
struct Spacecraft { struct Spacecraft {
char name[64]; char name[64];
double mass; double mass;
int parent_index;
// Orbital elements from config
OrbitalElements orbit;
// Global frame (from origin)
Vec3 global_position;
Vec3 global_velocity;
// Local frame (relative to parent)
Vec3 local_position; Vec3 local_position;
Vec3 local_velocity; Vec3 local_velocity;
Vec3 position;
Vec3 velocity;
int parent_index;
}; };
#endif #endif

12
src/ui_renderer.cpp

@ -188,12 +188,12 @@ void render_body_info_ui(SimulationState* sim, RenderState* render_state) {
if (body->parent_index <= 0) { if (body->parent_index <= 0) {
// Position // Position
snprintf(temp_buffer, sizeof(temp_buffer), "Position: (%.2e, %.2e, %.2e)", snprintf(temp_buffer, sizeof(temp_buffer), "Position: (%.2e, %.2e, %.2e)",
body->position.x, body->position.y, body->position.z); body->global_position.x, body->global_position.y, body->global_position.z);
strcat(info_text, "\n"); strcat(info_text, "\n");
strcat(info_text, temp_buffer); strcat(info_text, temp_buffer);
// Velocity // Velocity
double vel_mag = vec3_magnitude(body->velocity); double vel_mag = vec3_magnitude(body->global_velocity);
snprintf(temp_buffer, sizeof(temp_buffer), "Velocity: %.2f m/s", vel_mag); snprintf(temp_buffer, sizeof(temp_buffer), "Velocity: %.2f m/s", vel_mag);
strcat(info_text, "\n"); strcat(info_text, "\n");
strcat(info_text, temp_buffer); strcat(info_text, temp_buffer);
@ -205,19 +205,19 @@ void render_body_info_ui(SimulationState* sim, RenderState* render_state) {
strcat(info_text, temp_buffer); strcat(info_text, temp_buffer);
// Velocity (Local) // Velocity (Local)
double parent_vel_mag = vec3_magnitude(sim->bodies[body->parent_index].velocity); double parent_vel_mag = vec3_magnitude(sim->bodies[body->parent_index].global_velocity);
double vel_mag = vec3_magnitude(body->velocity) - parent_vel_mag; double vel_mag = vec3_magnitude(body->global_velocity) - parent_vel_mag;
snprintf(temp_buffer, sizeof(temp_buffer), "local_velocity: %.2f m/s", vel_mag); snprintf(temp_buffer, sizeof(temp_buffer), "local_velocity: %.2f m/s", vel_mag);
strcat(info_text, "\n"); strcat(info_text, "\n");
strcat(info_text, temp_buffer); strcat(info_text, temp_buffer);
} }
// Orbital elements // Orbital elements
snprintf(temp_buffer, sizeof(temp_buffer), "Eccentricity: %.3f", body->eccentricity); snprintf(temp_buffer, sizeof(temp_buffer), "Eccentricity: %.3f", body->orbit.eccentricity);
strcat(info_text, "\n"); strcat(info_text, "\n");
strcat(info_text, temp_buffer); strcat(info_text, temp_buffer);
snprintf(temp_buffer, sizeof(temp_buffer), "Semi-major axis: %.2e m", body->semi_major_axis); snprintf(temp_buffer, sizeof(temp_buffer), "Semi-major axis: %.2e m", body->orbit.semi_major_axis);
strcat(info_text, "\n"); strcat(info_text, "\n");
strcat(info_text, temp_buffer); strcat(info_text, temp_buffer);

Loading…
Cancel
Save