Browse Source

impletment multiple orbits

main
cinnaboot 4 years ago
parent
commit
cc934945de
  1. 117
      src/main.cpp
  2. 27
      src/orbits.cpp
  3. 5
      src/orbits.h
  4. 12
      tests/orbit_test.cpp

117
src/main.cpp

@ -8,7 +8,6 @@
* - make an 'overlay' graphic for things like apoapsis, perisapsis, f1, f2,
* flight path
* - impulsive orbital maneuvers
* - test multiple orbits
* - Hohmman transfer orbits
* - patched conic method for transferring between 2 grav bodies
*/
@ -32,6 +31,17 @@ const vec4 g_light_direction = vec4(-2, 1, 3, 1);
const vec4 g_light_color = vec4(0.5, 0.5, 0.5, 1);
const uvec4 g_light_intensities = uvec4(1, 0, 0, 0);
struct GameOrbit
{
TwoBodySystem system;
Entity* grav_body;
Entity* ellipse_entity;
Entity* satellite_entity;
bool in_use;
};
struct GameState
{
bool running;
@ -41,10 +51,41 @@ struct GameState
u64 sim_time_ms;
float sim_speed;
TwoBodySystem system; // FIXME: we're going to need more than 1 system...
Entity* satellite_entity;
GameOrbit* orbits;
u32 num_orbits;
u32 max_orbits;
};
GameOrbit*
getFreeOrbit(GameState* gs)
{
GameOrbit* orbit = nullptr;
// NOTE: first check if we have a freed orbit to use
for (u32 i = 0; i < gs->num_orbits; i++) {
if (!gs->orbits[i].in_use)
orbit = &gs->orbits[i];
}
// NOTE: if we can't re-use a freed orbit, initialize a new one
if (!orbit) {
assert(gs->num_orbits < gs->max_orbits);
orbit = &gs->orbits[gs->num_orbits++];
}
orbit->in_use = true;
return orbit;
}
void
disableGameOrbit(GameOrbit* orbit)
{
orbit->in_use = false;
orbit->system = {0};
orbit->grav_body = nullptr;
orbit->ellipse_entity = nullptr;
orbit->satellite_entity = nullptr;
}
void
initCamera(RenderState* rs, vec3 cam_pos, vec3 cam_focus, vec3 cam_up)
@ -72,6 +113,7 @@ initLights(RenderState* rs)
updateGLBuffer(lights_ubo, lb->buffer);
}
// FIXME: could pass EllipseParameters and Ellipse3D instead of TwoBodySystem
Entity*
initEllipseEntity(RenderState* rs,
TwoBodySystem* system,
@ -157,37 +199,47 @@ loadScene(GameState* gs, RenderState* rs)
{
initCamera(rs, vec3(0, -75 / SCALING, 0), vec3(0, 0, 0), vec3(0,0,1));
initLights(rs);
double a = 26564.5; // NOTE: semi-major axis in km
double e = 0.7411; // NOTE: eccentricity
double mu = 398601.68; // NOTE: gravitational parameter
double r = 6378; // NOTE: body radius in km
gs->system = systemInit(gravBodyInit(mu, r), orbitInit(a, e));
gs->running = true;
double a = 26564.5; // semi-major axis in km
double e = 0.7411; // eccentricity
double mu = 398601.68; // gravitational parameter
double r = 6378; // body radius in km
GameOrbit* orbit_1 = getFreeOrbit(gs);
systemInit(orbit_1->system, gravBodyInit(mu, r), orbitInit(a, e));
// TODO: streamline the boilerplate in init_X_Entity functions
ShaderProgram* shader = getShaderByName("colored_vertices", rs->gl_ctx);
initRenderGroup(
getFreeRenderGroup(rs), rs->rg_arena, shader, 256, "manual mesh group");
//Entity* ellipse_entity = initEllipseEntity(rs, g_sys.ep, 256);
Entity* ellipse_entity = initEllipseEntity(rs, &gs->system, 256);
setEntityPosition(ellipse_entity, vec3(0, 0, 0));
rotateEntity(ellipse_entity, vec3(1, 0, 0), (float) M_PI / 2);
orbit_1->ellipse_entity = initEllipseEntity(rs, &orbit_1->system, 256);
setEntityPosition(orbit_1->ellipse_entity, vec3(0, 0, 0));
rotateEntity(orbit_1->ellipse_entity, vec3(1, 0, 0), (float) M_PI / 2);
initPlanetEntity(rs, r);
gs->satellite_entity = initSatelliteEntity(rs);
scaleEntity(gs->satellite_entity, 1 / SCALING);
rotateEntity(gs->satellite_entity, vec3(1, 0, 0), (float) M_PI / 2);
setEntityPosition(gs->satellite_entity, gs->system.e3d.vertices[0]);
orbit_1->satellite_entity = initSatelliteEntity(rs);
scaleEntity(orbit_1->satellite_entity, 1 / SCALING);
rotateEntity(orbit_1->satellite_entity, vec3(1, 0, 0), (float) M_PI / 2);
setEntityPosition(orbit_1->satellite_entity,
orbit_1->system.e3d.vertices[0]);
// NOTE: testing multiple orbits
double a_2 = r + 10000; // km
double e_2 = 0;
GameOrbit* orbit_2 = getFreeOrbit(gs);
systemInit(orbit_2->system, gravBodyInit(mu, r), orbitInit(a_2, e_2));
orbit_2->ellipse_entity = initEllipseEntity(rs, &orbit_2->system, 256);
setEntityPosition(orbit_2->ellipse_entity, vec3(0, 0, 0));
rotateEntity(orbit_2->ellipse_entity, vec3(1, 0, 0), (float) M_PI / 2);
}
void
updateSatelliteModel(const TwoBodySystem& sys,
Satellite& sat,
double time_step)
updateSatelliteModel(TwoBodySystem& sys, double time_step)
{
Satellite& sat = sys.sat;
sat.theta = orbitGetPropagatedTrueAnomaly(sys, sat.theta, time_step);
sat.gamma = orbitGetFlightPathAngle(sys.ep.e, sat.theta);
sat.r = orbitGetRadialDistance(sys.ep.e, sys.ep.p, sat.theta);
@ -250,10 +302,16 @@ preFrameCallback(RenderState* rs, void* user_data = nullptr)
u32 diff_ms = gs->sim_time_ms - last_game_tick;
double time_step = double(diff_ms) / 1000;
updateSatelliteModel(gs->system, gs->system.sat, time_step);
gs->system.ep = ellipseInitAE(gs->system.ep.a, gs->system.ep.e);
updateSatelliteEntity(gs->satellite_entity, gs->system.sat);
//updateOrbit(gs->system, ellipse_entity);
for (u32 i = 0; i < gs->num_orbits; i++) {
GameOrbit& orbit = gs->orbits[i];
if (orbit.in_use && orbit.satellite_entity) {
updateSatelliteModel(orbit.system, time_step);
updateSatelliteEntity(orbit.satellite_entity, orbit.system.sat);
// TODO: update EllipseEntity per frame
//updateOrbit(gs->system, ellipse_entity);
}
}
}
}
@ -262,14 +320,18 @@ postFrameCallback(RenderState* rs, void* user_data = nullptr)
{
assert(user_data != nullptr);
GameState* gs = (GameState*) user_data;
GameOrbit& orbit = gs->orbits[0];
assert(orbit.in_use);
gooDraw(rs->handles.window,
gs->system,
orbit.system,
gs->running,
gs->sim_time_ms,
gs->sim_speed);
}
#define DEFAULT_SIM_SPEED 2000
#define GAME_ARENA_SIZE 16 * 1024 * 1024 // 16MB
#define DEFAULT_MAX_ORBITS 10000
int
main()
{
@ -288,8 +350,11 @@ main()
}
GameState gs = {0};
gs.arena = arenaInit(16);
gs.arena = arenaInit(GAME_ARENA_SIZE);
gs.sim_speed = DEFAULT_SIM_SPEED;
gs.max_orbits = DEFAULT_MAX_ORBITS;
gs.orbits = ARENA_ALLOC(gs.arena, GameOrbit, DEFAULT_MAX_ORBITS);
loadScene(&gs, rs);
doRenderLoop(rs, 60, preFrameCallback, postFrameCallback, &gs);
gooFree();

27
src/orbits.cpp

@ -5,21 +5,18 @@
const static uint ELLIPSE_VERT_COUNT = 256;
TwoBodySystem
systemInit(GravBody gb, OrbitalElements el)
{
TwoBodySystem s = {0};
s.body = gb;
s.elements = el;
s.ep = ellipseInitAE(el.a, el.e);
s.e3d = ellipseInit3D(s.ep, ELLIPSE_VERT_COUNT);
s.epsilon = orbitGetSpecificEnergy(s.ep.a, gb.mu);
s.h = orbitGetAngularMomentum(s.ep.p, gb.mu);
s.orbital_period = orbitGetPeriod(s.ep.a, gb.mu);
s.r_apoapsis = s.ep.a - s.ep.c;
s.r_periapsis = 2 * s.ep.a - s.r_apoapsis;
return s;
void
systemInit(TwoBodySystem& system, GravBody gb, OrbitalElements el)
{
system.body = gb;
system.elements = el;
system.ep = ellipseInitAE(el.a, el.e);
system.e3d = ellipseInit3D(system.ep, ELLIPSE_VERT_COUNT);
system.epsilon = orbitGetSpecificEnergy(system.ep.a, gb.mu);
system.h = orbitGetAngularMomentum(system.ep.p, gb.mu);
system.orbital_period = orbitGetPeriod(system.ep.a, gb.mu);
system.r_apoapsis = system.ep.a - system.ep.c;
system.r_periapsis = 2 * system.ep.a - system.r_apoapsis;
}
GravBody

5
src/orbits.h

@ -69,9 +69,8 @@ struct TwoBodySystem
double orbital_period; // in seconds
};
TwoBodySystem
systemInit(GravBody gb, OrbitalElements el);
void
systemInit(TwoBodySystem& system, GravBody gb, OrbitalElements el);
GravBody
gravBodyInit(double mu, double r);

12
tests/orbit_test.cpp

@ -50,7 +50,8 @@ TEST_CASE("orbit propagation, example 4.6", "[orbits]")
double r = EARTH_RADIUS;
double initial_anom = 260 * M_PI / 180; // NOTE: radians
double time_step = 60 * 50; // NOTE: seconds
TwoBodySystem sys = systemInit(gravBodyInit(mu, r), orbitInit(a, e));
TwoBodySystem sys = {0};
systemInit(sys, gravBodyInit(mu, r), orbitInit(a, e));
double E1 = getEccAnomFromTrueAnom(sys.ep.e, initial_anom);
REQUIRE_THAT(E1, WithinAbs(-0.8615, 1e-4));
@ -71,7 +72,8 @@ TEST_CASE("orbit propagation, example 4.6", "[orbits]")
double ecc_anom = getPropagatedEccAnomaly(sys, initial_anom, time_step);
REQUIRE_THAT(ecc_anom, WithinAbs(0.481518, 1e-5));
double true_anom = getPropagatedTrueAnomaly(sys, initial_anom, time_step);
double true_anom =
orbitGetPropagatedTrueAnomaly(sys, initial_anom, time_step);
REQUIRE_THAT(true_anom, WithinAbs(1.1339, 1e-4));
double r2 = orbitGetRadialDistance(sys.ep.e, sys.ep.p, true_anom);
@ -97,7 +99,8 @@ TEST_CASE("time of flight example 4.1a", "[orbits]")
double e = MOLNIYA_ECCENTRICITY;
double mu = EARTH_GRAVITATIONAL_PARAMETER;
double r = EARTH_RADIUS;
TwoBodySystem sys = systemInit(gravBodyInit(mu, r), orbitInit(a, e));
TwoBodySystem sys = {0};
systemInit(sys, gravBodyInit(mu, r), orbitInit(a, e));
// NOTE: get ToF from periapsis to true anomaly at 154.85 degrees
double theta_0 = 0.0;
@ -122,7 +125,8 @@ TEST_CASE("time of flight example 4.2", "[orbits]")
double e = MOLNIYA_ECCENTRICITY;
double mu = EARTH_GRAVITATIONAL_PARAMETER;
double r = EARTH_RADIUS;
TwoBodySystem sys = systemInit(gravBodyInit(mu, r), orbitInit(a, e));
TwoBodySystem sys = {0};
systemInit(sys, gravBodyInit(mu, r), orbitInit(a, e));
// NOTE: get ToF from true anom 230 degrees to true anom at 120 degrees
double theta_1 = 230 * M_PI / 180;

Loading…
Cancel
Save