|
|
|
@ -125,39 +125,59 @@ selectOrbit(GameState* gs, GameOrbit* orbit) |
|
|
|
gs->last_selected_orbit = 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 |
|
|
|
bool |
|
|
|
addManeuver(GameOrbit* orbit, |
|
|
|
addManeuver(GameState* gs, |
|
|
|
|
|
|
|
GameOrbit* orbit, |
|
|
|
ImpulseType impulse_type, |
|
|
|
ImpulseType impulse_type, |
|
|
|
double true_anomaly, |
|
|
|
double true_anomaly, |
|
|
|
double impulse_delta_v) |
|
|
|
double impulse_delta_v) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ManeuverNode& node = orbit->maneuver; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (true_anomaly < -M_PI || true_anomaly > M_PI) { |
|
|
|
if (true_anomaly < -M_PI || true_anomaly > M_PI) { |
|
|
|
LOGF(Error, "invalid true true_anomaly: %f\n", true_anomaly); |
|
|
|
LOGF(Error, "invalid true true_anomaly: %f\n", true_anomaly); |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (node.active) { |
|
|
|
|
|
|
|
LOGF(Warning, "cannot add multiple maneuvers (yet)\n"); |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (impulse_delta_v == 0.f) { |
|
|
|
if (impulse_delta_v == 0.f) { |
|
|
|
LOGF(Warning, "refusing to add maneuver with 0 dv\n"); |
|
|
|
LOGF(Warning, "refusing to add maneuver with 0 dv\n"); |
|
|
|
return false; |
|
|
|
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
|
|
|
|
// TODO: thrust calculations
|
|
|
|
//double flight_path_angle = orbit->system.sat.gamma;
|
|
|
|
//double flight_path_angle = orbit->system.sat.gamma;
|
|
|
|
//node.impulse_vector.x = ...
|
|
|
|
//node.impulse_vector.x = ...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (node->impulse_type == ImpulseType::PROGRADE) { |
|
|
|
if (node.impulse_type == ImpulseType::PROGRADE) { |
|
|
|
node->true_anomaly = true_anomaly; |
|
|
|
node.true_anomaly = true_anomaly; |
|
|
|
node->impulse_delta_v = impulse_delta_v; |
|
|
|
node.impulse_delta_v = impulse_delta_v; |
|
|
|
node->active = true; |
|
|
|
node.active = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -167,29 +187,17 @@ addManeuver(GameOrbit* orbit, |
|
|
|
return false; |
|
|
|
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
|
|
|
|
// NOTE: test if the maneuver node would have occured between 2 orbit positions
|
|
|
|
// eg) between 2 time steps
|
|
|
|
// eg) between 2 time steps
|
|
|
|
bool |
|
|
|
bool |
|
|
|
testManeuverStep(const ManeuverNode& maneuver, |
|
|
|
testManeuverStep(ManeuverNode* maneuver, |
|
|
|
double previous_theta, |
|
|
|
double previous_theta, |
|
|
|
double next_theta) |
|
|
|
double next_theta) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!maneuver.active) |
|
|
|
assert(maneuver); |
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NOTE: clamp angles between 0 and 2 pi to simplify inequalities
|
|
|
|
// 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_previous_theta = orbitClampAngle(previous_theta); |
|
|
|
double clamped_next_theta = orbitClampAngle(next_theta); |
|
|
|
double clamped_next_theta = orbitClampAngle(next_theta); |
|
|
|
|
|
|
|
|
|
|
|
@ -209,16 +217,16 @@ testManeuverStep(const ManeuverNode& maneuver, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
void |
|
|
|
applyManeuver(GameOrbit* orbit, double previous_true_anomaly) |
|
|
|
applyManeuver(GameOrbit* orbit, ManeuverNode* maneuver) |
|
|
|
{ |
|
|
|
{ |
|
|
|
const ManeuverNode& node = orbit->maneuver; |
|
|
|
|
|
|
|
TwoBodySystem& sys = orbit->system; |
|
|
|
TwoBodySystem& sys = orbit->system; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert(maneuver); |
|
|
|
// FIXME: assuming prograde impulse vector
|
|
|
|
// 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
|
|
|
|
// re-calculate state vectors at the maneuver node
|
|
|
|
double theta = node.true_anomaly; |
|
|
|
double theta = maneuver->true_anomaly; |
|
|
|
double mu = sys.body.mu; |
|
|
|
double mu = sys.body.mu; |
|
|
|
double r = orbitGetRadialDistance(sys.ep.e, sys.ep.p, theta); |
|
|
|
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; |
|
|
|
vel = sys.rotation * vel; |
|
|
|
|
|
|
|
|
|
|
|
// apply impulse along velocity vector
|
|
|
|
// 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; |
|
|
|
vel = vel + impulse; |
|
|
|
sys.elements = orbitGetElementsFromStateVectors(pos, vel, mu); |
|
|
|
sys.elements = orbitGetElementsFromStateVectors(pos, vel, mu); |
|
|
|
systemInit(orbit->system, sys.body, sys.elements); |
|
|
|
systemInit(orbit->system, sys.body, sys.elements); |
|
|
|
@ -245,6 +253,29 @@ applyManeuver(GameOrbit* orbit, double previous_true_anomaly) |
|
|
|
updateGLBuffer(buf, orbit->e3d.vertices); |
|
|
|
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
|
|
|
|
// internal
|
|
|
|
|
|
|
|
|
|
|
|
|