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

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