乌龟放慢速度以获得更大的图纸
Turtle slowing down for larger drawings
我已经创建了一些代码来模拟 sierpinski 的三角形。为此,在我的代码中,我将其设置为可以模拟三角形上的任意数量的点,但我注意到将其增加到一个很大的数量,最终乌龟花费的时间增加为它继续。
我用 100 000 个点做了一个样本输出,这就是我得到的
0% done
Time since last update: 0.0019948482513427734
5.0% done
Time since last update: 1.2903378009796143
10.0% done
Time since last update: 1.8589198589324951
15.000000000000002% done
Time since last update: 2.325822114944458
20.0% done
Time since last update: 2.9351391792297363
25.0% done
Time since last update: 3.4773638248443604
30.0% done
Time since last update: 4.152036190032959
35.0% done
Time since last update: 4.7314231395721436
40.0% done
Time since last update: 5.260996103286743
44.99999999999999% done
Time since last update: 5.988528490066528
49.99999999999999% done
Time since last update: 6.804485559463501
54.99999999999999% done
Time since last update: 7.768667221069336
60.0% done
Time since last update: 8.379971265792847
65.0% done
Time since last update: 8.995774745941162
70.0% done
Time since last update: 15.876121282577515
75.00000000000001% done
Time since last update: 17.292492151260376
80.00000000000001% done
Time since last update: 29.57323122024536
85.00000000000001% done
Time since last update: 65.96741080284119
90.00000000000003% done
Time since last update: 148.21749567985535
95.00000000000003% done
运行程序主循环的相关代码是这个
t = turtle.Turtle()
t.penup()
curr_time = time()
for x in range(iterations):
#The code will take a while should the triangle be large, so this will give its % completion
if x / iterations > percent_done:
print(percent_done * 100, r"% done", sep='')
percent_done += 0.05
window.update()
print(f"Time since last update:\t{time() - curr_time}")
curr_time = time()
c = determine_point(t, init_c)
make_point(t, c)
determine_point 和 make_point 根本不迭代,所以我找不到让 turtle 大大减慢速度的理由。为什么在创建更多点时海龟会变慢? (屏幕跟踪器已设置为 (0,0) 并且代码本身按预期工作
提出观点:
def make_point(turt: turtle.Turtle, point):
'''
Basically does turt.goto(*point) where point is a list of length 2, then places a dot at that place
I did not use goto because I forgot what the function was, and instead of doing a 2 second google search to find out,
I did a 15 second google search to find out how to set the angle of the turtle, and use trigonometry and pythagorean
theorem in order to move the turt to the right position
'''
if point[0] != turt.xcor():
y = point[1] - turt.ycor()
x = point[0] - turt.xcor()
if x > 0:
turt.setheading(math.degrees(math.atan(y / x)))
else:
turt.setheading(math.degrees(math.pi + math.atan(y / x)))
else:
turt.setheading(0 if point[1] < turt.ycor() else 180)
turt.fd(pythag(turt.xcor(), turt.ycor(), point[0], point[1]))
turt.dot(3)
determine_point:
def determine_point(turt: turtle.Turtle, initial_cords):
'''
Returns the midpoint between the turt's current coordinates and a random one of the of the 3 starting points
'''
coord = initial_cords[random.randint(0, 2)]
result = []
result.append((coord[0] - turt.xcor()) / 2 + turt.xcor())
result.append((coord[1] - turt.ycor()) / 2 + turt.ycor())
return result
pythag:
def pythag(a, b, x, y):
'''
Does pythagorean theorem to find the length between 2 points
'''
return math.sqrt((x - a) ** 2 + (y - b) ** 2)
尽管您的 code 不需要在每次迭代中使用更多资源,但您的 program 需要更多资源,因为它构建在需要的库之上。 turtle 和 tkinter 都是如此。
虽然我们认为turtledot()
是贴上dead墨水,而不是stamp可以有选择地去除,对于底层的 tkinter 图形,一切都是 live 墨水并添加到其(重新)显示列表中。
我无法完全消除每次迭代的时间增加,但通过优化代码,我相信我已经将其减少到不再是一个问题。我的一些优化:将 turtle 置于 radians 模式以避免调用 math.degrees()
;减少对乌龟的调用,例如。通过 position()
一步获取 x 和 y 而不是调用 xcor()
和 ycor()
;关闭 turtle 的 undo 缓冲区,因为它会保留越来越多的图形命令列表:
from turtle import Screen, Turtle
from time import time
from random import choice
from math import sqrt, atan, pi
iterations = 100_000
init_c = [(300, -300), (300, 300), (-300, -300)]
def make_point(t, point):
'''
Basically do turtle.goto(*point) where point is a list of length 2,
then places a dot at that place
I did not use goto() because I forgot what the function was, and instead
of doing a 2 second google search to find out, I did a 15 second google
search to find out how to set the angle of the turtle, and use trigonometry
and pythagorean theorem in order to move the turtle to the right position
'''
x, y = t.position()
if point[0] != x:
dx = point[0] - x
dy = point[1] - y
if dx > 0:
t.setheading(atan(dy / dx))
else:
t.setheading(pi + atan(dy / dx))
else:
t.setheading(0 if point[1] < y else pi)
t.forward(pythag(x, y, point[0], point[1]))
t.dot(2)
def determine_point(t, initial_cords):
'''
Return the midpoint between the turtles's current coordinates
and a random one of the of the 3 starting points
'''
coord = choice(initial_cords)
x, y = t.position()
return [(coord[0] - x) / 2 + x, (coord[1] - y) / 2 + y]
def pythag(a, b, x, y):
'''
Do pythagorean theorem to find the length between 2 points
'''
return sqrt((x - a) ** 2 + (y - b) ** 2)
screen = Screen()
screen.tracer(False)
turtle = Turtle()
turtle.hideturtle()
turtle.setundobuffer(None)
turtle.radians()
turtle.penup()
fraction_done = 0
curr_time = time()
for iteration in range(iterations):
# The code will take a while should the triangle be large, so this will give its % completion
if iteration / iterations > fraction_done:
screen.update()
print(fraction_done * 100, r"% done", sep='')
fraction_done += 0.05
print(f"Time since last update:\t{time() - curr_time}")
curr_time = time()
make_point(turtle, determine_point(turtle, init_c))
screen.update()
screen.exitonclick()
控制台
% python3 test.py
0% done
Time since last update: 0.024140119552612305
5.0% done
Time since last update: 1.2522082328796387
10.0% done
Time since last update: 1.619455099105835
15.000000000000002% done
Time since last update: 1.9793877601623535
20.0% done
...
Time since last update: 9.460317373275757
85.00000000000001% done
Time since last update: 10.161489009857178
90.00000000000003% done
Time since last update: 10.585438966751099
95.00000000000003% done
Time since last update: 11.479820966720581
我已经创建了一些代码来模拟 sierpinski 的三角形。为此,在我的代码中,我将其设置为可以模拟三角形上的任意数量的点,但我注意到将其增加到一个很大的数量,最终乌龟花费的时间增加为它继续。
我用 100 000 个点做了一个样本输出,这就是我得到的
0% done
Time since last update: 0.0019948482513427734
5.0% done
Time since last update: 1.2903378009796143
10.0% done
Time since last update: 1.8589198589324951
15.000000000000002% done
Time since last update: 2.325822114944458
20.0% done
Time since last update: 2.9351391792297363
25.0% done
Time since last update: 3.4773638248443604
30.0% done
Time since last update: 4.152036190032959
35.0% done
Time since last update: 4.7314231395721436
40.0% done
Time since last update: 5.260996103286743
44.99999999999999% done
Time since last update: 5.988528490066528
49.99999999999999% done
Time since last update: 6.804485559463501
54.99999999999999% done
Time since last update: 7.768667221069336
60.0% done
Time since last update: 8.379971265792847
65.0% done
Time since last update: 8.995774745941162
70.0% done
Time since last update: 15.876121282577515
75.00000000000001% done
Time since last update: 17.292492151260376
80.00000000000001% done
Time since last update: 29.57323122024536
85.00000000000001% done
Time since last update: 65.96741080284119
90.00000000000003% done
Time since last update: 148.21749567985535
95.00000000000003% done
运行程序主循环的相关代码是这个
t = turtle.Turtle()
t.penup()
curr_time = time()
for x in range(iterations):
#The code will take a while should the triangle be large, so this will give its % completion
if x / iterations > percent_done:
print(percent_done * 100, r"% done", sep='')
percent_done += 0.05
window.update()
print(f"Time since last update:\t{time() - curr_time}")
curr_time = time()
c = determine_point(t, init_c)
make_point(t, c)
determine_point 和 make_point 根本不迭代,所以我找不到让 turtle 大大减慢速度的理由。为什么在创建更多点时海龟会变慢? (屏幕跟踪器已设置为 (0,0) 并且代码本身按预期工作
提出观点:
def make_point(turt: turtle.Turtle, point):
'''
Basically does turt.goto(*point) where point is a list of length 2, then places a dot at that place
I did not use goto because I forgot what the function was, and instead of doing a 2 second google search to find out,
I did a 15 second google search to find out how to set the angle of the turtle, and use trigonometry and pythagorean
theorem in order to move the turt to the right position
'''
if point[0] != turt.xcor():
y = point[1] - turt.ycor()
x = point[0] - turt.xcor()
if x > 0:
turt.setheading(math.degrees(math.atan(y / x)))
else:
turt.setheading(math.degrees(math.pi + math.atan(y / x)))
else:
turt.setheading(0 if point[1] < turt.ycor() else 180)
turt.fd(pythag(turt.xcor(), turt.ycor(), point[0], point[1]))
turt.dot(3)
determine_point:
def determine_point(turt: turtle.Turtle, initial_cords):
'''
Returns the midpoint between the turt's current coordinates and a random one of the of the 3 starting points
'''
coord = initial_cords[random.randint(0, 2)]
result = []
result.append((coord[0] - turt.xcor()) / 2 + turt.xcor())
result.append((coord[1] - turt.ycor()) / 2 + turt.ycor())
return result
pythag:
def pythag(a, b, x, y):
'''
Does pythagorean theorem to find the length between 2 points
'''
return math.sqrt((x - a) ** 2 + (y - b) ** 2)
尽管您的 code 不需要在每次迭代中使用更多资源,但您的 program 需要更多资源,因为它构建在需要的库之上。 turtle 和 tkinter 都是如此。
虽然我们认为turtledot()
是贴上dead墨水,而不是stamp可以有选择地去除,对于底层的 tkinter 图形,一切都是 live 墨水并添加到其(重新)显示列表中。
我无法完全消除每次迭代的时间增加,但通过优化代码,我相信我已经将其减少到不再是一个问题。我的一些优化:将 turtle 置于 radians 模式以避免调用 math.degrees()
;减少对乌龟的调用,例如。通过 position()
一步获取 x 和 y 而不是调用 xcor()
和 ycor()
;关闭 turtle 的 undo 缓冲区,因为它会保留越来越多的图形命令列表:
from turtle import Screen, Turtle
from time import time
from random import choice
from math import sqrt, atan, pi
iterations = 100_000
init_c = [(300, -300), (300, 300), (-300, -300)]
def make_point(t, point):
'''
Basically do turtle.goto(*point) where point is a list of length 2,
then places a dot at that place
I did not use goto() because I forgot what the function was, and instead
of doing a 2 second google search to find out, I did a 15 second google
search to find out how to set the angle of the turtle, and use trigonometry
and pythagorean theorem in order to move the turtle to the right position
'''
x, y = t.position()
if point[0] != x:
dx = point[0] - x
dy = point[1] - y
if dx > 0:
t.setheading(atan(dy / dx))
else:
t.setheading(pi + atan(dy / dx))
else:
t.setheading(0 if point[1] < y else pi)
t.forward(pythag(x, y, point[0], point[1]))
t.dot(2)
def determine_point(t, initial_cords):
'''
Return the midpoint between the turtles's current coordinates
and a random one of the of the 3 starting points
'''
coord = choice(initial_cords)
x, y = t.position()
return [(coord[0] - x) / 2 + x, (coord[1] - y) / 2 + y]
def pythag(a, b, x, y):
'''
Do pythagorean theorem to find the length between 2 points
'''
return sqrt((x - a) ** 2 + (y - b) ** 2)
screen = Screen()
screen.tracer(False)
turtle = Turtle()
turtle.hideturtle()
turtle.setundobuffer(None)
turtle.radians()
turtle.penup()
fraction_done = 0
curr_time = time()
for iteration in range(iterations):
# The code will take a while should the triangle be large, so this will give its % completion
if iteration / iterations > fraction_done:
screen.update()
print(fraction_done * 100, r"% done", sep='')
fraction_done += 0.05
print(f"Time since last update:\t{time() - curr_time}")
curr_time = time()
make_point(turtle, determine_point(turtle, init_c))
screen.update()
screen.exitonclick()
控制台
% python3 test.py
0% done
Time since last update: 0.024140119552612305
5.0% done
Time since last update: 1.2522082328796387
10.0% done
Time since last update: 1.619455099105835
15.000000000000002% done
Time since last update: 1.9793877601623535
20.0% done
...
Time since last update: 9.460317373275757
85.00000000000001% done
Time since last update: 10.161489009857178
90.00000000000003% done
Time since last update: 10.585438966751099
95.00000000000003% done
Time since last update: 11.479820966720581