Dies ist eine alte Version des Dokuments!
← zurück zur Liste der Komponenten
INFO: Soweit nicht anders angegeben, sind die Code-Bestandteile auf dieser Seite aus den jeweiligen Header-Dateien.
Die Klasse Vector3D ist die Grundlage für alle Größen der Berechnungen wie Positionen, Geschwindigkeiten, Beschleunigungen und Kräfte.
Unser Vector3D bietet folgende Funktionalitäten:
class Vector3D { private: // DEKLARATION DER ATTRIBUTE double x,y,z; public: // KONSTRUKTOREN Vector3D(); Vector3D(double, double, double); // GETTER double getX() const; double getY() const; double getZ() const; // SETTER void setX(double); void setY(double); void setZ(double); // OPERATORUEBERLADUNGEN Vector3D operator+(const Vector3D &a) const; Vector3D operator-(const Vector3D &a) const; Vector3D operator*(const double) const; Vector3D operator/(double) const; bool operator== (const Vector3D) const; // SONSTIGE FUNKTIONEN double betrag(); double skalarprodukt(Vector3D &a); double winkel(Vector3D &a); double abstand (const Vector3D &a); Vector3D kreuzprodukt(Vector3D &a) const; double spatprodukt(Vector3D &a, Vector3D &b); Vector3D norm(); std::string asString() const; };
Unsere Objects dienen der Aufbewahrung der Werte, die für die Berechnungen wichtig sind sowie einen Namen zur Identifikation.
#include "vector3d.hpp" class Object { private: // DEKLARATION DER ATTRIBUTE std::string name; Vector3D pos; // Position Vector3D vel; // Velocity Vector3D acc; // Acceleration double vol; // Volume double den; // Density double mas; // Mass bool fix; // is fixed? public: // KONSTRUKTOREN Object (std::string); Object (Vector3D, Vector3D); Object (Vector3D, Vector3D, Vector3D); // GETTER std::string getName() const; Vector3D getPos() const; Vector3D getVel() const; Vector3D getAcc() const; double getVol() const; double getDen() const; double getMass() const; bool isFixed() const; // SETTER void setPos (Vector3D); void setVel (Vector3D); void setAcc (Vector3D); void setVol (double); void setDen (double); void setMass(double); void setFix (bool); // OPERATOR OVERLOADINGS bool operator== (Object*) const; };
Unser Universe dient als Container für Objects. Im Prinzip funktioniert es wie ein std::vector mit besseren Zugriffsmöglichkeiten.
#include "object.hpp" class Universe { private: // DEKLARATION DER ATTRIBUTE std::vector <Object*> objects; public: // KONSTRUKTOREN Universe (); // DESTRUKTOR ~Universe (); // GETTER std::vector <Object*> getObjects() const; Object* getObject (std::string) const; // SONSTIGE FUNKTIONEN void add (Object*); unsigned int size() const; void remove (Object*); std::string asString (); };
Die size()-Methode gibt die Anzahl der Objects zurück, die sich aktuell in diesem Universe befinden.
Die Simulation ist das Herzstück des C++-Teils. Hier laufen die Berechnungen ab, deren Ergebnisse später angezeigt werden.
Hier sind das Euler- und das Runge-Kutta-Verfahren implementiert, wobei wir aktuell nur letzteres tatsächlich nutzen.
#include "universe.hpp" class Simulation { private: // DEKLARATION DER ATTRIBUTE double dt; const double stdG = 0.0002958935421; double G; Universe* unvrs; public: // KONSTRUKTOR Simulation (Universe*); Simulation (Universe*, double); // FUNKTIONEN void setG (double); void setDT (double); void simulate (); void simulate (unsigned int); // simuliert n Schritte void simulate_rk4 (); void simulate_rk4 (unsigned int); // simuliert n Schritte // Euler-Verfahren Vector3D updateForce (unsigned int) const; void updateAcc (); void updateVel (); void updatePos (); // Runge-Kutta-Verfahren void updateVel_rk4 (); void updatePos_rk4 (); };
Die Hauptmethode ist simulate_rk4(). Hier werden die Beschleunigungen (und Kräfte) berechnet, daraus die Geschwindigkeiten und daraus die Positionen.
Dazu ein paar Ausschnitte aus der simulation.cpp:
void Simulation::simulate_rk4 () { updateAcc(); updateVel_rk4(); updatePos_rk4(); }
Bei der Berechnung der Beschleunigungen ist die Berechnung der Kräfte mit eingebunden, denn aus
F=m*a
folgt
a = F/m
void Simulation::updateAcc () { Vector3D newAcc = Vector3D(0.,0.,0.); for (unsigned int i = 0; i < unvrs->size(); i++) { newAcc = (updateForce(i)/unvrs->getObjects().at(i)->getMass()); unvrs->getObjects().at(i)->setAcc(newAcc); } }
Die Kräfte werden nach dieser Formel in updateForce() berechnet.
Vector3D Simulation::updateForce (unsigned int a) const // a ist der Index des Object im Universe { std::vector<Object*> objects = unvrs->getObjects(); std::vector<Vector3D> forces (objects.size(), Vector3D (0.,0.,0.)); for (unsigned int i = 0; i < objects.size(); i++) { if (i != a) // Object wirkt keine Kraft auf sich selbst aus { Vector3D abstand_vec (objects.at(a)->getPos() - objects.at(i)->getPos()); double abstand = objects.at(a)->getPos().abstand(objects.at(i)->getPos()); forces.at(a) = forces.at(a) + (abstand_vec * ((objects.at(a)->getMass() * objects.at(i)->getMass())/(abstand*abstand*abstand))* -G); } } return forces.at(a); }
Mit den berechneten Beschleunigungen kann man nun mithilfe des Runge-Kutta-Verfahrens die Geschwindigkeiten und analog dazu die Positionen berechnen:
void Simulation::updateVel_rk4 () { std::vector<Object*> objects = unvrs->getObjects(); Vector3D newVel = Vector3D(0.,0.,0.); for (unsigned int i = 0; i < objects.size(); i++) { Vector3D k1 = (objects.at(i)->getAcc()) * dt; Vector3D k2 = (objects.at(i)->getAcc() + (k1*0.5)) * dt; Vector3D k3 = (objects.at(i)->getAcc() + (k2*0.5)) * dt; Vector3D k4 = (objects.at(i)->getAcc() + (k3)) * dt; newVel = objects.at(i)->getVel() + ((k1 + k2*2 + k3*2 + k4)/6); objects.at(i)->setVel(newVel); } }