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, * - make an 'overlay' graphic for things like apoapsis, perisapsis, f1, f2,
* flight path * flight path
* - impulsive orbital maneuvers * - impulsive orbital maneuvers
* - test multiple orbits
* - Hohmman transfer orbits * - Hohmman transfer orbits
* - patched conic method for transferring between 2 grav bodies * - 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 vec4 g_light_color = vec4(0.5, 0.5, 0.5, 1);
const uvec4 g_light_intensities = uvec4(1, 0, 0, 0); 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 struct GameState
{ {
bool running; bool running;
@ -41,10 +51,41 @@ struct GameState
u64 sim_time_ms; u64 sim_time_ms;
float sim_speed; float sim_speed;
TwoBodySystem system; // FIXME: we're going to need more than 1 system... GameOrbit* orbits;
Entity* satellite_entity; 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 void
initCamera(RenderState* rs, vec3 cam_pos, vec3 cam_focus, vec3 cam_up) initCamera(RenderState* rs, vec3 cam_pos, vec3 cam_focus, vec3 cam_up)
@ -72,6 +113,7 @@ initLights(RenderState* rs)
updateGLBuffer(lights_ubo, lb->buffer); updateGLBuffer(lights_ubo, lb->buffer);
} }
// FIXME: could pass EllipseParameters and Ellipse3D instead of TwoBodySystem
Entity* Entity*
initEllipseEntity(RenderState* rs, initEllipseEntity(RenderState* rs,
TwoBodySystem* system, 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)); initCamera(rs, vec3(0, -75 / SCALING, 0), vec3(0, 0, 0), vec3(0,0,1));
initLights(rs); 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; 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 // TODO: streamline the boilerplate in init_X_Entity functions
ShaderProgram* shader = getShaderByName("colored_vertices", rs->gl_ctx); ShaderProgram* shader = getShaderByName("colored_vertices", rs->gl_ctx);
initRenderGroup( initRenderGroup(
getFreeRenderGroup(rs), rs->rg_arena, shader, 256, "manual mesh group"); getFreeRenderGroup(rs), rs->rg_arena, shader, 256, "manual mesh group");
//Entity* ellipse_entity = initEllipseEntity(rs, g_sys.ep, 256); orbit_1->ellipse_entity = initEllipseEntity(rs, &orbit_1->system, 256);
Entity* ellipse_entity = initEllipseEntity(rs, &gs->system, 256); setEntityPosition(orbit_1->ellipse_entity, vec3(0, 0, 0));
setEntityPosition(ellipse_entity, vec3(0, 0, 0)); rotateEntity(orbit_1->ellipse_entity, vec3(1, 0, 0), (float) M_PI / 2);
rotateEntity(ellipse_entity, vec3(1, 0, 0), (float) M_PI / 2);
initPlanetEntity(rs, r); initPlanetEntity(rs, r);
gs->satellite_entity = initSatelliteEntity(rs); orbit_1->satellite_entity = initSatelliteEntity(rs);
scaleEntity(gs->satellite_entity, 1 / SCALING); scaleEntity(orbit_1->satellite_entity, 1 / SCALING);
rotateEntity(gs->satellite_entity, vec3(1, 0, 0), (float) M_PI / 2); rotateEntity(orbit_1->satellite_entity, vec3(1, 0, 0), (float) M_PI / 2);
setEntityPosition(gs->satellite_entity, gs->system.e3d.vertices[0]); 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 void
updateSatelliteModel(const TwoBodySystem& sys, updateSatelliteModel(TwoBodySystem& sys, double time_step)
Satellite& sat,
double time_step)
{ {
Satellite& sat = sys.sat;
sat.theta = orbitGetPropagatedTrueAnomaly(sys, sat.theta, time_step); sat.theta = orbitGetPropagatedTrueAnomaly(sys, sat.theta, time_step);
sat.gamma = orbitGetFlightPathAngle(sys.ep.e, sat.theta); sat.gamma = orbitGetFlightPathAngle(sys.ep.e, sat.theta);
sat.r = orbitGetRadialDistance(sys.ep.e, sys.ep.p, 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; u32 diff_ms = gs->sim_time_ms - last_game_tick;
double time_step = double(diff_ms) / 1000; double time_step = double(diff_ms) / 1000;
updateSatelliteModel(gs->system, gs->system.sat, time_step); for (u32 i = 0; i < gs->num_orbits; i++) {
gs->system.ep = ellipseInitAE(gs->system.ep.a, gs->system.ep.e); GameOrbit& orbit = gs->orbits[i];
updateSatelliteEntity(gs->satellite_entity, gs->system.sat);
//updateOrbit(gs->system, ellipse_entity); 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); assert(user_data != nullptr);
GameState* gs = (GameState*) user_data; GameState* gs = (GameState*) user_data;
GameOrbit& orbit = gs->orbits[0];
assert(orbit.in_use);
gooDraw(rs->handles.window, gooDraw(rs->handles.window,
gs->system, orbit.system,
gs->running, gs->running,
gs->sim_time_ms, gs->sim_time_ms,
gs->sim_speed); gs->sim_speed);
} }
#define DEFAULT_SIM_SPEED 2000 #define DEFAULT_SIM_SPEED 2000
#define GAME_ARENA_SIZE 16 * 1024 * 1024 // 16MB
#define DEFAULT_MAX_ORBITS 10000
int int
main() main()
{ {
@ -288,8 +350,11 @@ main()
} }
GameState gs = {0}; GameState gs = {0};
gs.arena = arenaInit(16); gs.arena = arenaInit(GAME_ARENA_SIZE);
gs.sim_speed = DEFAULT_SIM_SPEED; 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); loadScene(&gs, rs);
doRenderLoop(rs, 60, preFrameCallback, postFrameCallback, &gs); doRenderLoop(rs, 60, preFrameCallback, postFrameCallback, &gs);
gooFree(); gooFree();

27
src/orbits.cpp

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

5
src/orbits.h

@ -69,9 +69,8 @@ struct TwoBodySystem
double orbital_period; // in seconds double orbital_period; // in seconds
}; };
void
TwoBodySystem systemInit(TwoBodySystem& system, GravBody gb, OrbitalElements el);
systemInit(GravBody gb, OrbitalElements el);
GravBody GravBody
gravBodyInit(double mu, double r); 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 r = EARTH_RADIUS;
double initial_anom = 260 * M_PI / 180; // NOTE: radians double initial_anom = 260 * M_PI / 180; // NOTE: radians
double time_step = 60 * 50; // NOTE: seconds 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); double E1 = getEccAnomFromTrueAnom(sys.ep.e, initial_anom);
REQUIRE_THAT(E1, WithinAbs(-0.8615, 1e-4)); 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); double ecc_anom = getPropagatedEccAnomaly(sys, initial_anom, time_step);
REQUIRE_THAT(ecc_anom, WithinAbs(0.481518, 1e-5)); 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)); REQUIRE_THAT(true_anom, WithinAbs(1.1339, 1e-4));
double r2 = orbitGetRadialDistance(sys.ep.e, sys.ep.p, true_anom); 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 e = MOLNIYA_ECCENTRICITY;
double mu = EARTH_GRAVITATIONAL_PARAMETER; double mu = EARTH_GRAVITATIONAL_PARAMETER;
double r = EARTH_RADIUS; 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 // NOTE: get ToF from periapsis to true anomaly at 154.85 degrees
double theta_0 = 0.0; double theta_0 = 0.0;
@ -122,7 +125,8 @@ TEST_CASE("time of flight example 4.2", "[orbits]")
double e = MOLNIYA_ECCENTRICITY; double e = MOLNIYA_ECCENTRICITY;
double mu = EARTH_GRAVITATIONAL_PARAMETER; double mu = EARTH_GRAVITATIONAL_PARAMETER;
double r = EARTH_RADIUS; 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 // NOTE: get ToF from true anom 230 degrees to true anom at 120 degrees
double theta_1 = 230 * M_PI / 180; double theta_1 = 230 * M_PI / 180;

Loading…
Cancel
Save