diff --git a/src/gooey.cpp b/src/gooey.cpp index 6d7d33d..6f4eb49 100644 --- a/src/gooey.cpp +++ b/src/gooey.cpp @@ -50,12 +50,23 @@ gooDraw(SDL_Window* window, orbital_elements& orbit) ImGui::NewFrame(); ImGui::SetNextWindowPos(ImVec2(0,0)); - ImGui::SetNextWindowSize(ImVec2(300,400)); + ImGui::SetNextWindowSize(ImVec2(300,270)); ImGui::Begin("Orbital Elements"); + ImGui::Text("iota, inclination: %f", orbit.iota); + ImGui::Text("omega, argument of periapsis: %f", orbit.omega); + ImGui::Text("mu, gravitational parameter: %f", orbit.mu); + ImGui::Text("nu, true anomoly: %f", orbit.nu); + ImGui::Spacing(); + + ImGui::Separator(); + ImGui::Spacing(); + ImGui::Text("Ellipse Parameters:"); ImGui::Text("a: %f km", orbit.ep.a); + ImGui::Text("b: %f km", orbit.ep.b); ImGui::Text("e: %f", orbit.ep.e); - ImGui::Text("mu: %f km^3/s^2", orbit.mu); + ImGui::Text("c: %f km", orbit.ep.c); + ImGui::Text("a:"); ImGui::SameLine(); @@ -63,7 +74,7 @@ gooDraw(SDL_Window* window, orbital_elements& orbit) ImGui::Text("e:"); ImGui::SameLine(); - ImGui::InputDouble("##orbit.ep.e", &orbit.ep.e, 0.1f); + ImGui::InputDouble("##orbit.ep.e", &orbit.ep.e, 0.01f); ImGui::End(); diff --git a/src/main.cpp b/src/main.cpp index be31a17..e0cfde3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,7 +17,7 @@ const double SCALING = 0.001; static orbital_elements g_orbit = {}; -static ellipse_3d g_ellipse; +static ellipse_3d g_ellipse3d; simple_mesh* @@ -76,7 +76,37 @@ initOrbit() } void -doFrameCallbackPre(render_state* rs) +updateSatellitePosition(entity& satellite) +{ + const static glm::mat4 xform = + glm::rotate(glm::mat4(1.0), (float) M_PI_2, glm::vec3(1, 0, 0)); + + // TODO: decouple framerate from time_step + unsigned int time_step = 100; // NOTE: seconds + + g_orbit.nu = getPropagatedTrueAnomaly(g_orbit, g_orbit.nu, time_step); + double r2 = getRadialPosition(g_orbit.ep, g_orbit.nu); + glm::vec2 coords = polarToRect(g_orbit.nu, r2); + glm::vec3 v = glm::vec3(coords, 0); + entSetWorldPosition(satellite, xform * glm::vec4(v.x, v.y, v.z, 1)); +} + +// NOTE: use validateEllipse(orbit.ep) before calling to avoid failing +// assertions +void +updateOrbit(orbital_elements& orbit, ellipse_3d& e3d, entity& ellipse_entity) +{ + orbit.ep = constructEllipseAE(orbit.ep.a, orbit.ep.e); + ellipse3DUpdate(orbit.ep, e3d); + + for (uint i = 0; i < e3d.vert_count; i++) + ellipse_entity.mesh->vertices[i] = e3d.vertices[i]; + + entUpdateSimpleMesh(ellipse_entity, ellipse_entity.mesh, GL_LINE_LOOP); +} + +void +preFrameCallback(render_state* rs) { // handle input static input_state is = {}; @@ -91,50 +121,40 @@ doFrameCallbackPre(render_state* rs) if (is.window_closed || is.escape) rs->running = false; - // update orbital elements/ellipse_3d - g_orbit.ep = constructEllipseAE(g_orbit.ep.a, g_orbit.ep.e); - entity& ellipse_entity = rs->render_groups[0].entities[0]; - - // TODO: fix this - double angle = 2 * M_PI / g_ellipse.vert_count; - for (uint i = 0; i < g_ellipse.vert_count; i++) { - double a = angle * i; - double r = g_orbit.ep.a * - (1 - pow(g_orbit.ep.e, 2)) / (1 + g_orbit.ep.e * cos(a)); - g_ellipse.vertices[i] = glm::vec3(polarToRect(a, r), 0); - // NOTE: update mesh - ellipse_entity.mesh->vertices[i] = g_ellipse.vertices[i]; - // NOTE: update entity.render_object - entUpdateSimpleMesh(ellipse_entity, ellipse_entity.mesh, GL_LINE_LOOP); - } - - - // update satellite position - const static glm::mat4 xform = - glm::rotate(glm::mat4(1.0), (float) M_PI_2, glm::vec3(1, 0, 0)); - entity& satellite = rs->render_groups[0].entities[2]; - - // TODO: decouple framerate from time_step - unsigned int time_step = 100; // NOTE: seconds - - g_orbit.nu = getPropagatedTrueAnomaly(g_orbit, g_orbit.nu, time_step); - double r2 = getRadialPosition(g_orbit.ep, g_orbit.nu); - glm::vec2 coords = polarToRect(g_orbit.nu, r2); - glm::vec3 v = glm::vec3(coords, 0); - entSetWorldPosition(satellite, xform * glm::vec4(v.x, v.y, v.z, 1)); + updateSatellitePosition(rs->render_groups[0].entities[2]); } void -doFrameCallbackPost(render_state* rs) +postFrameCallback(render_state* rs) { - gooDraw(rs->handles->window, g_orbit); + static orbital_elements c_orb = {}; + orbitCopy(g_orbit, c_orb); + gooDraw(rs->handles->window, c_orb); + + // TODO: will need more validation from GUI as added + if (!ellipsesEqual(c_orb.ep, g_orbit.ep)) { + // NOTE: handle the case where semimajor axis lowered with low + // eccentricity would fail validation + if (c_orb.ep.a < g_orbit.ep.a && c_orb.ep.a > 0 + && c_orb.ep.e == g_orbit.ep.e) + { + c_orb.ep.b = c_orb.ep.a * sqrt(1 - pow(c_orb.ep.e, 2.0)); + } + + if (validateEllipse(c_orb.ep)) { + c_orb.ep = constructEllipseAE(c_orb.ep.a, c_orb.ep.e); + ellipseCopy(c_orb.ep, g_orbit.ep); + entity& ellipse_entity = rs->render_groups[0].entities[0]; + updateOrbit(g_orbit, g_ellipse3d, ellipse_entity); + } + } } int main() { render_state* rs = renInit("orbital shipping", - glm::vec2(1920, 1080), + glm::vec2(1280, 720), SDL_INIT_TIMER); if (rs == nullptr) { @@ -163,8 +183,8 @@ main() rs->render_group_count = 1; entity& ellipse_entity = rs->render_groups[0].entities[0]; - g_ellipse = constructEllipse3D(ep, 256); - simple_mesh* sm = constructEllipseMesh(g_ellipse, glm::vec3(255, 0, 255)); + g_ellipse3d = constructEllipse3D(ep, 256); + simple_mesh* sm = constructEllipseMesh(g_ellipse3d, glm::vec3(255, 0, 255)); entInitMesh(ellipse_entity, sm, GL_LINE_LOOP); entRotate(ellipse_entity, (float) M_PI_2, glm::vec3(1, 0, 0)); @@ -177,9 +197,9 @@ main() sm = createSatelliteMesh(); entInitMesh(satellite_entity, sm, GL_TRIANGLES); entRotate(satellite_entity, (float) M_PI_2, glm::vec3(1, 0, 0)); - entSetWorldPosition(satellite_entity, g_ellipse.vertices[0]); + entSetWorldPosition(satellite_entity, g_ellipse3d.vertices[0]); - renDoRenderLoop(rs, 60 , doFrameCallbackPre, doFrameCallbackPost); + renDoRenderLoop(rs, 60 , preFrameCallback, postFrameCallback); // TODO: clean up mesh pointers? don't remember if renderer does that // automatically diff --git a/src/orbits.cpp b/src/orbits.cpp index dc05ee0..53274e8 100644 --- a/src/orbits.cpp +++ b/src/orbits.cpp @@ -24,9 +24,43 @@ constructEllipseAE(double a, double e) } bool -validateEllipse(ellipse_parameters) +validateEllipse(const ellipse_parameters ep) { - return false; + return (ep.a > 0 && + ep.b > 0 && + ep.a >= ep.b && + ep.e >= 0 && + ep.e < 1); +} + +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; } ellipse_3d @@ -37,17 +71,23 @@ constructEllipse3D(ellipse_parameters ep, uint vert_count) 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); - double angle = 2 * M_PI / vert_count; + ellipse3DUpdate(ep, e3d); + return e3d; +} - for (uint i = 0; i < vert_count; i++) { +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); } - - return e3d; } double diff --git a/src/orbits.h b/src/orbits.h index c185d52..9a363bc 100644 --- a/src/orbits.h +++ b/src/orbits.h @@ -24,7 +24,7 @@ struct orbital_elements ellipse_parameters ep; double iota; // NOTE: (ι) inclination double omega; // NOTE: (ω) argument of periapsis - double mu; // NOTE: (μ) gravittional parameter + double mu; // NOTE: (μ) gravitational parameter double nu; // NOTE: (ν) true anomaly }; @@ -43,15 +43,24 @@ ellipse_parameters constructEllipseAE(double a, double e); bool -validateEllipse(ellipse_parameters); +validateEllipse(const ellipse_parameters); + +bool +ellipsesEqual(ellipse_parameters& e1, ellipse_parameters& e2); + +void +ellipseCopy(const ellipse_parameters& e1, ellipse_parameters& e2); + +void +orbitCopy(const orbital_elements& o1, orbital_elements& o2); // NOTE: create vertices for a 3d ellipse // NOTE: all vertices are in the x/y plane with z = 0 ellipse_3d constructEllipse3D(ellipse_parameters ep, uint vert_count); -bool -ellipsesEqual(ellipse_parameters e1, ellipse_parameters e2); +void +ellipse3DUpdate(ellipse_parameters ep, ellipse_3d& e3d); /* NOTE: how-to propagate orbit position given initial true anomaly, semimajor * axis, mean motion, and eccentricity: ref) section 4.4, Kepler's Problem,