旋转Tkinter画布上的正方形

时间:2016-04-14 10:45:07

标签: python list tkinter-canvas

我已经接近了,但有两个问题。一个是旋转方块的最终位置(不再位于中心)。第二个是我的原始顶点列表变异,尽管我用列表(..)制作副本。

任何帮助都像往常一样非常受欢迎。

from Tkinter import *
import math


WIDTH = 400
HEIGHT = 400
CANVAS_MID_X = WIDTH/2
CANVAS_MID_Y = HEIGHT/2
SIDE = WIDTH/4

root = Tk()
canvas = Canvas(root, bg="black", height=HEIGHT, width=WIDTH)
canvas.pack()

vertices = [
                    [CANVAS_MID_X - SIDE/2, CANVAS_MID_Y - SIDE/2],
                    [CANVAS_MID_X + SIDE/2, CANVAS_MID_Y - SIDE/2],
                    [CANVAS_MID_X + SIDE/2, CANVAS_MID_Y + SIDE/2],
                    [CANVAS_MID_X - SIDE/2, CANVAS_MID_Y + SIDE/2]]

def rotate(points, angle):
    new_points = list(points)
    rad = angle * (math.pi/180)
    cos_val = math.cos(rad)
    sin_val = math.sin(rad)
    for coords in new_points:
        x_val =  coords[0] 
        y_val = coords[1]
        coords[0] = x_val * cos_val - y_val * sin_val
        coords[1] = x_val * sin_val + y_val * cos_val
    return new_points

def draw_square(points):
    canvas.create_polygon(points, fill="red")

def test():
    print "vertices: ", vertices, "should be: ", "[[150, 150], [250, 150], [250, 250], [150, 250]]"


new_square = rotate(vertices, 30)
draw_square(new_square)
test()
mainloop()

1 个答案:

答案 0 :(得分:2)

您的第一个问题是您使用的公式会在原点周围旋转。我假设您想围绕其中心旋转方块。要做到这一点,你只需翻译正方形,使其中心位于原点,旋转它,然后将其翻译回来。

第二个问题是,list(points) 会创建一个新的外部列表,但不会为{}内的列表创建新列表{1}}。有一些方法可以制作深层副本,为这些内部列表创建新列表,但您并不需要在此处执行此操作。只需从旋转的顶点构建一个新的列表。

我的代码版本将原始方块绘制为蓝色,以便我们可以看到旋转的方块最终位于正确的位置。

points

我还对您的代码进行了一些其他细微更改。

顺便说一下,你可能应该这样做

from Tkinter import *
import math

WIDTH = 400
HEIGHT = 400
CANVAS_MID_X = WIDTH/2
CANVAS_MID_Y = HEIGHT/2
SIDE = WIDTH/4

root = Tk()
canvas = Canvas(root, bg="black", height=HEIGHT, width=WIDTH)
canvas.pack()

vertices = [
    [CANVAS_MID_X - SIDE/2, CANVAS_MID_Y - SIDE/2],
    [CANVAS_MID_X + SIDE/2, CANVAS_MID_Y - SIDE/2],
    [CANVAS_MID_X + SIDE/2, CANVAS_MID_Y + SIDE/2],
    [CANVAS_MID_X - SIDE/2, CANVAS_MID_Y + SIDE/2],
]

def rotate(points, angle, center):
    angle = math.radians(angle)
    cos_val = math.cos(angle)
    sin_val = math.sin(angle)
    cx, cy = center
    new_points = []
    for x_old, y_old in points:
        x_old -= cx
        y_old -= cy
        x_new = x_old * cos_val - y_old * sin_val
        y_new = x_old * sin_val + y_old * cos_val
        new_points.append([x_new + cx, y_new + cy])
    return new_points

def draw_square(points, color="red"):
    canvas.create_polygon(points, fill=color)

def test():
    old_vertices = [[150, 150], [250, 150], [250, 250], [150, 250]]
    print "vertices: ", vertices, "should be: ", old_vertices
    print vertices == old_vertices

draw_square(vertices, "blue")

center = (CANVAS_MID_X, CANVAS_MID_Y)
new_square = rotate(vertices, 30, center)
test()
draw_square(new_square)

mainloop()

在你的其他进口之前。这告诉Python使用真正的分裂。没有它,from __future__ import division 会进行整数除法。这在这里工作正常,但如果SIDE / 2是奇数,它就不会正确。

你应该试着摆脱做

的习惯
SIDE

相反,做

from Tkinter import *

然后像这样调用Tkinter函数:

import Tkinter as tk

这稍微多一点,但它使代码更容易阅读和维护,并防止代码意外使用Tkinter定义的名称之一时可能发生的错误。 FWIW,将canvas = tk.Canvas(root, bg="black", height=HEIGHT, width=WIDTH) 个170多个名称导入您的命名空间。你不需要那种混乱!