Seite 1 von 1

Pfeil anhand eines Winkels zeichnen

Verfasst: Sonntag 20. Dezember 2009, 12:40
von MasterJulian
Da dies kein GUI bezogenes Problem ist, sondern ein mathematisches, habe ich es hier gepostet. Ich möchte einen Pfeil (Polygon) in Abhängigkeit eines Winkels zeichnen. Er soll also um den Mittelpunkt (210,210) gedreht werden. Die Ursprungskoordinaten lauten (210.0, 30.0), (190.0, 210.0), (230.0, 210.0). Meine Funktion zum berechnen der neuen Punkte sieht so aus:

Code: Alles auswählen

def calcarrow(angle):
    angle = math.radians(angle)
    AX = 0
    AY = 180
    AX2 = math.cos(angle) * AX - AY * math.sin(angle)
    AY2 = math.cos(angle) * AY - AX * math.sin(angle)
    
    BX = 20
    BY = 0
    BX2 = math.cos(angle) * BX - BY * math.sin(angle)
    BY2 = math.cos(angle) * BY - BX * math.sin(angle)

    CX = -20
    CY = 0
    CX2 = math.cos(angle) * CX - CY * math.sin(angle)
    CY2 = math.cos(angle) * CY - CX * math.sin(angle)
    return [(210 - AX2, 210 - AY2),(210 - BX2, 210 - BY2),(210 - CX2, 210 - CY2)]
Die Spitze stimmt, der rest leider nicht. Der Pfeil wird immer schmäler zwischen 0 und 45 Grad und dann immer größer. Warscheinlich eine triviale Sache, aber ich stehe irgendwie auf dem Schlauch. Dieses ganze Vektor-, Verschiebung-, Drehungsgedöns hab ich schon in der Schule nie gemocht.

Verfasst: Sonntag 20. Dezember 2009, 15:54
von EyDu

Code: Alles auswählen

ax = cos(angle) * l
ay = sin(angle) * l

#Spitze
bx = cos(angle + delta) * s
by = sin(angle + delta) * s

cx = cos(angle - delta) * s
cy = cos(angle - delta) * s
Damit hast du einen Pfeil, welcher immer auf den Ursprung zeigt. Den zu verschieben sollte jetzt nicht mehr so schwer sein.

Verfasst: Sonntag 20. Dezember 2009, 20:50
von problembär
Weißt Du, "Tkinter.Canvas.create_line()" kennt sogar ein Argument "arrow = ...".

Gruß

Verfasst: Sonntag 20. Dezember 2009, 22:07
von snafu
Woran machst du fest, dass er Tkinter nutzen will? Aber die Anregung ist an sich ja nicht schlecht. Vielleicht einfach mal schauen, ob das verwendete Toolkit Unterstützung in dieser Richtung bietet.

Verfasst: Dienstag 22. Dezember 2009, 10:03
von problembär
snafu hat geschrieben:Woran machst du fest, dass er Tkinter nutzen will?
Das weiß ich natürlich nicht, das ist nur eine Anregung.

Hier noch mal ein Beispiel mit Tkinter:

Code: Alles auswählen

#!/usr/bin/env python

import Tkinter
from Tkconstants import *
 
class ArrowWindow:

    def __init__(self):

        self.mw = Tkinter.Tk()
        self.mw.title("Arrow")
        self.mw.geometry("+300+250")

        self.cv = Tkinter.Canvas(self.mw, bg = "white")
        self.cv.pack()

        self.arrow = 0
        self.drawArrow("Right")

        self.btnOk = Tkinter.Button(self.mw,
                                    text = "Ok",
                                    command = self.mw.destroy)

        self.btnOk.bind(sequence = "<Return>",
                      func = lambda event: self.mw.destroy())

        self.btnOk.focus()

        self.btnOk.pack(side = RIGHT, padx = 10, pady = 10)

        self.fr = Tkinter.Frame(self.mw)
        self.fr.pack(side = RIGHT, padx = 10, pady = 10)

        self.btnl = Tkinter.Button(self.fr, text = "Left", command = lambda: self.drawArrow("Left")).pack(side = LEFT, padx = 10)

        self.btnu = Tkinter.Button(self.fr, text = "Up", command = lambda: self.drawArrow("Up")).pack(side = LEFT, padx = 5)

        self.btnd = Tkinter.Button(self.fr, text = "Down", command = lambda: self.drawArrow("Down")).pack(side = LEFT, padx = 5)
    
        self.btnr = Tkinter.Button(self.fr, text = "Right", command = lambda: self.drawArrow("Right")).pack(side = LEFT, padx = 10)

        self.mw.mainloop()


    def drawArrow(self, direction):

        self.cv.delete(self.arrow)

        if direction in ("Left", "Right"):
            coords = (100, 100, 200, 100)
        else:
            coords = (150, 50, 150, 150)

        if direction in ("Left", "Up"):
            arrdir = FIRST
        else:
            arrdir = LAST

        self.arrow = self.cv.create_line(coords, arrow = arrdir, arrowshape = (8, 10, 3))

if __name__ == "__main__":
   app = ArrowWindow()
:wink:

(Man kann die vier Richtungsbuttons hier übrigens nicht in einer Liste verwalten, weil die Parameterübergabe mit "command = lamda :" dann nicht hinhaut ...)

Gruß

Verfasst: Dienstag 22. Dezember 2009, 10:24
von HWK
problembär hat geschrieben:(Man kann die vier Richtungsbuttons hier übrigens nicht in einer Liste verwalten, weil die Parameterübergabe mit "command = lamda :" dann nicht hinhaut ...)
Warum nicht? Ungetestet:

Code: Alles auswählen

for text in ('Left', 'Up', 'Down', 'Right'):
    self.button_list.append(Tkinter.Button(self.fr, text=text,
                                           command=lambda arg=text:
                                               self.draw_arrow(arg)))
    self.button_list[-1].pack(side=LEFT, padx=10 if text in ('Left', 'Right')
                                                 else 5)
Übrigens: Du weißt, was Du mit

Code: Alles auswählen

self.btnu = Tkinter.Button(self.fr, text = "Up", command = lambda: self.drawArrow("Up")).pack(side = LEFT, padx = 5)
in self.btnu speicherst?
MfG
HWK

Verfasst: Dienstag 22. Dezember 2009, 21:17
von problembär
HWK hat geschrieben:
problembär hat geschrieben:(Man kann die vier Richtungsbuttons hier übrigens nicht in einer Liste verwalten, weil die Parameterübergabe mit "command = lamda :" dann nicht hinhaut ...)
Warum nicht?
Hey super! Mit der Syntax aus Deinem Beispiel:

Code: Alles auswählen

... lamda arg = text: self.drawArrow(arg)
geht's: Vielen Dank!
HWK hat geschrieben:Übrigens: Du weißt, was Du mit

Code: Alles auswählen

self.btnu = Tkinter.Button(self.fr, text = "Up", command = lambda: self.drawArrow("Up")).pack(side = LEFT, padx = 5)
in self.btnu speicherst?
Ääh, jedenfalls nicht das, was ich speichern wollte :oops: :P. Auch dafür danke, HWK!

Manchmal ist das schon toll, wie gut viele von euch sich in Python auskennen!

Gruß

Verfasst: Dienstag 22. Dezember 2009, 21:36
von HWK
Ansonsten gibt es ja statt lambda noch functools.partial.
MfG
HWK