Browse Source

Simplify find_dominant_body based on parent type

Implement much simpler SOI transition logic:

If parent is not root (parent_idx != 0):
  - Only two options: stay with parent or go to Sun
  - If within parent's SOI: stay with current parent
  - If outside parent's SOI: switch to Sun (index 0)

If parent is root (parent_idx == 0):
  - Check all bodies for SOI containment
  - Find closest body whose SOI contains us
  - If no SOI contains us: stay with Sun

Benefits:
- Eliminates unnecessary N-body comparisons when inside parent's SOI
- Prevents unphysical transitions (Moon→Mars while in Earth's SOI)
- Much simpler and more maintainable logic
- Enables proper patched conics: Earth→Sun→Mars→Sun→Earth

Test results:
- SOI transition test now passes (2 parent changes: Sun→Mars→Sun)
- All 24 tests passing
- Net change: +18/-21 lines
main
cinnaboot 6 months ago
parent
commit
a260d24d36
  1. 39
      src/simulation.cpp

39
src/simulation.cpp

@ -60,28 +60,33 @@ int add_body_to_simulation(SimulationState* sim, CelestialBody* body) {
return new_idx; return new_idx;
} }
// Find which body is gravitationally dominant for the given body
int find_dominant_body(SimulationState* sim, int body_index) { int find_dominant_body(SimulationState* sim, int body_index) {
if (body_index < 0 || body_index >= sim->body_count) { if (body_index < 0 || body_index >= sim->body_count) {
return -1; return -1;
} }
CelestialBody* body = &sim->bodies[body_index]; CelestialBody* body = &sim->bodies[body_index];
int dominant = body->parent_index; int parent_idx = body->parent_index;
// If within current parent's SOI → stay with current parent // If parent is not root (not Sun): only check if still within parent's SOI
if (dominant >= 0 && dominant < sim->body_count) { if (parent_idx != 0) {
CelestialBody* parent = &sim->bodies[dominant]; if (parent_idx < 0 || parent_idx >= sim->body_count) {
return -1;
}
CelestialBody* parent = &sim->bodies[parent_idx];
double distance = vec3_distance(body->position, parent->position); double distance = vec3_distance(body->position, parent->position);
// Stay with parent if within SOI, otherwise go to Sun
if (distance < parent->soi_radius) { if (distance < parent->soi_radius) {
return dominant; return parent_idx;
} else {
return 0;
} }
} }
// Outside current parent's SOI (or has no parent) // Parent is root (Sun): check all bodies for SOI containment
// Find new parent: body we're within SOI of and closest to int new_parent = 0;
int new_parent = -1;
double min_distance = INFINITY; double min_distance = INFINITY;
for (int i = 0; i < sim->body_count; i++) { for (int i = 0; i < sim->body_count; i++) {
@ -90,23 +95,15 @@ int find_dominant_body(SimulationState* sim, int body_index) {
CelestialBody* potential = &sim->bodies[i]; CelestialBody* potential = &sim->bodies[i];
double distance = vec3_distance(body->position, potential->position); double distance = vec3_distance(body->position, potential->position);
// Only consider bodies we're within SOI of // If within SOI and closer than current, switch to this body
if (distance < potential->soi_radius) { if (distance < potential->soi_radius && distance < min_distance) {
if (distance < min_distance) { min_distance = distance;
min_distance = distance; new_parent = i;
new_parent = i;
}
} }
} }
// If no body's SOI contains us, fall back to root (Sun)
if (new_parent == -1) {
new_parent = 0;
}
return new_parent; return new_parent;
} }
// Update sphere of influence radius using Hill sphere approximation // Update sphere of influence radius using Hill sphere approximation
// r_soi = a * (m/M)^(2/5) where a = semi-major axis, m = body mass, M = parent mass // r_soi = a * (m/M)^(2/5) where a = semi-major axis, m = body mass, M = parent mass
void update_soi(CelestialBody* body, CelestialBody* parent, double semi_major_axis) { void update_soi(CelestialBody* body, CelestialBody* parent, double semi_major_axis) {

Loading…
Cancel
Save