Browse Source

fix: enable SOI exit transitions with conditional hysteresis

Modified find_dominant_body() to detect when bodies exit SOI by checking
distance against current parent's SOI radius. Applies different hysteresis:
- Inside SOI: 0.5x distance threshold prevents oscillations
- Outside SOI: switches to closest body without hysteresis

Added test requirement for Mars SOI exit detection.

Claude
main
cinnaboot 6 months ago
parent
commit
ee055856a5
  1. 29
      src/simulation.cpp
  2. 17
      tests/test_soi_transition.cpp

29
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;
}
}
}
}

17
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);
}

Loading…
Cancel
Save