Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

ss16:physiksimulation_doc_cpp

Dies ist eine alte Version des Dokuments!


Hauptseite des Projekts

zurück zur Liste der Komponenten

Physiksimulation | C++-Teil

INFO: Soweit nicht anders angegeben, sind die Code-Bestandteile auf dieser Seite aus den jeweiligen Header-Dateien.

Programmstruktur

vector3d.cpp

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;
};

object.cpp

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;
 
};

universe.cpp

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.

simulation.cpp

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);
    }
}
ss16/physiksimulation_doc_cpp.1471106698.txt.gz · Zuletzt geändert: 2016/08/13 18:44 von markumnus