Browse Source

implement multiple maneuver nodes as linked list

main
cinnaboot 4 years ago
parent
commit
2b7ffe8909
  1. 99
      src/game.cpp
  2. 22
      src/game.h
  3. 10
      src/gooey.cpp
  4. 18
      src/main.cpp

99
src/game.cpp

@ -125,39 +125,59 @@ selectOrbit(GameState* gs, GameOrbit* orbit)
gs->last_selected_orbit = orbit;
}
ManeuverNode*
getFreeManeuver(GameState* gs)
{
for (u32 i = 0; i < gs->max_maneuvers; i++) {
if (gs->maneuver_nodes[i].active == false) {
gs->maneuver_nodes[i].active = true;
return &gs->maneuver_nodes[i];
}
}
LOGF(Error, "No free maneuver nodes\n");
return nullptr;
}
// TODO: appendManeuver(orbit, node) would be better
bool
addManeuver(GameOrbit* orbit,
addManeuver(GameState* gs,
GameOrbit* orbit,
ImpulseType impulse_type,
double true_anomaly,
double impulse_delta_v)
{
ManeuverNode& node = orbit->maneuver;
if (true_anomaly < -M_PI || true_anomaly > M_PI) {
LOGF(Error, "invalid true true_anomaly: %f\n", true_anomaly);
return false;
}
if (node.active) {
LOGF(Warning, "cannot add multiple maneuvers (yet)\n");
return false;
}
if (impulse_delta_v == 0.f) {
LOGF(Warning, "refusing to add maneuver with 0 dv\n");
return false;
}
node.impulse_type = impulse_type;
ManeuverNode* node = getFreeManeuver(gs);
assert(node);
if (orbit->last_maneuver) {
node->previous_maneuver = orbit->last_maneuver;
orbit->last_maneuver->next_maneuver = node;
orbit->last_maneuver = node;
} else {
orbit->first_maneuver = node;
orbit->last_maneuver = node;
}
node->impulse_type = impulse_type;
// TODO: thrust calculations
//double flight_path_angle = orbit->system.sat.gamma;
//node.impulse_vector.x = ...
if (node.impulse_type == ImpulseType::PROGRADE) {
node.true_anomaly = true_anomaly;
node.impulse_delta_v = impulse_delta_v;
node.active = true;
if (node->impulse_type == ImpulseType::PROGRADE) {
node->true_anomaly = true_anomaly;
node->impulse_delta_v = impulse_delta_v;
node->active = true;
return true;
}
@ -167,29 +187,17 @@ addManeuver(GameOrbit* orbit,
return false;
}
void
removeManeuver(GameOrbit* orbit)
{
// TODO: multiple maneuver nodes
ManeuverNode& node = orbit->maneuver;
node.impulse_type = ImpulseType::NONE;
node.true_anomaly = 0.f;
node.impulse_delta_v = 0.f;
node.active = false;
}
// NOTE: test if the maneuver node would have occured between 2 orbit positions
// eg) between 2 time steps
bool
testManeuverStep(const ManeuverNode& maneuver,
testManeuverStep(ManeuverNode* maneuver,
double previous_theta,
double next_theta)
{
if (!maneuver.active)
return false;
assert(maneuver);
// NOTE: clamp angles between 0 and 2 pi to simplify inequalities
double r = orbitClampAngle(maneuver.true_anomaly);
double r = orbitClampAngle(maneuver->true_anomaly);
double clamped_previous_theta = orbitClampAngle(previous_theta);
double clamped_next_theta = orbitClampAngle(next_theta);
@ -209,16 +217,16 @@ testManeuverStep(const ManeuverNode& maneuver,
}
void
applyManeuver(GameOrbit* orbit, double previous_true_anomaly)
applyManeuver(GameOrbit* orbit, ManeuverNode* maneuver)
{
const ManeuverNode& node = orbit->maneuver;
TwoBodySystem& sys = orbit->system;
assert(maneuver);
// FIXME: assuming prograde impulse vector
assert(node.impulse_type == ImpulseType::PROGRADE);
assert(maneuver->impulse_type == ImpulseType::PROGRADE);
// re-calculate state vectors at the maneuver node
double theta = node.true_anomaly;
double theta = maneuver->true_anomaly;
double mu = sys.body.mu;
double r = orbitGetRadialDistance(sys.ep.e, sys.ep.p, theta);
@ -229,7 +237,7 @@ applyManeuver(GameOrbit* orbit, double previous_true_anomaly)
vel = sys.rotation * vel;
// apply impulse along velocity vector
dvec3 impulse = glm::normalize(vel) * node.impulse_delta_v;
dvec3 impulse = glm::normalize(vel) * maneuver->impulse_delta_v;
vel = vel + impulse;
sys.elements = orbitGetElementsFromStateVectors(pos, vel, mu);
systemInit(orbit->system, sys.body, sys.elements);
@ -245,6 +253,29 @@ applyManeuver(GameOrbit* orbit, double previous_true_anomaly)
updateGLBuffer(buf, orbit->e3d.vertices);
}
void
removeManeuver(GameOrbit* orbit, ManeuverNode* maneuver)
{
assert(maneuver);
// FIXME: we're only removing the first maneuver for now
assert(maneuver == orbit->first_maneuver);
if (orbit->last_maneuver == maneuver) {
orbit->first_maneuver = nullptr;
orbit->last_maneuver = nullptr;
} else {
orbit->first_maneuver = maneuver->next_maneuver;
maneuver->previous_maneuver = nullptr;
}
maneuver->impulse_type = ImpulseType::NONE;
maneuver->true_anomaly = 0.f;
maneuver->impulse_delta_v = 0.f;
maneuver->active = false;
maneuver->previous_maneuver = nullptr;
maneuver->next_maneuver = nullptr;
}
// internal

22
src/game.h

@ -40,16 +40,16 @@ struct ManeuverNode
double impulse_delta_v;
bool active;
// TODO: thrust calculations
//vec3 impulse_vector;
ManeuverNode* previous_maneuver;
ManeuverNode* next_maneuver;
};
struct GameOrbit
{
TwoBodySystem system;
Ellipse3D e3d;
// TODO: multiple maneuvers
ManeuverNode maneuver;
ManeuverNode* first_maneuver;
ManeuverNode* last_maneuver;
Entity* grav_body;
Entity* ellipse_entity;
@ -71,6 +71,9 @@ struct GameState
u32 num_orbits;
u32 max_orbits;
ManeuverNode* maneuver_nodes;
u32 max_maneuvers;
GameOrbit* last_selected_orbit;
Entity* coord_overlay;
};
@ -89,15 +92,16 @@ void ellipse3DUpdate(dmat3 rotation, EllipseParameters ep, Ellipse3D& e3d);
void selectOrbit(GameState* gs, GameOrbit* orbit);
bool addManeuver(GameOrbit* orbit,
bool addManeuver(GameState* gs,
GameOrbit* orbit,
ImpulseType impulse_type,
double true_anomaly,
double impulse_delta_v);
void removeManeuver(GameOrbit* orbit);
bool testManeuverStep(const ManeuverNode& maneuver,
bool testManeuverStep(ManeuverNode* maneuver,
double previous_theta,
double next_theta);
void applyManeuver(GameOrbit* orbit, double previous_true_anomaly);
void applyManeuver(GameOrbit* orbit, ManeuverNode* node);
void removeManeuver(GameOrbit* orbit, ManeuverNode* maneuver);

10
src/gooey.cpp

@ -273,15 +273,15 @@ drawManeuverWindow(GameState* gs)
static float dv = 0.f;
if (orbit) {
if (orbit->maneuver.active) {
if (orbit->last_maneuver) {
Text("Orbital Maneuver");
Indent();
Text("true anomaly: %f", orbit->maneuver.true_anomaly);
Text("impulse dv: %f km/s", orbit->maneuver.impulse_delta_v);
Text("true anomaly: %f", orbit->first_maneuver->true_anomaly);
Text("impulse dv: %f km/s", orbit->first_maneuver->impulse_delta_v);
Unindent();
if (Button("remove")) {
removeManeuver(orbit);
removeManeuver(orbit, orbit->first_maneuver);
item_current_idx = 0;
anom = 0.f;
dv = 0.f;
@ -307,7 +307,7 @@ drawManeuverWindow(GameState* gs)
InputFloat("impulse dv, km/s", &dv, 0.1, 4.0, "%.1f");
if (Button("apply")) {
if (!addManeuver(orbit, ImpulseType::PROGRADE, anom, dv)) {
if (!addManeuver(gs, orbit, ImpulseType::PROGRADE, anom, dv)) {
// flash a color or something?
}
}

18
src/main.cpp

@ -258,7 +258,12 @@ loadScene(GameState* gs, RenderState* rs)
//GameOrbit* go_2 = loadOrbit(gs, rs, body, el2, rg, "sat_02");
double v_transfer = orbitGetTransferVelocity(go_1->system, el2);
addManeuver(go_1, ImpulseType::PROGRADE, DEG2RAD(180), v_transfer);
addManeuver(gs, go_1, ImpulseType::PROGRADE, DEG2RAD(180), v_transfer);
// FIXME: can't get circularization here unless we simulate the transfer
// orbit ahead of time, eg) applyManeuver to a dummy orbit
// could also add a ImpulseType::CIRCULARIZE and calculate in
// applyManeuver()
addManeuver(gs, go_1, ImpulseType::PROGRADE, DEG2RAD(180), 0.500);
return true;
}
@ -301,12 +306,13 @@ updateOrbit(GameOrbit* orbit, bool running, double time_step)
updateSatelliteModel(orbit->system, time_step);
setEntityPosition(orbit->satellite_entity, orbit->system.sat.position);
if (testManeuverStep(orbit->maneuver,
if (orbit->first_maneuver
&& testManeuverStep(orbit->first_maneuver,
previous_true_anom,
orbit->system.sat.theta))
{
applyManeuver(orbit, previous_true_anom);
removeManeuver(orbit);
applyManeuver(orbit, orbit->first_maneuver);
removeManeuver(orbit, orbit->first_maneuver);
}
}
}
@ -333,6 +339,7 @@ postFrameCallback(RenderState* rs, void* user_data = nullptr)
#define DEFAULT_SIM_SPEED 500
#define GAME_ARENA_SIZE 16 * 1024 * 1024 // 16MB
#define DEFAULT_MAX_ORBITS 10000
#define DEFAULT_MANUEVER_NODES 3 * DEFAULT_MAX_ORBITS
int
main()
{
@ -355,6 +362,9 @@ main()
gs.sim_speed = DEFAULT_SIM_SPEED;
gs.max_orbits = DEFAULT_MAX_ORBITS;
gs.orbits = ARENA_ALLOC(gs.arena, GameOrbit, DEFAULT_MAX_ORBITS);
gs.max_maneuvers = DEFAULT_MANUEVER_NODES;
gs.maneuver_nodes =
ARENA_ALLOC(gs.arena, ManeuverNode, DEFAULT_MANUEVER_NODES);
if (!loadScene(&gs, rs)) {
LOGF(Error, "Error loading scene\n");

Loading…
Cancel
Save