Ich versuche, ein physikalisches Simulationsprogramm zu schreiben. Im Prinzip funktioniert es schon gut, nur das GUI macht nicht richtig mit.
Selbst wenn die Subroutine Simulation 1000 Zyklen durchläuft, werden die 1000 Zeichnungen erst am Schluss auf einmal geplottet, die after Funktion sorgt zwar für eine Zeitverzögerung, aber gezeichnet wird erst ganz am Schluss.
Ich verstehe das nicht ganz, jede pack anweisung schiebt die zu zeichnende Linie doch in eine Queue, wo sie unabhängig vom Programmablauf gezeichnet wird? Warum wartet das Gui mit dem zeichnen, bis das Programm durch alle Zyklen durch ist, anstatt sofort zu loszulegen ?
Code: Alles auswählen
import time
#import datetime
import os
import re
import math
from tkinter import *
# Spezifikation der Variablen
G=6.672*10 ** (-11)
LBL=[]
M=[]
R=dict()
pstart=dict()
pz=lz=oz=Anzahl_Objekte=zeit=lfz=0
t_alt=-1
P=[]
Kalibrierung=0
R[0]=0
V=[]
O=[]
F=[]
ROTATION=[]
BM=[]
BP=[]
BV=[]
S=[]
NAME=[]
LINIE=[]
SKALIERUNG=[]
ZOOM=[]
UPS=[]
ZK=0
Z=0
BV_Schritt=1
counter=1
Zyklen=0
lfz=0
PROJEKTION="Zentralprojektion"
class Data:
    def __init__(self,objnr,txt="",x=0,y=0,z=0):
        self.objnr=objnr
        self.txt=txt
        self.x=x
        self.y=y
        self.z=z
    def Drehen(self,zeit,ups,n1,n2,n3):
        u=ups*zeit
        w=2*math.pi*(u - int(u))
        cos=math.cos(w)
        sin=math.sin(w)
        a1=n1**2*(1-cos) + cos
        a2=n1*n2*(1-cos) + n3*sin
        a3=n1*n3*(1-cos) - n2*sin
        b1=n1*n2*(1-cos) - n3*sin
        b2=n2**2*(1-cos) + cos
        b3=n2*n3*(1-cos) + n1*sin
        c1=n1*n3*(1-cos)+ n2*sin
        c2=n2*n3*(1-cos)-n1*sin
        c3=n3**2*(1-cos) + cos   
        xx=self.x * a1 + self.y * b1 + self.z * c1
        yy=self.x * a2 + self.y * b2 + self.z * c2
        zz=self.x * a3 + self.y * b3 + self.z * c3
        self.x=xx
        self.y=yy
        self.z=zz
    def Laden(fn):
        global LBL, pstart, M, R, pz, lz, oz, zeit, lfz, t_alt, P
        global R, V, O, F, ROTATION, BM, BP, BV, S, NAME, LINIE, SKALIERUNG, ZOOM
        global UPS, ZK, Z, PROJEKTION, Anzahl_Objekte, BV_Schritt
        Anzahl_Objekte=counter=Zyklen=0
        BM=[]
        BV=[]
        BP=[]
        SKALIERUNG=[]
        P=[]
        LINIE=[]
        ROTATION=[]
        O=[]
        F=[]
        LBL=[]
        pz=0
        lz=0
        
        f=open(fn,"r")
        for l in f:
            zeile=l.split()
            if zeile[1] == "P":
                t0=int(zeile[0])
                t2=float(zeile[2])
                t3=float(zeile[3])
                t4=float(zeile[4])
                P.append(Data(t0, "", t2, t3, t4))
                if t_alt != t0:
                    R[t0]=0
                    pstart[t0] = pz
                    t_alt = t0
                pz = pz + 1
                # Ermittle max Radius für Kollisionsdetektor
                betrag=(t2 ** 2 + t3 ** 2 + t4 ** 2)**0.5
                if R[t0]< betrag : R[t0]=betrag
            elif zeile[1] == "NAME": NAME.append(Data(0, zeile[2]))       
            elif zeile[1] == "L":
                t0=int(zeile[0])
                LINIE.append(Data(int(zeile[0]), "", int(zeile[2]) + pstart[t0], int(zeile[3]) + pstart[t0]))
                lz=lz+1
            elif zeile[1] == "F": F.append(Data(0, zeile[2]))
            elif zeile[1] == "ZOOM": ZOOM = float(zeile[2])
            elif zeile[1] == "ZK": ZK = float(zeile[2])
            elif zeile[1] == "Z": Z = float(zeile[2])                
            elif zeile[1] == "V": V.append(Data(int(zeile[0]), "", float(zeile[2]), float(zeile[3]), float(zeile[4])))
            elif zeile[1] == "O":
                Anzahl_Objekte += 1
                t0=int(zeile[0])
                O.append(Data(t0, "", float(zeile[2]), float(zeile[3]), float(zeile[4])))
                LBL.extend(["Info_" + zeile[0]])
                LblPos=28+ 100 * t0
                LBL[t0] = Label(master=master, bg='#FFCFC9', text=zeile[0])
                LBL[t0].place(x=1000, y=LblPos, width=200, height=99)
            elif zeile[1] == "ROTATION": ROTATION.append(Data(0, "", float(zeile[2]), float(zeile[3]), float(zeile[4])))
            elif zeile[1] == "UPS": UPS.append(Data(float(zeile[2])))
            elif zeile[1] == "M": M.append(Data(float(zeile[2])))
            elif zeile[1] == "S": S.append(Data(int(zeile[0]), "", float(zeile[2]), float(zeile[3]), float(zeile[4])))
            elif zeile[1] == "BP": BP.append(Data(0, "", float(zeile[2]),float(zeile[3]),float(zeile[4])))
            elif zeile[1] == "BM": BM.append(Data(0, "", float(zeile[2]), float(zeile[3]), float(zeile[4])))
            elif zeile[1] == "BV": BV.append(Data(0, "", float(zeile[2]), float(zeile[3]), float(zeile[4])))
            elif zeile[1] == "SKALIERUNG": SKALIERUNG.append(Data(0, "", float(zeile[2]), float(zeile[3]), float(zeile[4])))
            elif zeile[1] == "BVS": BV_Schritt = float(zeile[2])
            elif zeile[1] == "PROJEKTION": PROJEKTION = zeile[2]
        f.close()
        update_Info()  
    def Zyklus_berechnen():
        global LBL, pstart, M, R, pz, lz, oz, zeit, lfz, t_alt, Zyklen, Kollisionswarnung
        global R, V, O, F, BP, BV, BM, ROTATION, S, NAME, LINIE, SKALIERUNG, ZOOM, P
        global UPS, ZK, Z, PROJEKTION, Anzahl_Objekte, BV_Schritt, counter
        # Update Anzahl Zyklen Label
        counter+=1
        v=(BV[0].x**2 + BV[0].y**2 + BV[0].z**2)**0.5
        txt="Anzahl Zyklen: " + str(counter) + " BV: " + str(v)
        LabelZyklen.config(text=txt)
        # Ermittlung der Abstände und Kraftvektoren
        z1=0
        while z1 < Anzahl_Objekte:
            z2=0
            if counter == 1: break
            while z2 < Anzahl_Objekte:
                # Sonderfall für nur ein Objekt
                if Anzahl_Objekte==1:
                    O[0].x += Z * V[0].x
                    O[0].y += Z * V[0].y
                    O[0].z += Z * V[0].z
                    betrag=(V[0].x**2 + V[0].y**2 + V[0].z**2)**0.5
                    txt=NAME[0].txt + " \nV=" + str(betrag) + " m/s"
                    LBL[0].config(text=txt)
                    # Änderung der Beobachterposition
                    BP[0].x += BV[0].x * Z
                    BP[0].y += BV[0].y * Z
                    BP[0].z += BV[0].z * Z
                    update_Info()
                    z2=z2+1                    
                    continue
                elif z2<=z1:
                    z2=z2+1
                    continue
                # Ermittlung des Kraftvektors zwischen den Objekten
                x=O[z2].x - O[z1].x
                y=O[z2].y - O[z1].y
                z=O[z2].z - O[z1].z
                # Normiere den Kraftvektor
                betrag=(x ** 2 + y ** 2 + z ** 2)**0.5
                if betrag == 0:
                    x=y=z=0
                else:
                    x=x/betrag
                    y=y/betrag
                    z=z/betrag
                # Kollisionsprüfung
                if Kollisionswarnung >0 and betrag <= R[z1] + R[z2]:
                    line="Achtung, Kollision Objekt " + str(z1) + " und " + str(z2) + "\nTrotzdem fortfaheren?"
                    if Bestätigung(line) == "n": return(0)
                    if Bestätigung("Weitere Kollisionswarnungen unterdrücken ?") == "j":
                        Kollisionswarnung=0
            
                # Berechnung der Anziehungskraft
                if betrag > 0:
                    Kraft = (G * M[z1].objnr * M[z2].objnr)/betrag ** 2
                else:
                    Kraft=0
                line="Kraft zwischen Objekt " + str(z1) + " und Objekt " + str(z2) + " : " + str(Kraft) + "\n"
                log.write(line)
                line="Kraftvektor: " + str(x) + " , " + str(y) + " , " + str(z) + "\n"
                log.write(line)
                # Berechnung der resultierenden Beschleunigungen
                if M[z1].objnr > 0: a1 = Kraft / M[z1].objnr
                else: a1=0
                v1 = Z * a1
                if M[z2].objnr > 0: a2 = -1 * Kraft / M[z2].objnr
                else: a2=0
                v2 = Z * a2
                line="a1,v1,a2,v2,zeit: " + str(a1) + "," + str(v1) + "," + str(a2) + "," + str(v2) + "," +  "\n"
                log.write(line)
                #andrucken der aktuellen Daten
                txt=NAME[z1].txt + " \nV=" + str(v1) + " m/s\na=" + str(a1) + "\nMitte-Mitte Abstand zu " + NAME[z2].txt + " =" + str(betrag)
                LBL[z1].config(text=txt)
                txt=NAME[z2].txt + " \nV=" + str(v2) + " m/s\na=" + str(a2) + "\nMitte-Mitte Abstand zu " + NAME[z1].txt + " =" + str(betrag)
                LBL[z2].config(text=txt)
                
                # Änderung der Ortsvektoren unter Annahme konstanter Kraft
                O[z1].x += Z * V[z1].x + x * 0.5 * a1 * Z ** 2
                O[z1].y += Z * V[z1].y + y * 0.5 * a1 * Z ** 2
                O[z1].z += Z * V[z1].z + z * 0.5 * a1 * Z ** 2
                O[z2].x += Z * V[z2].x + x * 0.5 * a2 * Z ** 2
                O[z2].y += Z * V[z2].y + y * 0.5 * a2 * Z ** 2
                O[z2].z += Z * V[z2].z + z * 0.5 * a2 * Z ** 2
                # Änderung der Geschwindigekeitsvektoren
                V[z1].x += v1 * x
                V[z1].y += v1 * y
                V[z1].z += v1 * z
                V[z2].x += v2 * x
                V[z2].y += v2 * y
                V[z2].z += v2 * z
                #Schreibe Objektdaten in Logfile
                line = str(z1) + " O " +str(O[z1].x) + " " + str(O[z1].y) + " " + str(O[z1].z) + "\n"
                log.write(line)
                line  =str(z1) + " V " +str(V[z1].x) + " " + str(V[z1].y) + " " + str(V[z1].z) + "\n"
                log.write(line)
                line = str(z2) + " O " +str(O[z2].x) + " " + str(O[z2].y) + " " + str(O[z2].z) + "\n"
                log.write(line)
                line = str(z2) + " V " +str(V[z2].x) + " " + str(V[z2].y) + " " + str(V[z2].z) + "\n"
                log.write(line)   
                z2=z2+1
            z1=z1+1
        lfz+=Z
        laufzeit=str(lfz)
        line="Laufzeit " + laufzeit + "\n\n"
        log.write(line)
          
        #Anpassung der Punkte
        PP=[]
        p=0
        while p < pz:
            objnr=P[p].objnr
            
            # Drehung der Objekte
            if UPS[objnr].objnr != 0: P[p].Drehen(lfz,UPS[objnr].objnr,ROTATION[objnr].x,ROTATION[objnr].y,ROTATION[objnr].z)
            # Normierung auf das Beobachterkooordinatensystem
            x=(P[p].x+O[objnr].x-BP[0].x)*BM[0].x+(P[p].y+O[objnr].y-BP[0].y)*BM[0].y+(P[p].z+O[objnr].z-BP[0].z)*BM[0].z
            y=(P[p].x+O[objnr].x-BP[0].x)*BM[1].x+(P[p].y+O[objnr].y-BP[0].y)*BM[1].y+(P[p].z+O[objnr].z-BP[0].z)*BM[1].z
            z=(P[p].x+O[objnr].x-BP[0].x)*BM[2].x+(P[p].y+O[objnr].y-BP[0].y)*BM[2].y+(P[p].z+O[objnr].z-BP[0].z)*BM[2].z
 
            if PROJEKTION=="Parallelprojektion":
                x=int(x * Kalibrierung * ZOOM) + 400
                y=400 - int(y * Kalibrierung * ZOOM)
                PP.append(Data(objnr, "", x, y, z))
            elif PROJEKTION=="Projektion_auf_Kugel":
                betrag=(x**2 + y**2 + z**2)**0.5
                x=int((x * Kalibrierung * ZOOM)/betrag) + 400
                y=400 - int((y * Kalibrierung * ZOOM)/betrag)
                PP.append(Data(objnr, "", x, y, z))
            else:
                if z != 0:
                    x=int((x/z) * Kalibrierung * ZOOM + 400)
                    y=400 - int((y/z) * Kalibrierung * ZOOM)
                else: x = y = -1000
                PP.append(Data(objnr, "", int(x), int(y), z))
            line="Punkt " + str(p) + "--> z=" + str(z) +" Bildtafel:" + str(x) + " " +str(y) + "\n"
            log.write(line)
            p = p + 1
                
        #Zeichnen der Linien
        l=0
        while l < lz:
            objnr=int(LINIE[l].objnr)
            p1=LINIE[l].x
            p2=LINIE[l].y
            l=l+1
            # Überspringe Zeilen mit Start- und Endpunkt hinter dem Betrachter
            if PP[p1].z <= 0 and PP[p2].z <= 0: continue
            # Setzen des Mindestabstandes von einem Punkt
            if PP[p1].x == PP[p2].x: PP[p1].x += 1
            if PP[p1].y == PP[p2].y: PP[p2].y += 1
            w.create_line(PP[p1].x, PP[p1].y, PP[p2].x, PP[p2].y, fill=F[objnr].txt , width=1)
            w.pack()
    def Kalibrierung():
        global Kalibrierung, pz, P, BM, O, BP, PROJEKTION, log
        max=p=0
        while p < pz:
            objnr=P[p].objnr
            x=(P[p].x+O[objnr].x-BP[0].x)*BM[0].x+(P[p].y+O[objnr].y-BP[0].y)*BM[0].y+(P[p].z+O[objnr].z-BP[0].z)*BM[0].z
            y=(P[p].x+O[objnr].x-BP[0].x)*BM[1].x+(P[p].y+O[objnr].y-BP[0].y)*BM[1].y+(P[p].z+O[objnr].z-BP[0].z)*BM[1].z
            z=(P[p].x+O[objnr].x-BP[0].x)*BM[2].x+(P[p].y+O[objnr].y-BP[0].y)*BM[2].y+(P[p].z+O[objnr].z-BP[0].z)*BM[2].z
            if PROJEKTION == "Parallelprojektion":
                xx=abs(x)
                yy=abs(y)
            elif PROJEKTION == "Projektion_auf_Kugel":
                betrag=(x**2 + y**2 + z**2)**0.5
                xx=abs(x/betrag)
                yy=abs(y/betrag)
            elif PROJEKTION == "Zentralprojektion":
                if z != 0:
                    xx=abs(x/z)
                    yy=abs(y/z)
                else: xx=yy=0
            if xx > max : max=xx
            if yy > max : max=yy
            line="x="+str(x)+" y="+str(y)+" z=" + str(z)+ " xx="+str(xx)+" YY="+str(yy)+ " max=" + str(max) + "\n"
            log.write(line)
            p += 1
        if max != 0: Kalibrierung=200/max
        else: Kalibrierung = 1
        line="Projektionsart: " + PROJEKTION + "Kalibrierungsfakror: " + str(Kalibrierung) + "\n"
        log.write(line)
def Zeit_anpassen(Zeit):
    if Zeit> 31536000:
        Faktor=1/31536000
        Einheit="Jahre"
    elif Zeit> 86400:
        Faktor=1/86400
        Einheit = "Tage"
    elif Zeit > 3600:
        Faktor=1-3600
        Einheit = "Stunden"
    else:
        Faktor=1
        Einheit = "Sekunden"
    return(Zeit * Faktor,Einheit)
def update_Info():
    global BV, BM, BP
    Faktor = 1
    Einheit = " m"
    if abs(BP[0].x) > 1000 and abs(BP[0].y) > 1000 and abs(BP[0].z) > 1000:
        Faktor = 0.001
        Einheit = " Km"
    elif abs(BP[0].x) < 0.001 and abs(BP[0].y) < 0.001 and abs(BP[0].z) < 0.001:
        Faktor = 1000000
        Einheit = " μm"
    elif abs(BP[0].x) < 1 and abs(BP[0].y) < 1 and abs(BP[0].z) < 1:
        Faktor = 1000
        Einheit = " mm"
    x='{:.2f}'.format(BP[0].x * Faktor)
    y='{:.2f}'.format(BP[0].y * Faktor)
    z='{:.2f}'.format(BP[0].z * Faktor)
    txt="Position: " + x + "/" + y + "/" + z + Einheit
    Label_BP.config(text=txt)
    betrag=(BV[0].x**2 + BV[0].y**2 + BV[0].z**2)**0.5
    Faktor = 1
    Einheit = " m/Sek"
    if betrag > 1000:
        Faktor = 0.001
        Einheit = " Km/Sek"
    elif betrag < 0.001:
        Faktor = 1000000
        Einheit = " μm/Sek"
    elif betrag < 1:
        Faktor = 1000
        Einheit = " mm/Sek"    
    txt="Geschwindigkeit " + '{:.2f}'.format(betrag * Faktor) + Einheit
    Label_BV.config(text=txt)
    txt="Blickrichtung: " + '{:.2f}'.format(BM[2].x) + "/" + '{:.2f}'.format(BM[2].y) + "/" + '{:.2f}'.format(BM[2].z)
    txt=txt + "\n" + "Horizont : " + '{:.2f}'.format(BM[1].x) + "/" + '{:.2f}'.format(BM[1].y) + "/" + '{:.2f}'.format(BM[1].z) 
    Label_BM.config(text=txt)
def Beobachter_drehen(Achse,Richtung):
    n1=n2=n3=0
    ups=1/360
    if   Achse == "x": n1 = 1
    elif Achse == "y": n2 = 1
    elif Achse == "z": n3 = 1
    if Richtung == "links": ups = -ups
    BM[0].Drehen(1, ups, n1, n2, n3)
    BM[1].Drehen(1, ups, n1, n2, n3)
    BM[2].Drehen(1, ups, n1, n2, n3)
    x='{:3.2f}'.format(BM[2].x)
    y='{:3.2f}'.format(BM[2].y)
    z='{:3.2f}'.format(BM[2].z)
    a='{:3.2f}'.format(BM[0].x)
    b='{:3.2f}'.format(BM[0].y)
    c='{:3.2f}'.format(BM[0].z)
    txt="Blickrichtung: " + x + "/" + y + "/" + z
    txt=txt + "\n" + "Horizont : " + a + "/" + b + "/" + c +"/" 
    Label_BM.config(text=txt)
def Beobachter_bewegen(Achse,Richtung):
    global BV, BV_Schritt
    if   Richtung == "+": Schritt = BV_Schritt
    elif Richtung == "-": Schritt = - BV_Schritt
    if   Achse == "x": BV[0].x += Schritt
    elif Achse == "y": BV[0].y += Schritt
    elif Achse == "z": BV[0].z += Schritt
    v=str((BV[0].x**2 + BV[0].y**2 + BV[0].z**2)**0.5)
    txt="Beobachtertempo: " + v
    Label_BV.config(text=txt)
def neu_laden():
    global fn
    Data.Laden(fn)
def löschen():
    w.delete("all")
def Info(txt):
    info = Tk()
    T = Text(info, height=2, width=80)
    T.pack()
    T.insert(END, txt)
    T.mainloop()
def Bestätigung(txt):
    # Öffnet Ein Auswahlfeld für ja oder nein
    Eingabe = Toplevel()
    Eingabe.geometry('300x100+0+0')
    v = StringVar()
    Label(Eingabe,text=txt,justify = LEFT,padx = 50).pack()
    Radiobutton(Eingabe,text="Ja",indicatoron = 0,width = 40,padx = 50,variable=v,command=Eingabe.quit,value="j").pack(anchor=W)
    Radiobutton(Eingabe,text="Nein",indicatoron = 0,width =40,padx = 50,variable=v,command=Eingabe.quit,value="n").pack(anchor=W)
    Eingabe.mainloop()
    antwort=v.get()
    Eingabe.destroy()
    return(antwort)
def Auswahl(Labels):
    # Öffnet Ein Auswahlfeld für eine Liste von Argumenten
    Eingabe = Toplevel()
    v = StringVar()
    Label(Eingabe,text="Bitte wählen",justify = LEFT,padx = 50).pack()
    for label in Labels:
        Radiobutton(Eingabe,text=label,indicatoron = 0,width = 50,padx = 50,variable=v,command=Eingabe.quit,value=label).pack(anchor=W)
    Eingabe.mainloop()
    antwort=v.get()
    Eingabe.destroy()
    return(antwort)
    
def Datei_wählen(match):
    # Zeigt Dateien an, auf die match passt, lässt eine auswählen, und gibt den Dateinahmen als Returnwert zurück
    datei = Toplevel()
    v = IntVar()
    V=[]
    x=0
    Label(datei,text="""Bitte Datei auswählen:""",justify = LEFT,padx = 50).pack()
    for txt in os.listdir("Simulator"):
        if re.search(match,txt):
            V.append(txt)
            Radiobutton(datei, 
                text=txt,
                indicatoron = 0,
                width = 50,
                padx = 50, 
                variable=v, 
                command=datei.quit,
                value=x).pack(anchor=W)
            x=x+1
    mainloop()
    fn=V[v.get()]
    datei.destroy()
    return(fn)
def Eingabe(Labels):
    # Öffnet Ein textfeld zur Eingabe beliebig vieler Parameter, Ergebnis wird als Liste zurückgegeben
    entries=[]
    resultat=[]
    Eingabe = Toplevel()
    for field in Labels:
        L=field.split("=")
        row = Frame(Eingabe)
        lab = Label(row, width=60, text=L[0], anchor='w')
        ent = Entry(row)
        ent.insert(10,L[1])
        row.pack(side=TOP, fill=X, padx=5, pady=5)
        lab.pack(side=LEFT)
        ent.pack(side=RIGHT, expand=YES, fill=X)
        entries.append((L[0], ent))
    #Eingabe.bind('<Return>', (lambda event))   
    b1 = Button(Eingabe, text='Fertig',command=(Eingabe.quit))
    b1.pack(side=LEFT, padx=5, pady=5)
    Eingabe.mainloop()
    for entry in entries:
       field = entry[0]
       text  = entry[1].get()
       resultat.append(text)
    Eingabe.destroy()
    return(resultat)
def Neue_Objekte() :
    L=[]
    L=Eingabe(["Name des neuen Objekts="])
    obj='Simulator/' + L[0] + '_obj.txt'
    
    #Prüfe Existenz von Verzeichnis
    if (os.path.isdir('Simulator') == False):
         os.mkdir('Simulator')
    #Prüfe Existenz von Datei
    if (os.path.isfile(obj)):
        if Bestätigung("Datei existiert, soll sie überschrieben werden ?") == "n":
            return(1)
    f=open(obj,"w+")
    form=Auswahl(["Kreis","Kugel","Quader","Pyramide","Freie Modelierung"])
    if ('Kugel' in form):
        L=Eingabe(["Tiefe in Meter=1","Breite in Meter=1","Höhe in Meter=1","Teilung=10"])
        t=float(L[0])
        b=float(L[1])
        h=float(L[2])
        teilung=int(L[3])
        
        #Verschachtelte Schleife, um die Kugel zu konstruieren
        if teilung == "": teilung=30
        s=2 * math.pi / teilung
        wxz=0
        p=0
        while wxz < teilung:
            wxy=0
            while wxy < teilung:
                p=teilung * wxz + wxy
                y=0.5 * math.sin(s * wxy) * h
                x=0.5 * math.cos(s * wxy) * math.cos(wxz) * b
                z=0.5 * math.sin(s * wxz) * math.sin(wxy) * t
                line= "P " + str(x) + " " + str(y) + " " + str(z) + "\n"
                if wxy>0: line=line + " L " + str(p-1) + " " + str(p) + "\n"
                else: line=line + " L " + str(p) + " " + str(p+teilung -1) + "\n"
                if wxz > 0:
                    line=line + " L " + str(p) + " " + str(p - teilung) + "\n"
                f.write(line)
                wxy += 1
            wxz += 1
    elif ('Kreis' in form):
        L=Eingabe(["Breite in Meter=1","Höhe in Meter=1","Teilung=10"])
        b=float(L[0])
        h=float(L[1])
        teilung=int(L[2])
        
        # Schleife, um den Kreis zu konstruieren
        if teilung == "": teilung=30
        s=2 * math.pi / teilung
        p=0
        while p < teilung:
            y=0.5 * math.sin(s * p) * h
            x=0.5 * math.cos(s * p) * b
            line= "P " + str(x) + " " + str(y) + " 0\n"
            if p>0: line=line + " L " + str(p-1) + " " + str(p) + "\n"
            f.write(line)
            p += 1
        line=line + " L 0 " + str(p-1) + "\n"
        f.write(line)    
    elif('Quader' in form):
        L=Eingabe(["Tiefe in Meter=1","Breite in Meter=1","Höhe in Meter=1"])
        t=str(float(L[0])/2)
        b=str(float(L[1])/2)
        h=str(float(L[2])/2)
        line= "P -" + b + " -" + h + " -" + t + "\n"
        line= line + "P -" + b + " -" + h + " " + t + "\n"
        line= line + "P " + b + " -" + h + " " + t + "\n"
        line= line + "P " + b + " -" + h + " -" + t + "\n"
        line= line + "P -" + b + " " + h + " -" + t + "\n"
        line= line + "P -" + b + " " + h + " " + t + "\n"
        line= line + "P " + b + " " + h + " -" + t + "\n"
        line= line + "P " + b + " " + h + " " + t + "\n"
        line= line + "L 0 1\nL 1 2\nL 2 3\nL 3 0\n"
        line= line + "L 4 5\nL 5 6\nL 6 7\nL 7 4\n"
        line= line + "L 0 4\nL 1 5\nL 2 6\nL 3 7\n"
        f.write(line)
    elif('Pyramide' in form):
        L=Eingabe(["Tiefe in Meter=1","Breite in Meter=1","Höhe in Meter=1"])
        t=float(L[0])
        b=float(L[1])
        h=float(L[2])
        line= "P " + str(-0.5*b) + " " + str(-0.25*h) + " " + str(-0.5*t) + "\n"
        line= line + "P " + str(0.5*b) + " " + str(-0.25*h) + " " + str(-0.5*t) + "\n"
        line= line + "P " + str(0.5*b) + " " + str(-0.25*h) + " " + str(0.5*t) + "\n"
        line= line + "P " + str(-0.5*b) + " " + str(-0.25*h) + " " + str(0.5*t) + "\n"
        line= line + "P 0 "  + str(0.75*h) + " 0\n"
        line= line + "L 0 1\nL 1 2\nL 2 3\nL 3 0\n"
        line= line + "L 0 4\nL 1 4\nL 2 4\nL 3 4\n"
        f.write(line)
    elif('Freie Modelierung' in form):
        # Wird nur zur Anpassung der Punkte genutzt, um den Schwerpunkt zu 0/0/0 zu verschieben
        L=Eingabe(["Schwerpunkt des Objekts X-Achse=0", "Schwerpunkt des Objekts Y-Achse=0", "Schwerpunkt des Objekts Z-Achse=0"])
        x=float(L[0])
        y=float(L[1])
        z=float(L[2])
        f.write("SP 0 0 0\n")
        #Eingabe der Punkte
        L=Eingabe(["Anzahl der Punkte=", "Anzahl der Linien="])
        zeile=[]
        p=int(L[0]) # Anzahl der Punkte
        l=int(L[1]) # Anzahl der Linien
        for i in range(0, p):
            txt="Punkt " + str(i) + " X-Koordinate="
            zeile.extend([txt])
            txt="Punkt " + str(i) + " Y-Koordinate="
            zeile.extend([txt])
            txt="Punkt " + str(i) + " Z-Koordinate="
            zeile.extend([txt])
        L=Eingabe(zeile)
        zeile=[]
        for i in range(0, p):
            line="0" + " P " + str(float(L[i*3])-x) + " " + str(float(L[i*3 + 1])-y) + " " + str(float(L[i*3 + 2])-z) + "\n"
            f.write(line)
        # Eingabe der Linien
        for i in range(0, l):
            txt="Linie " + str(i) + " Startpunkt="
            zeile.extend([txt])
            txt="Linie " + str(i) + " Endpunkt="
            zeile.extend([txt])
        L=Eingabe(zeile)
        for i in range(0, l):
            line="0" + " L " + L[i*2] + " " + L[i*2 + 1] + "\n"
            f.write(line)     
        f.close()
            
def Neue_Simulation(modus):
    global LBL, pstart, M, R, pz, lz, oz, zeit, lfz, t_alt, P, Kalibrierung, G
    global R, V, O, F, ROTATION, BM, BP, BV, S, NAME, LINIE, SKALIERUNG, ZOOM
    global UPS, D, ZK, Z, ROJEKTION, Anzahl_Objekte, BV_Schritt
    if modus == "ändern": sim="Simulator/" + Datei_wählen("_sim")
    elif modus == "neu":  
        L=[]
        L=Eingabe(["Name der Simulation="])
        sim='Simulator/' + L[0] + '_sim.txt'
        if (os.path.isfile(sim)) and Bestätigung("Datei existiert bereits, soll sie überschrieben werden ?") == "n": return(1)
            
    #Prüfe Existenz von Verzeichnis
    if (os.path.isdir('Simulator') == False): os.mkdir('Simulator')
    # Setzen der Defaultwerte bzw Laden der aktuellen Werte
    if modus == "ändern": Data.Laden(sim)
    else:
        ZK=1
        Z=1
        BP.append(Data(0,"", 0, 0, 0))
        BM.append(Data(0, "", 1, 0, 0))
        BM.append(Data(0, "", 0, 1, 0))
        BM.append(Data(0, "", 0, 0, 1))
        BV.append(Data(0, "", 0, 0, 0))
        BV_Schritt=1
        ZOOM=1
        UPS.append(Data(0))
        ROTATION.append(Data(0, "", 0, 0, 0))
        
    # Spezifiziere Beobachtungssystem
    fs=open(sim,"w+")
    objnr=0
    L=["Beobachterposition X/Y/Z="+str(BP[0].x) + "/" + str(BP[0].y) + "/" +str(BP[0].z)]
    L.extend(["Beobachterkoordinatensystem X-Achse: X/Y/Z="+str(BM[0].x) + "/" +str(BM[0].y) + "/" + str(BM[0].z)])
    L.extend(["Beobachtekoordinatensystemx Y-Achse: X/Y/Z="+str(BM[1].x) + "/" + str(BM[1].y) + "/" + str(BM[1].z)])
    L.extend(["Beobachterkoordinatensystem Z-Achse: X(Y(Z="+str(BM[2].x) + "/" + str(BM[2].y) + "/" + str(BM[2].z)])
    L.extend(["Beobachtergeschwindigkeit in X/Y/Z="+str(BV[0].x) + "/" + str(BV[0].y) + "/" + str(BV[0].z)])
    L.extend(["Simulierte Zeit zwischen den Simulationsschritten in Sekunde="+str(Z),"Anzahl der zu berechnenden Zyklen="+str(ZK)])
    L.extend(["Zoomfaktor="+str(ZOOM), "Schrittweite der Änderung der Beobachtergeschwindigkeit="+str(BV_Schritt)])
    L=Eingabe(L)
    zeile=L[0].split("/")
    line=str(objnr) + " BP " + zeile[0] + " " +  zeile[1] + " " + zeile[2] + "\n"
    fs.write(line)
    zeile=L[1].split("/")    
    line=str(objnr) + " BM " + zeile[0] + " " +  zeile[1] + " " + zeile[2] + "\n"
    fs.write(line)
    zeile=L[2].split("/")  
    line=str(objnr) + " BM " + zeile[0] + " " +  zeile[1] + " " + zeile[2] + "\n"
    fs.write(line)
    zeile=L[3].split("/")  
    line=str(objnr) + " BM " + zeile[0] + " " +  zeile[1] + " " + zeile[2] + "\n"
    fs.write(line)
    zeile=L[4].split("/")  
    line=str(objnr) + " BV " + zeile[0] + " " +  zeile[1] + " " + zeile[2] + "\n"
    fs.write(line)
    line="0 Z " + L[5] + "\n"
    fs.write(line)
    line="0 ZK " + L[6] + "\n"
    fs.write(line)
    line="0 ZOOM " + L[7] + "\n"
    fs.write(line)
    line="0 BVS " + L[8] + "\n"
    fs.write(line)
    L=["Zentralprojektion", "Parallelprojektion", "Projektion_auf_Kugel"]
    antwort=Auswahl(L)
    line="0 PROJEKTION " + antwort + "\n"
    fs.write(line)
    
    #Lese Objekte aus Katalog ein, und individualisiere sie
    while True :
        obj=Datei_wählen("_obj")
        obj='Simulator/' + obj
        F.append(Data(0, "black"))
        O.append(Data(0, "", 0, 0, 0))
        V.append(Data(0, "", 0, 0, 0))
        ROTATION.append(Data(0,"", 0, 0, 0))
        M.append(Data(1))
        SKALIERUNG.append(Data(0, "", 1, 1, 1))
        NAME.append(Data(0, "?"))
        UPS.append(Data(0))
        
        L=["Farbe (Englisch klar oder #...... als RGB Wert="+F[objnr].txt]
        L.extend(["Skalierung Achsen X/Y/Z=" +str(SKALIERUNG[objnr].x) + "/" + str(SKALIERUNG[objnr].y) + "/" + str(SKALIERUNG[objnr].z)])
        L.extend(["Startposition des Objekts X/Y/Z="+str(O[objnr].x) + "/" + str(O[objnr].y) + "/" + str(O[objnr].z)])
        L.extend(["Geschwindigkeit in X/Y/Z="+str(V[objnr].x) +"/" + str(V[objnr].y) + "/" + str(V[objnr].z)])
        L.extend(["Masse in Kg="+str(M[objnr].objnr),"Objektbezeichnung="+NAME[objnr].txt,"Umdrehungen pro Sekunde (- für Linksdehung)="+str(UPS[objnr].objnr)])
        L.extend(["Rotationsvektor X/Y/Z="+str(ROTATION[objnr].x) + "/" +str(ROTATION[objnr].y) + "/" + str(ROTATION[objnr].z)])
        L=Eingabe(L)
        sk=L[1].split("/")
        line=str(objnr) + " SKALIERUNG " + sk[0] + " " + sk[1] + " " + sk[2] + "\n"
        fs.write(line)
        line=str(objnr) + " F " + L[0] + "\n"
        fs.write(line)
        zeile=L[3].split("/")
        line=str(objnr) + " V " + zeile[0] + " " + zeile[1] + " " + zeile[2] + "\n"
        fs.write(line)
        zeile=L[2].split("/")
        line=str(objnr) + " O " + zeile[0] + " " + zeile[1] + " " + zeile[2] + "\n"
        fs.write(line)
        line=str(objnr) + " M " + L[4] + "\n"
        fs.write(line)
        line=str(objnr) + " NAME " + L[5] + "\n"
        fs.write(line)
        line=str(objnr) + " UPS " + L[6] + "\n"
        fs.write(line)
        # Normierung des Rotationsvektors
        zeile=L[7].split("/")
        n1=float(zeile[0])
        n2=float(zeile[1])
        n3=float(zeile[2])
        betrag=(n1**2 + n2**2 + n3**2)**0.5
        if betrag > 0:
            n1 = n1 / betrag
            n2 = n2 / betrag
            n3 = n3 / betrag
            line=str(objnr) + " ROTATION " + str(n1) + " " + str(n2) + " " + str(n3) + "\n"
            fs.write(line)
                   
        # schreibe adaptierte Objektdaten in Simulationsdatei    
        fo=open(obj,"r")
        for l in fo:
            zeile=l.split()
            if (zeile[0] == "P"):
                x=str(float(sk[0]) * float(zeile[1]))
                y=str(float(sk[1]) * float(zeile[2]))
                z=str(float(sk[2]) * float(zeile[3]))
                line=str(objnr) + " P " + x + " " + y + " " + z + "\n"
                fs.write(line)
            else:
                line=str(objnr) + " " + l
                fs.write(line)
        fo.close()
        
        objnr +=1
        if modus == "ändern" and Anzahl_Objekte > objnr:
            txt="Alte Simulation enthält mehr Objekte, trotzdem beenden ?"
        else:
            txt="Ist die Simulation nun fertig ?"
        if Bestätigung(txt) == "j":
            fs.write(line)
            fs.close()
            break
            
def Simulation():
    global Kollisionswarnung, counter, Zyklen, ZK, log
    
    # Wähle Datei aus und öffne sie
    fn="Simulator/" + Datei_wählen("_sim")
    Data.Laden(fn)
    # Lege Logfile an
    logfile=fn.replace("_sim","_log",1)
    log=open(logfile,"w+")
    
    # Schleife durch alle Zyklen
    Kollisionswarnung=1
    counter=Zyklen=0
    Data.Kalibrierung()
    Data.Zyklus_berechnen()
    Zyklen += 1        
    while Zyklen < ZK:
        #Data.Zyklus_berechnen()
        w.after(100, Data.Zyklus_berechnen())
        Zyklen += 1        
        if Zyklen >= ZK:
            Zeit,Einheit=Zeit_anpassen(lfz)
            line="Laufzeit: " + '{:.2f}'.format(Zeit) + Einheit + "\nWeitere(n) " + str(ZK) + " Zyklen starten ?"
            if Bestätigung(line) == "j": Zyklen=0
    log.close()
os.chdir("/Users/Lenovo/Google Drive/Dokumente/Software/Python")
master = Tk()
master.geometry('1200x800')
master.title("Mein Simulator")
w = Canvas(master,width=1200,height=800)
w.pack
LabelZyklen = Label(master=master, bg='#FFCFC9', text='0')
LabelZyklen.place(x=1000, y=0, width=200, height=27)
button = Button(master, text='Plot löschen', width=20, command=löschen)
button.place(x=800, y=0, width=100, height=25)
button = Button(master, text='Neu laden', width=20, command=neu_laden)
button.place(x=900, y=0, width=100, height=25)
button = Button(master, text='Hoch drehen\nX-Achse Links', width=100, command=lambda: Beobachter_drehen("x","links"))
button.place(x=800, y=25, width=100, height=50)
button = Button(master, text='Runter drehen\nX-Achse Rechts', width=100, command=lambda: Beobachter_drehen("x","rechts"))
button.place(x=900, y=25, width=100, height=50)
button = Button(master, text='Links drehen\nY-Achse Links', width=100, command=lambda: Beobachter_drehen("y","links"))
button.place(x=800, y=75, width=100, height=50)
button = Button(master, text='Rechts drehen\nY-Achse Rechts', width=100, command=lambda: Beobachter_drehen("y","rechts"))
button.place(x=900, y=75, width=100, height=50)
button = Button(master, text='Links drehen\nZ-Achse Links', width=100, command=lambda: Beobachter_drehen("z","links"))
button.place(x=800, y=125, width=100, height=50)
button = Button(master, text='Ansicht drehen\nZ-Achse Rechts', width=100, command=lambda: Beobachter_drehen("z","rechts"))
button.place(x=900, y=125, width=100, height=50)
button = Button(master, text='Rechts bewegen\nX-Achse', width=100, command=lambda: Beobachter_bewegen("x","+"))
button.place(x=900, y=175, width=100, height=50)
button = Button(master, text='Links bewegen\nX-Achse', width=100, command=lambda: Beobachter_bewegen("x","-"))
button.place(x=800, y=175, width=100, height=50)
button = Button(master, text='Hoch bewegen\nY-Achse', width=100, command=lambda: Beobachter_bewegen("y","+"))
button.place(x=900, y=225, width=100, height=50)
button = Button(master, text='Runter bewegen\nY-Achse', width=100, command=lambda: Beobachter_bewegen("y","-"))
button.place(x=800, y=225, width=100, height=50)
button = Button(master, text='Vorwärts bewegen\nZ-Achse', width=100, command=lambda: Beobachter_bewegen("z","+"))
button.place(x=900, y=275, width=100, height=50)
button = Button(master, text='Rückwärts bewegen\nZ-Achse', width=100, command=lambda: Beobachter_bewegen("z","-"))
button.place(x=800, y=275, width=100, height=50)
Label_BP = Label(master=master, text='Beobachterposition')
Label_BP.place(x=800, y=325, width=200, height=25)
Label_BV = Label(master=master, text='Beobachtergeschwindigkeit')
Label_BV.place(x=800, y=350, width=200, height=25)
Label_BM = Label(master=master, text='Blickrichtung')
Label_BM.place(x=800, y=375, width=200, height=50)
menu = Menu(master)
master.config(menu=menu)
filemenu = Menu(menu)
menu.add_cascade(label="Simulation", menu=filemenu)
filemenu.add_command(label="Starte existierende Simulation", command=Simulation)
filemenu.add_command(label="Existierende Simulation verändern", command= lambda: Neue_Simulation("ändern"))
filemenu.add_command(label="Definiere neue Simulation", command= lambda: Neue_Simulation("neu"))
filemenu.add_command(label="Definiere neue Objektmaster", command=Neue_Objekte)
filemenu.add_separator()
filemenu.add_command(label="Exit", command=master.quit)
master.mainloop()



