You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
4.2 KiB
198 lines
4.2 KiB
|
|
#include "orbits.h" |
|
|
|
|
|
ellipse_parameters |
|
constructEllipseAB(double a, double b) |
|
{ |
|
assert(a > 0 && b > 0 && a >= b); |
|
ellipse_parameters ep = { a, b }; |
|
ep.c = sqrt(a * a - b * b); |
|
ep.e = ep.c / ep.a; |
|
ep.p = ep.a * (1 - pow(ep.e, 2)); |
|
ep.f1.x = -1 * ep.c; |
|
ep.f2.x = ep.c; |
|
return ep; |
|
} |
|
|
|
ellipse_parameters |
|
constructEllipseAE(double a, double e) |
|
{ |
|
assert(e >= 0 && e < 1); |
|
double b = a * sqrt(1 - pow(e, 2.0)); |
|
return constructEllipseAB(a, b); |
|
} |
|
|
|
bool |
|
validateEllipse(const ellipse_parameters& ep) |
|
{ |
|
// TODO: find out why satellite position gets wonky with orbit |
|
// eccentricity > 0.995 while passing through true anom = 0. |
|
// maybe divide by 0, or some floating point error? |
|
return (ep.a > 0 && |
|
ep.b > 0 && |
|
ep.a >= ep.b && |
|
ep.e >= 0 && |
|
ep.e < 0.995); |
|
} |
|
|
|
bool |
|
ellipsesEqual(ellipse_parameters& e1, ellipse_parameters& e2) |
|
{ |
|
return (e1.a == e2.a && |
|
e1.b == e2.b && |
|
e1.e == e2.e); |
|
} |
|
|
|
void |
|
ellipseCopy(const ellipse_parameters& e1, ellipse_parameters& e2) |
|
{ |
|
e2.a = e1.a; |
|
e2.b = e1.b; |
|
e2.e = e1.e; |
|
e2.c = e1.c; |
|
e2.p = e1.p; |
|
e2.f1 = e1.f1; |
|
e2.f2 = e1.f2; |
|
} |
|
|
|
void |
|
orbitCopy(const orbital_elements& o1, orbital_elements& o2) |
|
{ |
|
ellipseCopy(o1.ep, o2.ep); |
|
o2.iota = o1.iota; |
|
o2.omega = o1.omega; |
|
o2.mu = o1.mu; |
|
o2.nu = o1.nu; |
|
o2.pos = o1.pos; |
|
} |
|
|
|
ellipse_3d |
|
constructEllipse3D(ellipse_parameters ep, uint vert_count) |
|
{ |
|
assert(ep.a > 0 && ep.b > 0 && |
|
ep.a >= ep.b && |
|
vert_count > 0); |
|
|
|
ellipse_3d e3d = { ep, nullptr, vert_count}; |
|
// TODO: need to free this allocation at some point |
|
e3d.vertices = UTIL_ALLOC(vert_count, glm::vec3); |
|
ellipse3DUpdate(ep, e3d); |
|
return e3d; |
|
} |
|
|
|
void |
|
ellipse3DUpdate(ellipse_parameters ep, ellipse_3d& e3d) |
|
{ |
|
double angle = 2 * M_PI / e3d.vert_count; |
|
|
|
for (uint i = 0; i < e3d.vert_count; i++) { |
|
double a = angle * i; |
|
// NOTE: solving for distance in polar coordinates relative to focus |
|
double r = ep.a * (1 - pow(ep.e, 2)) / (1 + ep.e * cos(a)); |
|
e3d.vertices[i] = glm::vec3(polarToRect(a, r), 0); |
|
} |
|
} |
|
|
|
double |
|
getEccAnomFromTrueAnom(double ecc, double true_anom) |
|
{ |
|
return 2 * atan(sqrt((1 - ecc) / (1 + ecc)) * tan(true_anom / 2)); |
|
} |
|
|
|
double |
|
getTrueAnomFromEccAnom(double ecc, double ecc_anom) |
|
{ |
|
return 2 * atan(sqrt((1 + ecc) / (1 - ecc)) * tan(ecc_anom / 2)); |
|
} |
|
|
|
double |
|
getMeanAnomFromEccAnom(double ecc_anom, double ecc) |
|
{ |
|
return ecc_anom - ecc * sin(ecc_anom); |
|
} |
|
|
|
double |
|
getMeanMotion(double mu, double a) |
|
{ |
|
return sqrt(mu / pow(a, 3)); |
|
} |
|
|
|
double |
|
getPropagatedMeanAnom(double mean_anom, double mean_motion, double time_step) |
|
{ |
|
return mean_anom + mean_motion * (time_step); |
|
} |
|
|
|
double |
|
getInitialTrialValue(double mean_anom, double ecc) |
|
{ |
|
return mean_anom + ecc * sin(mean_anom) |
|
+ ((pow(ecc, 2) / 2) * sin(2 * mean_anom)); |
|
} |
|
|
|
double |
|
getTrialError(double ecc, double test_anom, double mean_anom) |
|
{ |
|
return test_anom - ecc * sin(test_anom) - mean_anom; |
|
} |
|
|
|
double |
|
getNextTrialValue(double err, double ecc, double test_anom, double mean_anom) |
|
{ |
|
// compute derivative of the error function |
|
double derr = 1 - ecc * cos(test_anom); |
|
|
|
// use Newton's method to compute next trial value of E2 |
|
return test_anom - (err / derr); |
|
} |
|
|
|
double |
|
getPropagatedEccAnomaly(orbital_elements orbit, |
|
double initial_anom, |
|
unsigned int time_step) |
|
{ |
|
double e = orbit.ep.e; |
|
double E1 = getEccAnomFromTrueAnom(e, initial_anom); |
|
double M1 = getMeanAnomFromEccAnom(E1, e); |
|
double n = getMeanMotion(orbit.mu, orbit.ep.a); |
|
double M2 = getPropagatedMeanAnom(M1, n, time_step); |
|
double E2_1 = getInitialTrialValue(M2, e); |
|
|
|
// test if guess is a solution to kepler's equation |
|
const double ACCEPTABLE_ERROR = 0.00000001; |
|
double E2_test = E2_1; |
|
|
|
for (uint i = 0; i < 10; i++) { |
|
double err = getTrialError(e, E2_test, M2); |
|
|
|
if (fabs(err) < ACCEPTABLE_ERROR) |
|
break; |
|
|
|
E2_test = getNextTrialValue(err, e, E2_test, M2); |
|
} |
|
|
|
return E2_test; |
|
} |
|
|
|
double |
|
getPropagatedTrueAnomaly(orbital_elements orbit, |
|
double initial_anom, |
|
unsigned int time_step) |
|
{ |
|
double ecc_anom = getPropagatedEccAnomaly(orbit, initial_anom, time_step); |
|
return getTrueAnomFromEccAnom(orbit.ep.e, ecc_anom); |
|
} |
|
|
|
double |
|
getRadialDistance(double e, double p, double true_anom) |
|
{ |
|
return p / (1 + e * cos(true_anom)); |
|
} |
|
|
|
glm::vec2 |
|
polarToRect(double angle, double r) |
|
{ |
|
return glm::vec2(r * cos(angle), r * sin(angle)); |
|
} |
|
|
|
|