在 Tkinter 画布上旋转正方形 [英] Rotating a Square on Tkinter Canvas

查看:31
本文介绍了在 Tkinter 画布上旋转正方形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've got close, but there are two problems. One is the final position of the rotated square (no longer in centre). The second is my original vertices list mutates, in spite of my making a copy with list(..).

像往常一样非常感谢任何帮助.

Any help much appreciated as usual.

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

推荐答案

您的第一个问题是您使用的公式围绕原点旋转.我假设您想围绕其中心旋转正方形.为此,您只需平移正方形使其中心位于原点,旋转它,然后将其平移回来.

Your first problem is that the formula you're using rotates around the origin. I assume you want to rotate the square around its center. To do that, you simply translate the square so its center is at the origin, rotate it, then translate it back.

第二个问题是list(points) 确实会创建一个新的外部列表,但它不会points 中的列表.有很多方法可以制作深层副本,为这些内部列表创建新列表,但您实际上不需要在这里这样做.只需从旋转的顶点构建一个新列表.

The second problem is that doing list(points) does create a new outer list, but it doesn't create new lists for the lists inside points. There are ways to make a deep copy that creates new lists for those internal lists, but you don't really need to do that here. Just build a fresh list from the rotated vertices.

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

My version of your code draws the original square in blue so that we can see that the rotated square ends up in the correct location.

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

我还对您的代码进行了其他一些小改动.

I've also made a few other minor changes to your code.

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

BTW, you probably should do

from __future__ import division

在您的其他导入之前.这告诉 Python 使用真正的除法.没有它, SIDE/2 做整数除法.这在这里工作正常,但如果 SIDE 是奇数,则它不会正确.

before your other imports. That tells Python to use true division. Without it, SIDE / 2 does integer division. That works ok here, but it won't be correct if SIDE is an odd number.

你应该试着改掉做事的习惯

You should try to get out of the habit of doing

from Tkinter import *

相反,做

import Tkinter as tk

然后像这样调用 Tkinter 函数:

and then call the Tkinter functions like this:

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

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

This is slightly more typing, but it makes the code easier to read and maintain, and prevents the errors that can occur when your code accidentally uses one of the names that Tkinter has defined. FWIW, doing from Tkinter import * imports over 170 names into your namespace. You don't need that clutter!

这篇关于在 Tkinter 画布上旋转正方形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆