feat: add particle map

This commit is contained in:
Cat Flynn 2024-08-20 00:35:43 +01:00
parent a5ff616e86
commit 56aa50251b
10 changed files with 140 additions and 33 deletions

9
README.md Normal file
View File

@ -0,0 +1,9 @@
# Skein
Skein is a library for efficiently simulating Keplerian astrodynamics.
## Usage
Kepler models orbiting bodies as particles. Particles are zero-dimensional objects which can be on elliptical orbits around other particles. The orbited particle is assumed to make up the overwhelming majority of the mass of the combined two-object system.

View File

@ -4,6 +4,7 @@ project(skein)
add_library(skein STATIC
src/orbit.cpp
src/particle.cpp
src/particlemap.cpp
)
target_include_directories(skein PUBLIC

View File

@ -2,14 +2,19 @@
#include <skein/orbit.h>
#include <string>
class Particle
{
public:
Particle() = default;
Particle(const std::string& id, double mass);
Particle(const Particle& other);
~Particle() = default;
Orbit& getOrbit();
const std::string& getId() const;
double getMass() const;
private:
Orbit _orbit;
const std::string _id;
const double _mass;
};

View File

@ -0,0 +1,27 @@
#pragma once
#include "skein/particle.h"
#include <string>
#include <map>
class ParticleMap
{
public:
ParticleMap() = default;
~ParticleMap() = default;
// providing these as two methods keeps things unambiguous - manipulating particles
// is just done for setup
const Particle& getParticle(const std::string& id) const;
glm::vec3 getParticlePosition(const std::string& id, double time) const;
const Orbit& getOrbit(const std::string& id) const;
void setParticle(const Particle& particle);
void setRelationship(const std::string& parentId, const std::string& childId, const Orbit& orbit);
private:
std::map<std::string, Particle> _particles;
std::map<std::string, std::string> _relationships;
std::map<std::string, Orbit> _orbits;
};

View File

@ -1,7 +1,21 @@
#include "skein/particle.h"
Orbit& Particle::getOrbit()
Particle::Particle(const std::string& id, double mass)
: _id(id), _mass(mass)
{
return _orbit;
}
Particle::Particle(const Particle& other)
: _id(other.getId()), _mass(other.getMass())
{
}
const std::string& Particle::getId() const
{
return _id;
}
double Particle::getMass() const
{
return _mass;
}

View File

@ -0,0 +1,39 @@
#include "skein/particlemap.h"
#include "skein/particle.h"
const Particle& ParticleMap::getParticle(const std::string& id) const
{
return _particles.at(id);
}
const Orbit& ParticleMap::getOrbit(const std::string& id) const
{
return _orbits.at(id);
}
glm::vec3 ParticleMap::getParticlePosition(const std::string& id, double time) const
{
// TODO: actually nest stuff so position is determined from all parents
if (_orbits.find(id) != _orbits.end())
{
const Orbit& orbit = _orbits.at(id);
return orbit.getPosition(time);
}
return {0,0,0};
}
void ParticleMap::setParticle(const Particle& particle)
{
_particles.insert({particle.getId(), particle});
}
void ParticleMap::setRelationship(const std::string& parentId, const std::string& childId, const Orbit& orbit)
{
// map children to parent - children can only have one parent, so we use the map to
// identify the parent directly using the child as the key
_relationships.insert({childId, parentId});
_orbits.insert({childId, orbit});
}

View File

@ -110,7 +110,7 @@ GLuint compileShaderProgram(const std::string& fragShaderPath)
void updateProjectionMatrix(GLuint shaderProgram)
{
float left = -aspect_, right = aspect_, bottom = -1.0, top = 1.0, near = -1.0, far = 1.0;
float left = -aspect_, right = aspect_, bottom = -1.0, top = 1.0, near = -2.0, far = 1.0;
glm::mat4 projection = glm::ortho(left, right, bottom, top, near, far);
GLint projectionLocation = getShaderUniformLocation(shaderProgram, "_Projection");
glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, &projection[0][0]);

View File

@ -47,6 +47,7 @@
#include <skein/orbit.h>
#include <skein/particle.h>
#include <skein/particlemap.h>
// INPUT!
//
@ -92,19 +93,26 @@ int main()
GLuint litProgram = compileShaderProgram("./frag_lit.glsl");
GLuint unlitProgram = compileShaderProgram("./frag_unlit.glsl");
// set up scene
Icosphere planet(0.2, 3, litProgram);
// set parameters of moon's orbit around earth
Orbit orbit;
orbit.setSemiMajorAxis(1.0); // in km
// TODO: implement zoom
//orbit.setSemiMajorAxis(384748); // in km
orbit.setEccentricity(0.055);
orbit.setInclination(5.15); // degreees
orbit.setArgumentOfPeriapsis(318.15); // in the case of the moon these last two values are
orbit.setLongitudeOfAscendingNode(60.0); // pretty much constantly changing so use whatever
Particle particle;
Orbit& orbit = particle.getOrbit();
orbit.setSemiMajorAxis(.75);
orbit.setEccentricity(.5);
orbit.setInclination(3.142 / 2.0 + 1);
orbit.setArgumentOfPeriapsis(2.0);
orbit.setLongitudeOfAscendingNode(0.1);
ParticleVisualizer particleVisualizer(particle, litProgram, unlitProgram);
OrbitVisualizer orbitVisualizer(orbit, unlitProgram);
// TODO: add something in a nice eccentric orbit around the moon
// make the earth-moon system
ParticleMap map;
map.setParticle({"moon", 7.3e22});
map.setParticle({"earth", 5.9e24});
map.setRelationship("moon", "earth", orbit);
// TODO: there is a bug where re-ordering the visualizers breaks rendering
ParticleVisualizer moonVis(map, "moon", 0.1, litProgram, unlitProgram);
ParticleVisualizer earthVis(map, "earth", 0.2, litProgram, unlitProgram);
OrbitVisualizer orbitVis(orbit, unlitProgram);
// register input
glfwSetKeyCallback(window, keyCallback);
@ -148,9 +156,9 @@ int main()
glClearColor(0.2, 0.3, 0.3, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
planet.render(time);
particleVisualizer.render(time);
orbitVisualizer.render(time);
earthVis.render(time);
moonVis.render(time);
orbitVis.render(time);
glfwSwapBuffers(window);
}

View File

@ -1,21 +1,24 @@
#include "particlevisualizer.hpp"
ParticleVisualizer::ParticleVisualizer(Particle& particle, GLuint sphereShaderProgram, GLuint widgetShaderProgram)
: _particle(particle), _sphere({0.07, 2, sphereShaderProgram}), _widget(widgetShaderProgram)
ParticleVisualizer::ParticleVisualizer(const ParticleMap& map, const std::string& particleId, float radius,
GLuint sphereShaderProgram, GLuint widgetShaderProgram)
: _map(map), _particleId(particleId), _sphere({radius, 2, sphereShaderProgram}), _widget(widgetShaderProgram)
{
}
void ParticleVisualizer::render(float time)
{
const Orbit& orbit = _particle.getOrbit();
// TODO: get mean anomly from particle which has the mass!!
const float meanAnomaly = time;
glm::vec3 pos = orbit.getPosition(meanAnomaly);
glm::vec3 pos = _map.getParticlePosition(_particleId, meanAnomaly);
// render widget
glm::mat4 widgetMatrix = orbit.getLookAlongMatrix(time);
_widget.setModelMatrix(widgetMatrix);
_widget.render(time);
// TODO: extract widget to its own visualizer since we know it wants an orbit but we
// might not have one here
//// render widget
//const Orbit& orbit = _map.getOrbit(_particleId);
//glm::mat4 widgetMatrix = orbit.getLookAlongMatrix(time);
//_widget.setModelMatrix(widgetMatrix);
//_widget.render(time);
// render sphere
_sphere.setPosition(pos);

View File

@ -3,12 +3,12 @@
#include "widget.hpp"
#include "icosphere.hpp"
#include <skein/particle.h>
#include <skein/particlemap.h>
class ParticleVisualizer
{
public:
ParticleVisualizer(Particle& particle, GLuint sphereShaderProgram, GLuint widgetShaderProgram);
ParticleVisualizer(const ParticleMap& map, const std::string& particleId, float radius, GLuint sphereShaderProgram, GLuint widgetShaderProgram);
~ParticleVisualizer() = default;
void render(float time);
@ -16,7 +16,8 @@ class ParticleVisualizer
private:
void updateModelMatrix();
Particle& _particle;
const ParticleMap& _map;
const std::string& _particleId;
Icosphere _sphere;
Widget _widget;
};