@ -66,20 +66,21 @@ void orbital_elements_to_cartesian(OrbitalElements elements, double parent_mass,
* out_velocity = mat3_multiply_vec3 ( rotation , velocity ) ;
* out_velocity = mat3_multiply_vec3 ( rotation , velocity ) ;
}
}
// Shared solver constants
static const double KEPLER_TOLERANCE = 1.0e-10 ;
static const int KEPLER_MAX_ITERATIONS = 50 ;
double get_initial_trial_value ( double mean_anomaly , double eccentricity ) {
double get_initial_trial_value ( double mean_anomaly , double eccentricity ) {
return mean_anomaly + eccentricity * sin ( mean_anomaly )
return mean_anomaly + eccentricity * sin ( mean_anomaly )
+ ( ( pow ( eccentricity , 2 ) / 2.0 ) * sin ( 2.0 * mean_anomaly ) ) ;
+ ( ( pow ( eccentricity , 2 ) / 2.0 ) * sin ( 2.0 * mean_anomaly ) ) ;
}
}
double solve_kepler_equation ( double mean_anomaly , double eccentricity ) {
double solve_kepler_elliptical ( double mean_anomaly , double eccentricity ) {
const double CONVERGENCE_TOLERANCE = 1.0e-10 ;
const int MAX_ITERATIONS = 50 ;
double E = get_initial_trial_value ( mean_anomaly , eccentricity ) ;
double E = get_initial_trial_value ( mean_anomaly , eccentricity ) ;
double E_prev = E + 2.0 * CONVERGENCE _TOLERANCE;
double E_prev = E + 2.0 * KEPLER_TOLERANCE ;
int iterations = 0 ;
int iterations = 0 ;
while ( fabs ( E - E_prev ) > CONVERGENCE _TOLERANCE & & iterations < MAX_ITERATIONS ) {
while ( fabs ( E - E_prev ) > KEPLER _TOLERANCE & & iterations < KEPLER_ MAX_ITERATIONS) {
E_prev = E ;
E_prev = E ;
double sin_E = sin ( E ) ;
double sin_E = sin ( E ) ;
E = E - ( E - eccentricity * sin_E - mean_anomaly ) / ( 1.0 - eccentricity * cos ( E ) ) ;
E = E - ( E - eccentricity * sin_E - mean_anomaly ) / ( 1.0 - eccentricity * cos ( E ) ) ;
@ -89,6 +90,52 @@ double solve_kepler_equation(double mean_anomaly, double eccentricity) {
return E ;
return E ;
}
}
double solve_kepler_hyperbolic ( double mean_anomaly , double eccentricity ) {
// Initial guess for hyperbolic anomaly
double H = mean_anomaly ;
if ( eccentricity * sinh ( mean_anomaly ) > mean_anomaly ) {
H = log ( 2.0 * mean_anomaly / eccentricity ) ;
}
double H_prev = H + 2.0 * KEPLER_TOLERANCE ;
int iterations = 0 ;
while ( fabs ( H - H_prev ) > KEPLER_TOLERANCE & & iterations < KEPLER_MAX_ITERATIONS ) {
H_prev = H ;
double sinh_H = sinh ( H ) ;
double cosh_H = cosh ( H ) ;
H = H - ( H - eccentricity * sinh_H - mean_anomaly ) / ( 1.0 - eccentricity * cosh_H ) ;
iterations + + ;
}
return H ;
}
double eccentric_to_true_anomaly ( double eccentric_anomaly , double eccentricity ) {
// E to true anomaly conversion: tan(ν/2) = √((1+e)/(1-e)) · tan(E/2)
double tan_half_E = tan ( eccentric_anomaly / 2.0 ) ;
double tan_half_nu = sqrt ( ( 1.0 + eccentricity ) / ( 1.0 - eccentricity ) ) * tan_half_E ;
return 2.0 * atan ( tan_half_nu ) ;
}
double hyperbolic_to_true_anomaly ( double hyperbolic_anomaly , double eccentricity ) {
// Hyperbolic E to true anomaly: tanh(ν/2) = √((e-1)/(e+1)) · tanh(H/2)
double tanh_half_H = tanh ( hyperbolic_anomaly / 2.0 ) ;
double tanh_half_nu = sqrt ( ( eccentricity - 1.0 ) / ( eccentricity + 1.0 ) ) * tanh_half_H ;
return 2.0 * atanh ( tanh_half_nu ) ;
}
double mean_anomaly_to_true_anomaly ( double mean_anomaly , double eccentricity ) {
if ( eccentricity < 1.0 ) {
double E = solve_kepler_elliptical ( mean_anomaly , eccentricity ) ;
return eccentric_to_true_anomaly ( E , eccentricity ) ;
} else {
double H = solve_kepler_hyperbolic ( mean_anomaly , eccentricity ) ;
return hyperbolic_to_true_anomaly ( H , eccentricity ) ;
}
}
// TODO: refactor for readability
OrbitalElements cartesian_to_orbital_elements ( Vec3 position , Vec3 velocity , double parent_mass ) {
OrbitalElements cartesian_to_orbital_elements ( Vec3 position , Vec3 velocity , double parent_mass ) {
double mu = G * parent_mass ;
double mu = G * parent_mass ;