Hauptseite des Projekts
**[[ss16:Physiksimulation|Physiksimulation]]/[[ss16:Physiksimulation_Doc_Main|Dokumentation]]/[[ss16:Physiksimulation_doc_components|Komponenten]]/** =====Python-Teil===== ====Programmstruktur==== {{ :ss16:physiksimulation_struktur2107.png?nolink |}} ====Parser.py==== In der Ergebnis-Textdatei sind einzelne Zeitschritte mit **//|//** getrennt, Objekte mit **//;//** und die Koordinaten der Objekte mit **//,//**. Die //parse()//-Funktion macht aus einem String nach diesem Muster eine Liste aus Tupeln mit den Positionsdaten. def parse (string): """ Nimmt einen String mit Object-Positionsdaten entgegen und gibt eine Liste aus Tupeln mit Positionsdaten zurueck. Beispiel: "0.0037, 0.0024, -0.0001;-0.315, -0.9603, -0.0001;-0.3129, -0.9592, -0.0002;|" -> [(0.0037, 0.0024, -0.0001), (-0.315, -0.9603, -0.0001), (-0.3129, -0.9592, -0.0002)] """ result = [] # aufteilen objects = string.split(";") # bereinigen for o in objects: if o == "": objects.remove(o) # Koordinaten extrahieren for o in objects: coords = o.split(",") # Whitespace entfernen for i, c in enumerate (coords): coords[i] = c.strip() # in Floats umwandeln try: coords = map (float, coords) except ValueError: print "Konnte", coords, "nicht umwandeln." result.append (tuple(coords)) return result ====Reader.py==== In der Datei Reader.py wird die Klasse Reader definiert. Wir haben uns hier für eine Klasse entschieden (anstatt nur einer Funktion wie beim Parser), da wir die //%%__getitem__()%%//-Funktion nutzen wollten, um die Ergebnis-Datei wie eine Liste indizierbar zu machen. Mit reader[time_step] kann man bequem auf die Positionsdaten des jeweiligen Zeitschritts zugreifen. ####################################### # IMPORTE ####################################### import Parser class Reader: time_steps = [] def __init__ (self, filename): # Deklarationen self.FILENAME = filename # File lesen with open (self.FILENAME) as f: file_cont = f.read() # Zeitschritte voneinander trennen | self.time_steps = file_cont.split('|') # letztes, leeres Element entfernen self.time_steps.pop() def __getitem__ (self, key): """ Indiziert einen Zeitschritt und gibt die Koordinaten der Objects zu diesem Zeitschritt zurueck. """ return Parser.parse(self.time_steps[key]) def __len__ (self): """ Gibt Anzahl der verfuegbaren Zeitschritte zurueck. """ return len (self.time_steps) def __str__ (self): s = "Reader auf \"" + self.FILENAME + "\" mit " + str(len(self)) + " Zeitschritten." return s def __repr__(self): return self.__str__() ====Visualizer.py==== Diese Datei deklariert die Klasse //Visualizer//. Im Konstruktor nimmt sie eine Liste mit Objekten entgegen, die visualisiert werden sollen. Außerdem wird die //scene// für Visual initialisiert.\\ Mit der Methode //run()// wird die Animation gestartet. Die benötigten Positionsdaten werden mithilfe des Readers ausgelesen. from visual import * from Reader import * from PyCInterface import PyCObject class Visualizer: def __init__ (self, list_of_objects, source = "results.txt"): """ Initialisiert den Visualizer mit verschiedenen Konstanten und Grundfunktionen, sowie mit einer Liste an Objekten, die gezeichnet werden sollen """ self.PROGRAM_NAME = "Gravitationssimulation" self.SPEED = 100 self.reader = Reader (source) self.time = 0 self.PyCObjects = [] # Objekte mit vom User gegebenen Daten wie Name, Farbe, Groesse, etc. self.Objects = [] # Objekte von Visual, die die Anzeige beeinflussen self.renew_objects (list_of_objects) # Initialisierung von Visual scene = display (title = self.PROGRAM_NAME,\ x=0, y=0, width=1920,height=1080,\ range=10, background=color.black, center = (0,0,0)) def renew_objects (self, list_of_objects): """ Setzt die Objects komplett neu. """ self.PyCObjects = list_of_objects # Objekte mit vom User gegebenen Daten wie Name, Farbe, Groesse, etc. self.Objects = [] # Objekte von Visual, die die Anzeige beeinflussen # lese Daten aus for i, o in enumerate(self.PyCObjects): try: pos_o = self.reader[0][i] size_o = o.size color_o = o.color self.Objects.append(sphere(pos=pos_o, radius = size_o, color = color_o, make_trail = true)) except IndexError: print "Mehr Objekte uebergeben als berechnet wurden:", i def run (self): """ Laeuft einmal durch alle Daten und zeigt diese an. """ # Loop bis Fileende: # update die Positionen while self.time < len(self.reader): rate (self.SPEED) for i, o in enumerate (self.Objects): o.pos = self.reader[self.time][i] # Object des aktuellen Zeitschrittes self.time += 1 ====Main.py==== In dieser Datei werden mehrere Klassen definiert, darunter die MyApp-Klasse, die das Programm darstellt und einige PopupWindow-Klassen, die die Funktionen des Fensters steuern.\\ Bei einem Klick auf einen Button wird mit der Codezeile self.addSonne.clicked.connect(self.Add_Sonne) # 'addSonne' ist der Name des in der Window.ui-Datei deklarierten Buttons die Methode Add_Sonne aufgerufen. Diese erstellt ein PopupWindow... def Add_Sonne(self): print "Creating a new Sun..." self.w = PopupWindow0() self.w.setWindowTitle("Sonne erstellen...") self.w.setGeometry(QtCore.QRect(500, 200, 360, 300)) self.w.show() ... welches wiederum Buttons hat, die z.B. beim Klicken auf "OK" ein Objekt erstellen und es zunächst per [[ss16:Physiksimulation_Doc_cpp#Interface.cpp|Interface]] im [[ss16:Physiksimulation_Doc_cpp#Universe.cpp|Universe]] speichern: def output0(self): obj = PyCObject() obj.x = float(PositionEditx0.text()) # uebernehme obj.y = float(PositionEdity0.text()) # Positionsdaten obj.z = float(PositionEditz0.text()) # vom Benutzer interface.add (obj) Auf die gleiche Weise werden die Berechnungen und die Visualisierung gestartet. Der Einstiegspunkt ist dann einfach folgender: if __name__ == "__main__": app = QtGui.QApplication(sys.argv) window = MyApp() window.move(QtCore.QPoint(850, 300)) window.show() sys.exit(app.exec_())