Canvas-Objekte/Linie animiert drehen [gelöst]

Fragen zu Tkinter.
schlangenbeschwörer
User
Beiträge: 419
Registriert: Sonntag 3. September 2006, 15:11
Wohnort: in den weiten von NRW
Kontaktdaten:

Canvas-Objekte/Linie animiert drehen [gelöst]

Beitragvon schlangenbeschwörer » Montag 23. Oktober 2006, 16:47

Hallo!
Wie kann ich eine Linie auf einem Canvas in einer Animation um den anfangspunkt um 90° drehen?
Bzw. drehen kann man Canvas-Objekte ja nicht wirklich.(Oder etwa doch?) Also muss man doch den Endpunkt mit coords() schritt für schritt verlegen, oder?
Wie schreibe ich aber jetzt eine dynamische Funktion, die eine Animation erzeugt, bei der sich die Länge der Linie nicht verändert?
mfg, jj
Zuletzt geändert von schlangenbeschwörer am Donnerstag 9. November 2006, 18:14, insgesamt 1-mal geändert.
Benutzeravatar
Michael Schneider
User
Beiträge: 566
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Re: Canvas-Objekte/Linie animiert drehen

Beitragvon Michael Schneider » Samstag 4. November 2006, 15:53

schlangenbeschwörer hat geschrieben:Wie schreibe ich aber jetzt eine dynamische Funktion, die eine Animation erzeugt, bei der sich die Länge der Linie nicht verändert?
mfg, jj

Hi Schlangenbeschwörer,

das Zauberwort heißt "Mathematik" ;-). Ich sehe da zwei grundsetzliche Möglichkeiten:

a) Winkelfunktionen im rechtwinkligen Dreieck:
sin(w) * Laenge = GK
cos(w) * Laenge = AK

b) Satz des Pythagoras:
x**2 + y**2 = Laenge**2

Im ersten Fall zaehlst Du die Winkel hoch und berechnest den Abstand vom Mittelpunkt in x- und y-Richtung. Das führt zu einer gleichmäßigen Drehung, benötigt aber etwas Rechenleistung. Hier ein Beispiel:

Code: Alles auswählen

from Tkinter import *

class Rotor:
    import Canvas, math, time, thread
    def __init__(self, wMaster, center = (100, 100), length = 100, freq = 1, fps = 25):
        self.fWinkelProTic = 2 * self.math.pi * freq / fps
        self.iWaitTime = int(1000.0/fps)
        self.fAktWinkel = 0.0
        self.fRadius = float(length)/2
        self.iX, self.iY = center
        self.wMaster = wMaster
        self.isRotating = False
        self.Line = self.Canvas.Line(wMaster, 0, 0, 0, 0)
        self.update_line()
       
    def update_line(self):
        fAbstandX = self.fRadius * self.math.sin(self.fAktWinkel)
        fAbstandY = self.fRadius * self.math.cos(self.fAktWinkel)
        self.Line.coords(((self.iX+fAbstandX, self.iY-fAbstandY), (self.iX-fAbstandX, self.iY+fAbstandY)))

    def progress(self):
        if self.isRotating:
            self.fAktWinkel += self.fWinkelProTic
            if self.fAktWinkel > self.math.pi: self.fAktWinkel -= self.math.pi
            self.update_line()
            self.wMaster.after(self.iWaitTime, self.progress)

    def start(self):
        if self.isRotating: return
        self.isRotating = True
        self.thread.start_new_thread(self.progress, ())

    def stop(self):
        self.isRotating = False

wCanvas = Canvas(width = 400, height = 200, bd = 3, relief = SUNKEN)
wCanvas.grid()

R1 = Rotor(wCanvas, center = (100, 100), length = 50, freq = 1, fps = 20)
R2 = Rotor(wCanvas, center = (200, 100), length = 70, freq = 0.5, fps = 15)
R3 = Rotor(wCanvas, center = (300, 100), length = 20, freq = -2)
R1.start()
R2.start()
R3.start()
wCanvas.mainloop()


Im zweiten Fall gibst Du einen Abstand vor und brauchst dann nur den anderen zu berechnen. Wenn Du den Vorgabeabstand aber linear veränderst, ergibt sich eine ungleichmäßige Rotation. Wenn Du dafür sorgst, dass Du immer den größeren Abstandswert veränderst (also sobald abs(a)>abs(b) ist, auf a als Vorgabewert umsteigen), sieht das eigentlich noch passabel aus.

Wenn es Dir auf Performance ankommt, kannst Du auch die Positionen der Linienpunkte für eine Umdrehung zwischenspeichern und brauchst sie dann nicht immer neu zu berechnen.

EDIT: Eigentlich reichen die Sinuswerte für 0.5 Radiant aus

Grüße,
der Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
schlangenbeschwörer
User
Beiträge: 419
Registriert: Sonntag 3. September 2006, 15:11
Wohnort: in den weiten von NRW
Kontaktdaten:

Beitragvon schlangenbeschwörer » Samstag 4. November 2006, 16:35

Hi Michael,
danke für den Code, mit sin/cos hab ichs grad auch hinbekommen, zumidest einigermaßen. Doch es gibt echt keine kurze einfache Funktion dafür? Wenn man z.B. jetzt ein Quadrat drehen will, muss man das also entweder als sehr dicke Linie erzeugen, oder als Polygon, nur das wird dann echt schwer...
Gruß, jj
Benutzeravatar
Michael Schneider
User
Beiträge: 566
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Beitragvon Michael Schneider » Samstag 4. November 2006, 17:46

Hi,

stimmt, wenn Du Torsionsmatrizen einbaust, wirds einfacher. :wink:

Aber im Ernst, Du kannst natürlich Bilder mit der .rotate-Methode der Image-Instanzen drehen und dann ins Photoimage einfügen ... aber darunter werden Performance und Bildqualität erheblich leiden. Wenn Du das Bild nur auf 90° kippen willst ist es aber gut genug.

Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder