TkInter python - 在画布上创建点以获得Sierpinsky三角形

时间:2017-08-29 16:31:53

标签: python-3.x tkinter tkinter-canvas

我想制作一个绘制Sierpinsky三角形(任何模数)的程序。为了做到这一点,我使用了TkInter。该程序通过随机移动一个点来生成分形,始终将其保持在两侧。多次重复该过程后,分形出现。

然而,这是一个问题。我不知道如何在TkInter的画布上绘制点。程序的其余部分没问题,但我不得不欺骗"为了通过绘制小线而不是点来绘制点。它的工作方式或多或少,但它没有尽可能多的分辨率。

是否有功能在画布上绘制点,或者使用其他工具(使用Python)?我们也欢迎改进其他课程的想法。

感谢。这就是我所拥有的:

from tkinter import *
import random
import math
def plotpoint(x, y):
    global canvas
    point = canvas.create_line(x-1, y-1, x+1, y+1, fill = "#000000")
x = 0 #Initial coordinates
y = 0
#x and y will always be in the interval [0, 1]
mod = int(input("What is the modulo of the Sierpinsky triangle that you want to generate? "))
points = int(input("How many points do you want the triangle to have? "))
tkengine = Tk() #Window in which the triangle will be generated
window = Frame(tkengine)
window.pack()
canvas = Canvas(window, height = 700, width = 808, bg = "#FFFFFF") #The dimensions of the canvas make the triangle look equilateral
canvas.pack()
for t in range(points):
    #Procedure for placing the points
    while True:
        #First, randomly choose one of the mod(mod+1)/2 triangles of the first step. a and b are two vectors which point to the chosen triangle. a goes one triangle to the right and b one up-right. The algorithm gives the same probability to every triangle, although it's not efficient.
        a = random.randint(0,mod-1)
        b = random.randint(0,mod-1)
        if a + b < mod:
            break
    #The previous point is dilated towards the origin of coordinates so that the big triangle of step 0 becomes the small one at the bottom-left of step one (divide by modulus). Then the vectors are added in order to move the point to the same place in another triangle.
    x = x / mod + a / mod + b / 2 / mod
    y = y / mod + b / mod
    #Coordinates [0,1] converted to pixels, for plotting in the canvas.
    X = math.floor(x * 808)
    Y = math.floor((1-y) * 700)
    plotpoint(X, Y)
tkengine.mainloop()

3 个答案:

答案 0 :(得分:1)

如果你想绘制像素,画布可能是错误的选择。您可以创建PhotoImage并修改单个像素。如果您绘制每个单独的像素,它会有点慢,但如果您只为图像的每一行调用一次put方法,则可以获得显着的加速。

这是一个完整的例子:

from tkinter import *
import random
import math

def plotpoint(x, y):
    global the_image
    the_image.put(('#000000',), to=(x,y))

x = 0
y = 0
mod = 3
points = 100000
tkengine = Tk() #Window in which the triangle will be generated
window = Frame(tkengine)
window.pack()
the_image = PhotoImage(width=809, height=700)
label = Label(window, image=the_image, borderwidth=2, relief="raised")
label.pack(fill="both", expand=True)

for t in range(points):
    while True:
        a = random.randint(0,mod-1)
        b = random.randint(0,mod-1)
        if a + b < mod:
            break
    x = x / mod + a / mod + b / 2 / mod
    y = y / mod + b / mod

    X = math.floor(x * 808)
    Y = math.floor((1-y) * 700)
    plotpoint(X, Y)

tkengine.mainloop()

答案 1 :(得分:0)

您可以将canvas.create_oval与边界框的两个角使用相同的坐标:

from tkinter import *
import random
import math
def plotpoint(x, y):
    global canvas
#     point = canvas.create_line(x-1, y-1, x+1, y+1, fill = "#000000")
    point = canvas.create_oval(x, y, x, y, fill="#000000", outline="#000000")
x = 0 #Initial coordinates
y = 0
#x and y will always be in the interval [0, 1]
mod = int(input("What is the modulo of the Sierpinsky triangle that you want to generate? "))
points = int(input("How many points do you want the triangle to have? "))
tkengine = Tk() #Window in which the triangle will be generated
window = Frame(tkengine)
window.pack()
canvas = Canvas(window, height = 700, width = 808, bg = "#FFFFFF") #The dimensions of the canvas make the triangle look equilateral
canvas.pack()
for t in range(points):
    #Procedure for placing the points
    while True:
        #First, randomly choose one of the mod(mod+1)/2 triangles of the first step. a and b are two vectors which point to the chosen triangle. a goes one triangle to the right and b one up-right. The algorithm gives the same probability to every triangle, although it's not efficient.
        a = random.randint(0,mod-1)
        b = random.randint(0,mod-1)
        if a + b < mod:
            break
    #The previous point is dilated towards the origin of coordinates so that the big triangle of step 0 becomes the small one at the bottom-left of step one (divide by modulus). Then the vectors are added in order to move the point to the same place in another triangle.
    x = x / mod + a / mod + b / 2 / mod
    y = y / mod + b / mod
    #Coordinates [0,1] converted to pixels, for plotting in the canvas.
    X = math.floor(x * 808)
    Y = math.floor((1-y) * 700)
    plotpoint(X, Y)
tkengine.mainloop()

深度为3和100,000点,这给出了:

enter image description here

答案 2 :(得分:0)

最后找到了一个解决方案:如果要将1x1点放在像素(x,y)中,那么完全的命令是:

point = canvas.create_line(x, y, x+1, y+1, fill = "colour")

椭圆形是2x2点的好主意。

原始程序的一个显着特点是,如果每个点都被视为一个单独的对象,它会占用大量的RAM。