From 6edd30e75963220d8a2ddf60f61b87cdcf0cbe23 Mon Sep 17 00:00:00 2001 From: cinnaboot Date: Tue, 28 Apr 2026 13:04:23 -0400 Subject: [PATCH] refactor: improve OrbitTracker accuracy and test_utilities code quality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix orbit period detection: track accumulated signed rotation instead of wrapped delta, completing on true 2π revolution (was < 0.05 rad) - Rename quadrant_transitions → wrap_count (accurate semantics) - Add accumulated_rotation field to OrbitTracker struct - Consolidate create_orbit_tracker into create_orbit_tracker_with_min_time - Extract reset_tracker_fields() helper to avoid duplication - Use vec3_dot() for kinetic energy, vec3_magnitude() for speed calculations - Define MIN_DISTANCE_CLAMP and SECONDS_PER_DAY as file-level constants - Add NULL checks in dump_simulation_state for spacecraft/maneuver pointers --- src/test_utilities.cpp | 112 +++++++++++++++++++---------------------- src/test_utilities.h | 5 +- 2 files changed, 56 insertions(+), 61 deletions(-) diff --git a/src/test_utilities.cpp b/src/test_utilities.cpp index edd73ad..6c1a0a6 100644 --- a/src/test_utilities.cpp +++ b/src/test_utilities.cpp @@ -3,16 +3,18 @@ #include #include +#define MIN_DISTANCE_CLAMP 1.0 + +static const double SECONDS_PER_DAY = 86400.0; + double calculate_kinetic_energy(CelestialBody* body) { - double v_squared = body->global_velocity.x * body->global_velocity.x + - body->global_velocity.y * body->global_velocity.y + - body->global_velocity.z * body->global_velocity.z; - return 0.5 * body->mass * v_squared; + Vec3 v = body->global_velocity; + return 0.5 * body->mass * vec3_dot(v, v); } double calculate_potential_energy_pair(CelestialBody* body1, CelestialBody* body2) { double distance = vec3_distance(body1->global_position, body2->global_position); - if (distance < 1.0) distance = 1.0; + if (distance < MIN_DISTANCE_CLAMP) distance = MIN_DISTANCE_CLAMP; return -G * body1->mass * body2->mass / distance; } @@ -46,28 +48,13 @@ OrbitalMetrics calculate_orbital_metrics(CelestialBody* body, CelestialBody* par return metrics; } -OrbitTracker* create_orbit_tracker(int body_index) { - OrbitTracker* tracker = (OrbitTracker*)malloc(sizeof(OrbitTracker)); - tracker->body_index = body_index; - tracker->initial_angle = 0.0; - tracker->previous_angle = 0.0; - tracker->quadrant_transitions = 0; - tracker->orbit_completed = false; - tracker->time_at_completion = 0.0; - tracker->min_time_days = 100.0; - tracker->inclination = 0.0; - tracker->longitude_of_ascending_node = 0.0; - tracker->argument_of_periapsis = 0.0; - tracker->has_orbital_elements = false; - return tracker; -} - OrbitTracker* create_orbit_tracker_with_min_time(int body_index, double min_time_days) { OrbitTracker* tracker = (OrbitTracker*)malloc(sizeof(OrbitTracker)); tracker->body_index = body_index; tracker->initial_angle = 0.0; tracker->previous_angle = 0.0; - tracker->quadrant_transitions = 0; + tracker->accumulated_rotation = 0.0; + tracker->wrap_count = 0; tracker->orbit_completed = false; tracker->time_at_completion = 0.0; tracker->min_time_days = min_time_days; @@ -78,6 +65,10 @@ OrbitTracker* create_orbit_tracker_with_min_time(int body_index, double min_time return tracker; } +OrbitTracker* create_orbit_tracker(int body_index) { + return create_orbit_tracker_with_min_time(body_index, 100.0); +} + OrbitTracker* create_orbit_tracker_3d(int body_index, double min_time_days, double inclination, double lon_ascending_node, double argument_of_periapsis) { @@ -89,14 +80,19 @@ OrbitTracker* create_orbit_tracker_3d(int body_index, double min_time_days, return tracker; } -void reset_orbit_tracker(OrbitTracker* tracker) { +static void reset_tracker_fields(OrbitTracker* tracker) { tracker->initial_angle = 0.0; tracker->previous_angle = 0.0; - tracker->quadrant_transitions = 0; + tracker->accumulated_rotation = 0.0; + tracker->wrap_count = 0; tracker->orbit_completed = false; tracker->time_at_completion = 0.0; } +void reset_orbit_tracker(OrbitTracker* tracker) { + reset_tracker_fields(tracker); +} + void update_orbit_tracker(OrbitTracker* tracker, CelestialBody* body, CelestialBody* parent, double current_time) { if (tracker->orbit_completed) return; @@ -117,10 +113,11 @@ void update_orbit_tracker(OrbitTracker* tracker, CelestialBody* body, CelestialB current_angle = atan2(relative_pos.y, relative_pos.x); } - if (tracker->quadrant_transitions == 0) { + if (tracker->wrap_count == 0) { tracker->initial_angle = current_angle; tracker->previous_angle = current_angle; - tracker->quadrant_transitions = 1; + tracker->accumulated_rotation = 0.0; + tracker->wrap_count = 1; return; } @@ -128,23 +125,20 @@ void update_orbit_tracker(OrbitTracker* tracker, CelestialBody* body, CelestialB if (angle_diff > M_PI) { angle_diff -= 2.0 * M_PI; - tracker->quadrant_transitions++; + tracker->wrap_count++; } if (angle_diff < -M_PI) { angle_diff += 2.0 * M_PI; - tracker->quadrant_transitions++; + tracker->wrap_count++; } - double total_rotation = current_angle - tracker->initial_angle; - if (total_rotation < -M_PI) total_rotation += 2.0 * M_PI; - if (total_rotation > M_PI) total_rotation -= 2.0 * M_PI; + tracker->accumulated_rotation += angle_diff; - const double SECONDS_PER_DAY = 86400.0; double min_time_seconds = tracker->min_time_days * SECONDS_PER_DAY; - if (tracker->quadrant_transitions >= 2 && + if (tracker->wrap_count >= 2 && current_time > min_time_seconds && - fabs(total_rotation) < 0.05) { + tracker->accumulated_rotation >= 2.0 * M_PI) { tracker->orbit_completed = true; tracker->time_at_completion = current_time; } @@ -183,35 +177,35 @@ int dump_simulation_state(SimulationState* sim, const char* label, offset += snprintf(buffer + offset, buffer_size - offset, "Spacecraft (%d):\n", sim->craft_count); - for (int i = 0; i < sim->craft_count; i++) { - Spacecraft* s = &sim->spacecraft[i]; - double r = sqrt(s->local_position.x*s->local_position.x + - s->local_position.y*s->local_position.y + - s->local_position.z*s->local_position.z); - double v = sqrt(s->local_velocity.x*s->local_velocity.x + - s->local_velocity.y*s->local_velocity.y + - s->local_velocity.z*s->local_velocity.z); - offset += snprintf(buffer + offset, buffer_size - offset, - " [%d] %s: r=%.1f v=%.1f nu=%.5f a=%.1f e=%.6f, omega=%.6f\n", - i, s->name, r, v, - s->orbit.true_anomaly, - s->orbit.semi_major_axis, - s->orbit.eccentricity, - s->orbit.argument_of_periapsis); - offset += snprintf(buffer + offset, buffer_size - offset, - " pos=(%.1f, %.1f, %.1f) vel=(%.1f, %.1f, %.1f)\n", - s->local_position.x, s->local_position.y, s->local_position.z, - s->local_velocity.x, s->local_velocity.y, s->local_velocity.z); + if (sim->spacecraft) { + for (int i = 0; i < sim->craft_count; i++) { + Spacecraft* s = &sim->spacecraft[i]; + double r = vec3_magnitude(s->local_position); + double v = vec3_magnitude(s->local_velocity); + offset += snprintf(buffer + offset, buffer_size - offset, + " [%d] %s: r=%.1f v=%.1f nu=%.5f a=%.1f e=%.6f, omega=%.6f\n", + i, s->name, r, v, + s->orbit.true_anomaly, + s->orbit.semi_major_axis, + s->orbit.eccentricity, + s->orbit.argument_of_periapsis); + offset += snprintf(buffer + offset, buffer_size - offset, + " pos=(%.1f, %.1f, %.1f) vel=(%.1f, %.1f, %.1f)\n", + s->local_position.x, s->local_position.y, s->local_position.z, + s->local_velocity.x, s->local_velocity.y, s->local_velocity.z); + } } offset += snprintf(buffer + offset, buffer_size - offset, "Maneuvers (%d):\n", sim->maneuver_count); - for (int i = 0; i < sim->maneuver_count; i++) { - Maneuver* m = &sim->maneuvers[i]; - offset += snprintf(buffer + offset, buffer_size - offset, - " [%d] %s: craft=%d dir=%d dv=%.4f trigger=%d val=%.2f exec=%d\n", - i, m->name, m->craft_index, m->direction, m->delta_v, - m->trigger_type, m->trigger_value, m->executed); + if (sim->maneuvers) { + for (int i = 0; i < sim->maneuver_count; i++) { + Maneuver* m = &sim->maneuvers[i]; + offset += snprintf(buffer + offset, buffer_size - offset, + " [%d] %s: craft=%d dir=%d dv=%.4f trigger=%d val=%.2f exec=%d\n", + i, m->name, m->craft_index, m->direction, m->delta_v, + m->trigger_type, m->trigger_value, m->executed); + } } return offset; diff --git a/src/test_utilities.h b/src/test_utilities.h index d71087a..357a42e 100644 --- a/src/test_utilities.h +++ b/src/test_utilities.h @@ -16,7 +16,8 @@ struct OrbitalMetrics { struct OrbitTracker { double initial_angle; double previous_angle; - int quadrant_transitions; + double accumulated_rotation; + int wrap_count; bool orbit_completed; double time_at_completion; int body_index; @@ -48,7 +49,7 @@ bool compare_vec3(Vec3 a, Vec3 b, double tolerance); // Write simulation state to a caller-allocated buffer. // Returns number of characters written (excluding null terminator). -// Caller must ensure buffer is large enough. +// Caller must ensure buffer is large enough (recommended 4096 bytes). int dump_simulation_state(SimulationState* sim, const char* label, char* buffer, int buffer_size);