2016-04-14 59 views
2

我已经接近了,但有两个问题。一个是旋转正方形的最终位置(不再居中)。第二个是我的原始顶点列表发生了变化,尽管我使用list(..)进行了复制。在Tkinter帆布上旋转方块

任何帮助像往常一样受到重视。

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() 
+0

感谢您清楚解释您的问题并发布[mcve]! –

回答

2

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

第二个问题是,这样做list(points)确实创建一个新的外单,但对内部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() 

我也对你的代码做了一些其他的小改动。

顺便说一句,你应该做的

from __future__ import division 
你等进口前

。这告诉Python使用真正的划分。没有它,SIDE/2做整数除法。这在那里可行,但如果SIDE是奇数,它将不正确。


你应该想办法去干什么

from Tkinter import * 

相反的习惯,做

import Tkinter as tk 

,然后调用Tkinter的功能是这样的:

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

这是稍微打字,但它使代码更易于阅读和维护,并且可以防止在代码意外使用Tkinter定义的名称之一时发生的错误。 FWIW,from Tkinter import *将170多个名称导入您的名称空间。你不需要那么混乱!

+0

喜欢它!谢谢。在我学习的这个阶段,这种“超越基础”的答案确实非常有用。 – Robin