Seite 1 von 1

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

Verfasst: Montag 23. Oktober 2006, 16:47
von schlangenbeschwörer
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

Re: Canvas-Objekte/Linie animiert drehen

Verfasst: Samstag 4. November 2006, 15:53
von Michael Schneider
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

Verfasst: Samstag 4. November 2006, 16:35
von schlangenbeschwörer
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

Verfasst: Samstag 4. November 2006, 17:46
von Michael Schneider
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