kurse:efcomputergrafik:kw36

Sobald wir von Funktionen (d.h. Unterprogrammen) sprechen, müssen wir uns über den Gültigkeitsbereich von Variablen Gedanken machen. Im Grundsatz gilt:

Variablen sind in dem Block sichtbar und verwendbar, indem sie definiert wurden.

Zu Beginn hier noch ein Easter Egg. Führe dazu folgendes scheinbar nutzlose Programm aus.

EasterEgg
import this
  • Weshalb Holländer?

Aus der Mathematik ist der Funktionsbegriff bekannt. In der Informatik kennen wir das gleiche Prinzip.

# Definition
def meineErsteFunktion():
   # Hier steht der Code
   # meiner ersten Funktion!
   print 42
 
# Begin Hauptprogramm
for i in range(17):
   meineErsteFunktion()

Im obigen Programm wird zuerst eine Funktion mit dem Namen meineErsteFunktion definiert, welche die Zahl 42 ausgibt. Im Hauptprogramm wird die Funktion 17 mal aufgerufen. Soweit nichts spezielles. I.d.R. übergeben wir Funktionen mindestens einen Parameter.

# Definition
def quadratZahl(x):
    print(x*x)
 
# Hauptprogramm
for i in range(1,11):
    quadratZahl(i)

Im Hauptprogramm wird die Funktion quadratZahl aufgerufen und der Wert der Variablen $i$ wird übergeben. In der Funktion quadratZahl übernimmt die lokale Variable $x$ den Wert von $i$. $x$ und $i$ sind zwei verschiedene Variablen mit dem gleichen Inhalt. Sinnvollerweise wird die Quadratzahl wieder zurückgegeben.

# Definition
def quadratZahl(x):
    return(x*x)
 
# Hauptprogramm
for i in range(1,11):
    qZ=quadratZahl(i)
    print(qZ)
    # oder in einer Zeile
    print(quadratZahl(i))

Die Funktion quadratZahl gibt den Wert $x^2$ mit der Anweisung return(x*x) zurück an die Variable qZ im Hauptprogramm. Sinnvollerweise sind die Variablenbezeichnungen in der Funktion und im Hauptprogramm unterschiedlich.

Weitere Informationen findest du unter w3schools-funktionen

Löse folgende Aufgaben durch.

Aufgabe 1 zu Variablen

  1. Wie lautet die Ausgabe von…
def f():
    print(s)
s="Python"
f()

Click to display ⇲

Click to hide ⇱

Python. Variablen sind standardmässig lokal in der Funktion verwendbar, in der sie definiert werden. Man kann aber auch auf globale Variablen innerhalb einer Funktion lesend zugreifen.

  1. und von …
def f():
    print(s)
    s="Anaconda"
    print(s)
 
s="Python"
f()

Click to display ⇲

Click to hide ⇱

Es gibt einen Syntaxfehler. Da im Unterprogramm $f$ auf die Variable $s$ geschrieben wird, muss $s$ lokal definiert werden. Daher ist die erste print(s) Anweisung falsch, weil $s$ noch unbekannt ist.

  1. und von …
def f():
    global s
    print(s)
    s="Anaconda"
    print(s)
 
s="Python"
f()
print(s)

Click to display ⇲

Click to hide ⇱

Python, Anaconda, Anaconda. Mit global s wird die globale Variable $s$ im Unterprogramm sichtbar gemacht. D.h. auf $s$ kann gelesen und geschrieben werden. Entsprechend ist die erste Ausgabe Python, dann wird Anaconda zugewiesen und zweimal Anaconda ausgegeben. Einmal als zweite print-Anweisung im Unterprogramm und einmal als letzte Anweisung im Hauptprogramm.

Aufgabe 2 Gegeben ist folgender Programmrumpf.

heronWurzel
from gturtle import *
def heronWurzel(r):
   # r = Radikand
   # w = Wurzel (Breite)
   # h = Hoehe
   #
   # Hier sollte dein Code stehen
   return(w)
 
print(heronWurzel(inputInt("Gib eine natürliche Zahl ein:")))

Ergänze die Funktion heronWurzel mit dem Heronverfahren. Wurzelberechnung nach Heron hat die Grundidee ein Rechteck mit den Seitenlängen $1$ und $r$ (r für Radikand) in ein flächengleiches Quadrat zu verwandeln. Die Seitenlänge des Quadrates entspricht dann der Wurzel des Flächeninhalts. Wir beginnen mit einem Rechteck mit der Breite $r$ und der Höhe $1$. Damit ist die erste Näherung der Wurzel $w_1=r$. Die nächste Näherung ist der Mittelwert aus Grundlinie und Höhe, d.h. $w_2=\frac{1+r}{2}=\frac{h_1+w_1}{2}$ und damit die Höhe $h_2=r/w_2$.

Allgemein gilt: $$w_{n+1}=\frac{w_n+\frac{r}{w_n}}{2}$$ Sobald $|w_i -h_i|<\varepsilon$ ist bricht der Algorithmus ab. D.h. $\varepsilon$ ist die Genauigkeit.

Ergänze die Funktion heronWurzel so, dass bei jedem Iterationsvorgang das entsprechende Rechteck gezeichnet wird.

Aufgabe 3

  1. Studiert das nachfolgende Programm von Nicholas. Die Implementierung orientiert sich stark an der mathematischen Herleitung.
  2. Welches Konstrukt kennst du noch nicht?

Click to display ⇲

Click to hide ⇱

Listen, Felder, Arrays: Drei Ausdrücke für dasselbe. Finde mehr darüber heraus. Siehe dazu Arrays Besonders wichtig sind die Methoden, die auf Arrays anwendbar sind. Kennst du einige dieser Methoden? Hast du sie gefunden? Falls nicht, du findest sie am Ende des Artikels über Arrays.

nicholasKardioide
from gpanel import *
from math import sin,cos,pi
 
R=1
r=1
points = []
 
def v1(a):
    return [(R+r)*cos(a),(R+r)*sin(a)]
def v2(a):
    b = a * R/r - pi + a
    return [r*cos(b),r*sin(b)]
def add(v1,v2):
    return [v1[0]+v2[0],v1[1]+v2[1]]
 
makeGPanel(-4,4,-4,4)
 
t=0
dt=0.0025
while t<=2*pi:
    p1=v1(t)
    p2=v2(t)
    p3=add(p1,p2)
    points.append(p3)
    move(0,0)
    setColor("black")
    delay(2)
 
    clear()
 
    circle(R)
    move(p1)
    circle(r)
    setColor("red")
    move(p3)
    fillCircle(0.1)
    for p in points:
        point(p)
    t=t+dt

Um die Zoom Funktion in unserem Programm “Mandelbrot” implementieren zu können, müssen wir die Mausevents verstehen.

Bearbeite dazu das Kapitel 3.7 von Tigerjython.

Ein Callback ist somit eine Verzweigung des Programmes aufgrund eines äusseren Ereignisses. Diese äusseren Ereignisse sind von uns Usern initiiert, indem wir mit der Mause oder mit der Tastatur eine Eingabe vornehmen. Aufgrund eines Ereignisses $E$ springt das Programm in ein dafür vorgesehenes Unterprogramm $UP$ führt dieses aus und kehrt wieder an die alte Stelle im Programm zurück um dort weiterzufahren.

Alle Ereignisse $E$, auf die wir reagieren wollen, müssen wir bei der Initialisierung des GPanel's angeben.

makeGPanel(mousePressed = onMousePressed, 
           mouseReleased = onMouseReleased)

mousePressed und mouseReleased sind dabei die Ereignisse, onMousePressed und onMouseReleased sind die Namen der Unterprogramme die beim Eintreten des Ereignisses ausgeführt werden sollen. Eine Liste der Ereignisse findet ihr in der Dokumentation von Tigerjython.

Aufgabe 4

  1. Studiere das nachfolgende Programm
  2. Was macht das Programm? Bist du dir nicht sicher, so lade es herunter und probiere es aus.
Callback
from gpanel import *
 
def onMousePressed(x,y):
    clear()
    move(x,y)
    text("Eine Mausetaste wurde gedrückt")
 
def onMouseReleased(x,y):
    clear()
    move(x,y)
    text("Die Mausetaste wurde wieder losgelassen")
 
def onMouseDragged(x,y):
    clear()
    move(x,y)
    text("Die Mause bewegt sich (ev.) mit gedrückter Taste")
 
makeGPanel(mousePressed = onMousePressed, 
           mouseReleased = onMouseReleased,
           mouseDragged = onMouseDragged)

Aufgabe 5

  1. Ergänze dein Mandelbrot Programm so, dass du mit der Mause einen Zoombereich festlegen kannst. In einer ersten Version musst du den Zoombereich nicht mit einem Rechteck oder Quadrat anzeigen.
  2. Ergänze deine erste Version Mandelbrot mit Zoom so, dass der Zoobereich mit einem farbigen Rechteck oder Quadrat angezeigt wird. Benutze dabei die Idee aus Tigerjython bei den Gummibandlinien.

Hier eine mögliche Lösung.

Mandelbrot-Zoom
from gpanel import *
 
def onMousePressed(x, y):
    global xmin, ymin
    storeGraphics()
    xmin=x
    ymin=y
 
def onMouseReleased(x, y):
    global xmax,ymax
    global neuesBild
    xmax=x
    ymax=ymin+(xmax-xmin)
    neuesBild=0
 
def onMouseDragged(x, y):
    global xmin,ymin
    delta=x-xmin
    recallGraphics()
    move(xmin,ymin)
    setColor("white")
    line(xmin, ymin, xmin+delta, ymin)
    line(xmin+delta, ymin, xmin+delta, ymin+delta)
    line(xmin+delta, ymin+delta, xmin, ymin+delta)
    line(xmin, ymin+delta, xmin, ymin)
 
def getIterationColor(it):
    color = makeColor((it**2) % 256, 
                      (3*it) % 256, 
                      (5*it) % 256)
    return color
 
def Mandelbrot(c):
    z=0
    it=0
    while it<maxIterations and abs(z)<R :
        z = z**2 + c     
        it=it+1          
        if abs(z) > R:  
            return it
    return maxIterations
 
def drawP():
    global xmin, xmax, xstep, xSize
    global ymin, ymax, ystep, ySize
    xstep=(xmax-xmin)/xSize
    ystep=(ymax-ymin)/ySize
    makeGPanel(Size(xSize,ySize),
        mousePressed = onMousePressed, 
        mouseReleased = onMouseReleased,
        mouseDragged = onMouseDragged)
    window(xmin, xmax, ymin, ymax)
    y = ymin
    while y <= ymax:
        x = xmin
        while x <= xmax:
            c = complex(x,y)
            itCount = Mandelbrot(c)
            if itCount == maxIterations:
                setColor("black")
            else:
               setColor(getIterationColor(itCount))
            point(c)
            x += xstep
        repaint()
        y += ystep    
#---------------------------------------
# Hauptprogramm
#---------------------------------------
R = 2
maxIterations = 100
xmin = -2
xmax = 1
ymin = -1.5
ymax = 1.5
xSize=600
ySize=600
neuesBild=0
key = 0
while key!=27:
    if neuesBild==0:
        drawP();
        neuesBild=1
    key = getKeyCode()
  • kurse/efcomputergrafik/kw36.txt
  • Last modified: 2019/09/04 15:14
  • by Marcel Metzler