Bauforum-Logo

Offenes Forum Bauingenieurwesen

log in | registrieren

zurück zum Forum
  Mix-Ansicht

Python-3-Programmierbeispiel: Gleichgewicht, Schwerpunkt und Hebelarm an einer Balkenwaage (Software)

verfasst von Martin Vogel Homepage E-Mail, Dortmund / Bochum, 08.01.2017, 22:21 Uhr

Dieses Python-3-Programm mit Tkinter-Grafik und Mausbedienung über Schieberegler war in ähnlicher Form im vergangenen Jahr die Beispiellösung für die Programmieraufgabe im ersten Semester. Eine Balkenwaage hat vier mit der Maus beeinflussbare Parameter: die Längen der beiden Balkenarme und die Massen am jeweiligen Armende. Die Schieber sind so angeordnet, dass die Bedienung möglichst intuitiv ist. Die Regler für die Längen sind horizontal angeordnet und entgegengesetzt skaliert, die Regler für die Massen sind vertikal angeordnet.

Die Beschriftung der einzelnen Komponenten wird dynamisch an die sich ändernde Geometrie der Anordnung angepasst und auch eine gedrehte Beschriftung kommt vor. Ein (minimaler) 3D-Effekt wird durch einen Stapel immer heller und kleiner werdender Kreisscheiben erzielt, die eine Art Glanzpunkt auf den Massekugeln darstellen.

[image]

Download: [image]ZIP-Archiv_F8RAASYL1.zip

# Simulation einer Balkenwaage
#
# Die Massen an den Balkenenden sowie die Längen der Waagbalkenhälften
# sind variabel und können mit Schiebereglern beeinflusst werden.
#
# Durch Rechtsklick auf einen Schieberegler lässt sich die Waage wieder
# ins Gleichgewicht bringen.

from tkinter import Tk, Canvas, Label, Entry, Scale, mainloop, messagebox
from math import sin, cos, atan2, degrees, hypot

# Programmfenster einrichten
T = Tk()
T.title("Gleichgewicht und Schwerpunkt")

# Zeichenfläche definieren
C = Canvas(T, width=800, height=600, bg="white")
C.grid(row=0, column=1, columnspan=2, rowspan=2)


def kreis(p, r, fill="black", outline=None, width=1):
    """Zeichnet Kreis um Punkt p mit Radius r"""
    # Falls Randfarbe nicht angegeben wurde, entspricht sie der Füllfarbe.
    if not outline:
        outline = fill
    # Der Kreis wird über das ihn umschließende Quadrat definiert.
    C.create_oval(p[0]-r, p[1]-r, p[0]+r, p[1]+r,
                  fill=fill, outline=outline, width=width)


def kugel(p, m):
    """Zeichnet Kugel der Masse m an Punkt p"""
    # Der Radius ist proportional zur dritten Wurzel der Masse.
    r = m**(1/3)*10
    # Die Kreisscheibe ist rot.
    kreis(p, r, "#E00000")
    # Oben links befindet sich ein kleiner Glanzpunkt. Er besteht aus
    # vielen Kreisen, die immer heller und immer kleiner werden.
    for ri in range(int(r/2), 0, -1):
        pi = (p[0]-r/3, p[1]-r/3)
        fi = "#E0%02X%02X" % (int(180*(1-2*ri/r)), int(180*(1-2*ri/r)))
        kreis(pi, ri, fi)
    # Beschriftung
    C.create_text(p, text=m, fill="white")


def zeichnung(event=None):
    """Baut die Zeichnung komplett neu auf"""
    C.delete("all")

    # Maßstab: 1 Meter entspricht 30 Pixeln
    m = 30

    # Höhe des senkrechten Aufhängestabes
    h = 0.1 * m

    # Fadenlänge der aufgehängten Massen
    fl = 3*m

    # Massen links/rechts von Schiebereglern ablesen
    lm = S_LMasse.get()
    rm = S_RMasse.get()

    # Längen links/rechts von Schiebereglern ablesen
    ll = S_LLänge.get()
    rl = S_RLänge.get()

    # Schwerpunktordinate auf dem Waagbalken
    try:
        s = rm/(lm+rm)*(ll+rl)
    except ZeroDivisionError:
        C.create_text(400, 100, text="Eine der beiden Massen muss größer als"
                      " null sein.")
        return

    # Startpunkt (Gelenkige Aufhängung)
    p0 = x0, y0 = 400, 100

    # Winkel der Waage
    alpha = atan2(s-ll, h)

    # Hypotenuse des rechtwinkligen Dreiecks
    # Aufhängepunkt-Schwerpunkt-Balkenschnittpunkt
    hyp = h*m/cos(alpha)+fl

    # Schwerpunkt
    ps = x0, y0+hyp

    # Schnittpunkt von Aufhängestab und Waagbalken
    p1 = x0-h*m*sin(alpha), y0+h*m*cos(alpha)

    # Punkt des rechten Winkels im blauen Schwerpunktdreieck
    pw = x0-hyp*sin(alpha)*cos(alpha), y0+hyp*cos(alpha)*cos(alpha)

    # Linker Endpunkt des Waagbalkens
    pl = p1[0]-ll*m*cos(alpha), p1[1]-ll*m*sin(alpha)

    # Rechter Endpunkt des Waagbalkens
    pr = p1[0]+rl*m*cos(alpha), p1[1]+rl*m*sin(alpha)

    # Aufhängestab
    C.create_line(p0, p1, width=10, fill="brown")

    # Gelenkige Aufhängung
    kreis(p0, 0.3*m, fill="white", outline="black", width=4)

    # Waagbalken
    C.create_line(pl, pr, width=10, capstyle="round", fill="brown")

    # Linke Masse
    pl1 = pl[0], pl[1]+fl
    C.create_line(pl, pl1, width=2)
    kugel(pl1, lm)

    # Rechte Masse
    pr1 = pr[0], pr[1]+fl
    C.create_line(pr, pr1, width=2)
    kugel(pr1, rm)

    # Schwerpunkt zeichnen und beschriften
    kreis(ps, 3, fill="blue")
    C.create_text(x0, y0+hyp+5, fill="blue",
                  text="Schwerpunkt", anchor="n")

    # Winkel einzeichnen:
    # Das blaue Dreieck
    C.create_polygon(p0, ps, pw, outline="blue", fill="")
    # Der Maßbogen des Winkels
    C.create_arc(x0-2.5*m, y0-2.5*m, x0+2.5*m, y0+2.5*m,
                 style="arc", outline="blue",
                 start=270, extent=-degrees(alpha))
    # Die Pfeilspitze des Maßbogens nur bei ausreichend großem Winkel zeichnen
    if abs(degrees(alpha)) > 5:
        x2 = x0+10 if alpha < 0 else x0-10
        y2 = y0+2.5*m
        C.create_polygon(x2, y2-5, x0, y2, x2, y2+3, fill="blue")
    # Winkelbemaßung je nach Vorzeichen links- oder rechtsbündig
    C.create_text(x0, y0+2.5*m, fill="blue",
                  text=" α = %.2f° " % abs(degrees(alpha)),
                  anchor="e" if alpha < 0 else "w")
    # Schwerpunktabstand (falls kein Gleichgewicht) beschriften
    if alpha:
        sa = hypot(ps[0]-pw[0], ps[1]-pw[1])/m
        C.create_text((ps[0]+pw[0])/2, (ps[1]+pw[1])/2,
                      anchor="s", fill="blue",
                      angle=degrees(-alpha), text="%.2fm" % sa)


# Eingabebereich: Jeder Schieberegler lässt sich mit Rechtsklick
# in die Gleichgewichtslage zurücksetzen (falls möglich).

# Vertikaler linker Regler
Label(text="linke Masse\n[kg]").grid(row=0, column=0, sticky="ew")
S_LMasse = Scale(from_=0, to=99, width=20, orient="vertical", length=500,
                 tickinterval=10, resolution=0.1, command=zeichnung)
S_LMasse.set(10)
S_LMasse.grid(row=1, column=0, sticky="ns")


def reset_LMasse(event):
    S_LMasse.set(S_RMasse.get()*S_RLänge.get()/S_LLänge.get())
    zeichnung()
S_LMasse.bind("<Button-3>", reset_LMasse)

# Vertikaler rechter Regler
Label(text="rechte Masse\n[kg]").grid(row=0, column=3, sticky="ew")
S_RMasse = Scale(from_=0, to=99, width=20, orient="vertical", length=500,
                 tickinterval=10, resolution=0.1, command=zeichnung)
S_RMasse.set(10)
S_RMasse.grid(row=1, column=3, sticky="ns")


def reset_RMasse(event):
    S_RMasse.set(S_LMasse.get()*S_LLänge.get()/S_RLänge.get())
    zeichnung()
S_RMasse.bind("<Button-3>", reset_RMasse)

# Horizontaler linker Regler
Label(text="Länge des linken Waagbalkenarmes\n[m]",
      ).grid(row=3, column=0, columnspan=2, sticky="ew")
S_LLänge = Scale(from_=10, to=1, width=20, orient="horizontal",
                 tickinterval=1, resolution=0.1, command=zeichnung)
S_LLänge.set(5)
S_LLänge.grid(row=4, column=0, columnspan=2, sticky="ew")


def reset_LLänge(event):
    if S_LMasse.get():
        S_LLänge.set(S_RLänge.get()*S_RMasse.get()/S_LMasse.get())
        zeichnung()
S_LLänge.bind("<Button-3>", reset_LLänge)

# Horizontaler rechter Regler
Label(text="Länge des rechten Waagbalkenarmes\n[m]"
      ).grid(row=3, column=2, columnspan=2, sticky="ew")
S_RLänge = Scale(from_=1, to=10, width=20, orient="horizontal",
                 tickinterval=1, resolution=0.1, command=zeichnung)
S_RLänge.set(5)
S_RLänge.grid(row=4, column=2, columnspan=2, sticky="ew")


def reset_RLänge(event):
    if S_RMasse.get():
        S_RLänge.set(S_LLänge.get()*S_LMasse.get()/S_RMasse.get())
        zeichnung()
S_RLänge.bind("<Button-3>", reset_RLänge)

# Anfangsdarstellung
zeichnung()
mainloop()

--
Dipl.-Ing. Martin Vogel
Leiter des Bauforums

Heute schon programmiert? Einführung in Python 3 (PDF)

antworten
 



gesamter Thread:

zurück zum Forum
  Mix-Ansicht
Offenes Forum Bauingenieurwesen | Kontakt | Impressum
8382 Postings in 3995 Threads, 1086 registrierte User, 35 User online (0 reg., 35 Gäste)
powered by my little forum  RSS-Feed  ^
map | new