Browse Source

Simplify find_dominant_body to remove hysteresis

Remove complex hysteresis logic and implement simple SOI-based
parent switching: bodies stay with current parent while within its SOI,
and switch to closest body whose SOI contains them when exiting.

This eliminates unnecessary N-body comparisons when inside current
parent's SOI, preventing unphysical transitions (e.g., Moon→Mars
while still in Earth's SOI).

Simplified logic:
- Within parent's SOI → STAY with current parent
- Outside parent's SOI → FIND new parent (closest body whose SOI contains us)
- If no SOI contains us → fall back to Sun (index 0)

This matches simple 2-body simulation model and makes the code
much clearer and more maintainable.

Note: SOI transition test temporarily expects hysteresis behavior
and will need to be updated in follow-up commit.
main
cinnaboot 6 months ago
parent
commit
60e852be8b
  1. 54
      src/simulation.cpp
  2. 2
      tests/test_soi_transition.cpp

54
src/simulation.cpp

@ -69,48 +69,42 @@ int find_dominant_body(SimulationState* sim, int body_index) {
CelestialBody* body = &sim->bodies[body_index];
int dominant = body->parent_index;
// Check if we're outside current parent's SOI
bool outside_current_soi = false;
// If within current parent's SOI → stay with current parent
if (dominant >= 0 && dominant < sim->body_count) {
CelestialBody* current_parent = &sim->bodies[dominant];
double dist_to_current = vec3_distance(body->position, current_parent->position);
outside_current_soi = dist_to_current > current_parent->soi_radius;
CelestialBody* parent = &sim->bodies[dominant];
double distance = vec3_distance(body->position, parent->position);
if (distance < parent->soi_radius) {
return dominant;
}
}
// Check all other bodies to see if we're within their SOI
// Outside current parent's SOI (or has no parent)
// Find new parent: body we're within SOI of and closest to
int new_parent = -1;
double min_distance = INFINITY;
for (int i = 0; i < sim->body_count; i++) {
if (i == body_index) continue;
CelestialBody* potential_parent = &sim->bodies[i];
double distance = vec3_distance(body->position, potential_parent->position);
// If we're outside current parent's SOI, consider all bodies
// Otherwise, only consider bodies within their SOI
bool can_switch = outside_current_soi || distance < potential_parent->soi_radius;
if (can_switch && i != dominant) {
if (dominant == -1) {
dominant = i;
} else {
CelestialBody* current_parent = &sim->bodies[dominant];
double dist_to_current = vec3_distance(body->position, current_parent->position);
CelestialBody* potential = &sim->bodies[i];
double distance = vec3_distance(body->position, potential->position);
if (outside_current_soi) {
// Outside current SOI: switch to closest body
if (distance < dist_to_current) {
dominant = i;
}
} else {
// Inside current SOI: apply hysteresis to prevent oscillations
if (distance < dist_to_current * 0.5) {
dominant = i;
}
// Only consider bodies we're within SOI of
if (distance < potential->soi_radius) {
if (distance < min_distance) {
min_distance = distance;
new_parent = i;
}
}
}
// If no body's SOI contains us, fall back to root (Sun)
if (new_parent == -1) {
new_parent = 0;
}
return dominant;
return new_parent;
}
// Update sphere of influence radius using Hill sphere approximation

2
tests/test_soi_transition.cpp

@ -20,7 +20,7 @@ TEST_CASE("SOI transition - Sun to Mars", "[soi][transition]") {
const double SECONDS_PER_DAY = 86400.0;
const double AU = 1.496e11;
INFO("Note: Hysteresis (0.5 factor) prevents oscillations, allows Mars -> Sun exit when outside SOI");
INFO("Note: SOI transitions use simple model (no hysteresis)");
SimulationState* sim = create_simulation(10, TIME_STEP);

Loading…
Cancel
Save