Thread Agnesi - Netter Programmierspaß (4 answers)
Opened by hlubenow at 2014-05-18 01:58

hlubenow
 2014-05-18 01:58
#175562 #175562
User since
2009-02-22
875 Artikel
BenutzerIn
[default_avatar]
Hi,

gestern gab es ein interessantes Google-Doodle, gif-Animation hier.
Das wollte ich mal in Tk (Tkinter) nachmachen. Anleitung zur Mathematik hier.
Und ein Video hier.
Die Formel für die Kurve scheint zu sein: y = 8 / (4 + x ^ 2).

Mein Ansatz in Python (konnt's leider noch nicht nach Perl/Tk übertragen):
Code (python): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/usr/bin/python
# coding: iso-8859-1

import math
import Tkinter
from Tkconstants import *

# Screen resolution:
RESX = 800
RESY = 600

XFAC = 100
XSUM = 400
YFAC = 90
YSUM = 300

class AgnesiWindow:
    def __init__(self):
        self.mw = Tkinter.Tk()
        self.mw.option_add("*font", ("Arial", 12, "normal"))
        self.mw.title("Agnesi")
        self.mw.geometry("+90+45")
        self.cv = Tkinter.Canvas(self.mw,
                                 bg = "white",
                                 width = RESX,
                                 height = RESY)
        self.cv.pack()
        self.btn = Tkinter.Button(self.mw,
                                  text = "Ok",
                                  command = self.mw.destroy)
        self.btn.bind(sequence = "<Return>", func = self.bindFunc)
        self.btn.focus()
        self.btn.pack(side = RIGHT,
                      padx = 10,
                      pady = 10)
        self.w = 90
        self.points = {"up" : [math.cos(math.radians(270)),
                               math.sin(math.radians(270))],
                       "low" : [math.cos(math.radians(90)),
                                math.sin(math.radians(90))],
                       "circle" : [0, 0],
                       "line" : [-3.6, 0]}
        self.withdraw = []
        self.cv.create_line(0, self.points["up"][1] * YFAC + YSUM,
                            800, self.points["up"][1] * YFAC + YSUM) 
        self.cv.create_line(0, self.points["low"][1] * YFAC + YSUM,
                            800, self.points["low"][1] * YFAC + YSUM) 
        self.plotDot(self.points["low"], withdraw = False)
        self.mw.after(1000, self.draw)
        self.mw.mainloop()

    def bindFunc(self, a):
        self.mw.destroy()

    def plotPoint(self, point):
        a = [point[0] * XFAC + XSUM, point[1] * YFAC + YSUM]
        self.cv.create_line(a[0], a[1], a[0] + 1, a[1] + 1)

    def plotDot(self, point, withdraw = False):
        a = [point[0] * XFAC + XSUM, point[1] * YFAC + YSUM]
        if withdraw:
            self.withdraw.append(self.cv.create_oval(a[0] - 5, a[1] - 5,
                                                      a[0] + 5, a[1] + 5,
                                                      fill = 'black'))
        else:
            self.cv.create_oval(a[0] - 5, a[1] - 5,
                                a[0] + 5, a[1] + 5,
                                fill = 'black')

    def drawLine(self, from_, to_, withdraw = False):
        a = [from_[0] * XFAC + XSUM, from_[1] * YFAC + YSUM]
        b = [to_[0] * XFAC + XSUM, to_[1] * YFAC + YSUM]
        if withdraw:
            self.withdraw.append(self.cv.create_line(a[0], a[1],
                                                    b[0], b[1]))
        else:
            self.cv.create_line(a[0], a[1], b[0], b[1])

    def draw(self):
        if self.w <= 450:
            for i in self.withdraw:
                self.cv.delete(i)
            self.points["circle"] = [math.cos(math.radians(self.w)),
                                     math.sin(math.radians(self.w))]
            self.plotDot(self.points["circle"], withdraw = True)
            self.plotPoint(self.points["circle"])
            self.w += 1

            b = math.pow(self.points["line"][0], 2)
            self.points["line"][1] = 1 - (8. / (4. + b))
            self.plotPoint(self.points["line"])
            self.plotDot(self.points["line"], withdraw = True)

            self.plotDot([self.points["line"][0], self.points["up"][1]], withdraw = True)
            self.drawLine(self.points["low"], [self.points["line"][0], self.points["up"][1]], withdraw = True)

            self.plotDot([self.points["line"][0], self.points["low"][1]], withdraw = True)
            self.drawLine([self.points["line"][0], self.points["up"][1]],
                          [self.points["line"][0], self.points["low"][1]],
                          withdraw = True)

            self.points["line"][0] += 0.02
            self.mw.after(50, self.draw)
 
if __name__ == "__main__":
    app = AgnesiWindow()

Sieht schon ganz passabel aus, finde ich, aber da ist noch ein Fehler drin: Der Punkt auf dem Kreis müßte auf Höhe des Punktes auf der Kurve sein (und auf der Linie vom unteren Punkt aus). Das ist er leider nicht. :(
Na ja, wenn jemand Zeit und Lust dazu hat, kann er ja versuchen, den Fehler zu finden. Ich habe bisher aber auch mit Probieren "gearbeitet". :)

View full thread Agnesi - Netter Programmierspaß