diff --git a/src/simulation.cpp b/src/simulation.cpp index a9da247..198cde1 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -35,6 +35,14 @@ 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 (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; + } + // Check all other bodies to see if we're within their SOI for (int i = 0; i < sim->body_count; i++) { if (i == body_index) continue; @@ -42,18 +50,27 @@ int find_dominant_body(SimulationState* sim, int body_index) { CelestialBody* potential_parent = &sim->bodies[i]; double distance = vec3_distance(body->position, potential_parent->position); - // If we're within this body's SOI and it's not our current parent - if (distance < potential_parent->soi_radius && i != dominant) { - // Check if this body is more dominant (closer or more massive) + // 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); - // Switch if this potential parent is significantly closer - if (distance < dist_to_current * 0.5) { - dominant = i; + 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; + } } } } diff --git a/tests/test_soi_transition.cpp b/tests/test_soi_transition.cpp index bbca3f2..3acd099 100644 --- a/tests/test_soi_transition.cpp +++ b/tests/test_soi_transition.cpp @@ -16,11 +16,11 @@ struct ParentChange { TEST_CASE("SOI transition - Sun to Mars", "[soi][transition]") { const double TIME_STEP = 60.0; - const double DAYS_TO_SIMULATE = 1700.0; + const double DAYS_TO_SIMULATE = 2000.0; const double SECONDS_PER_DAY = 86400.0; const double AU = 1.496e11; - INFO("Note: Hysteresis (0.5 factor) makes Mars -> Sun exit impossible"); + INFO("Note: Hysteresis (0.5 factor) prevents oscillations, allows Mars -> Sun exit when outside SOI"); SimulationState* sim = create_simulation(10, TIME_STEP); @@ -80,6 +80,19 @@ TEST_CASE("SOI transition - Sun to Mars", "[soi][transition]") { REQUIRE(found_mars_transition); + bool found_mars_exit = false; + for (const auto& change : parent_changes) { + if (change.old_parent == MARS_INDEX && change.new_parent == SUN_INDEX) { + found_mars_exit = true; + INFO("Mars -> Sun exit at day " << change.time_days + << ", distance to Mars: " << change.distance_to_mars_au << " AU" + << ", distance to Sun: " << change.distance_to_sun_au << " AU"); + break; + } + } + + REQUIRE(found_mars_exit); + destroy_simulation(sim); }