Physiksimulation/Dokumentation/Komponenten/
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
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__()
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
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 Interface im 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_())