# 《Python极客项目编程 》——2.3　代码

+关注继续查看

### 2.3.1　Spiro构造函数

　 # a class that draws a Spirograph
class Spiro:
# constructor
def __init__(self, xc, yc, col, R, r, l):

# create the turtle object
1         self.t = turtle.Turtle()
# set the cursor shape
2       self.t.shape('turtle')
# set the step in degrees
3        self.step = 5
# set the drawing complete flag
4         self.drawingComplete = False

# set the parameters
5         self.setparams(xc, yc, col, R, r, l)

# initialize the drawing
6         self.restart()

### 2.3.2　设置函数

　     # set the parameters
def setparams(self, xc, yc, col, R, r, l):
# the Spirograph parameters
1         self.xc = xc
self.yc = yc
2         self.R = int(R)
self.r = int(r)
self.l = l
self.col = col
# reduce r/R to its smallest form by dividing with the GCD
3         gcdVal = gcd(self.r, self.R)
4         self.nRot = self.r//gcdVal
self.k = r/float(R)
# set the color
self.t.color(*col)
# store the current angle
5         self.a = 0

### 2.3.3　restart()方法

　     # restart the drawing
def restart(self):
# set the flag
1        self.drawingComplete = False
# show the turtle
2         self.t.showturtle()
# go to the first point
3         self.t.up()
4         R, k, l = self.R, self.k, self.l
a = 0.0
5         x = R*((1-k)*math.cos(a) + l*k*math.cos((1-k)*a/k))
y = R*((1-k)*math.sin(a) - l*k*math.sin((1-k)*a/k))
6         self.t.setpos(self.xc + x, self.yc + y)
7         self.t.down()

### 2.3.4　draw()方法

draw()方法用连续的线段绘制该曲线。

　     # draw the whole thing
def draw(self):
# draw the rest of the points
R, k, l = self.R, self.k, self.l
1         for i in range(0, 360*self.nRot + 1, self.step):
2           x = R*((1-k)*math.cos(a) + l*k*math.cos((1-k)*a/k))
y = R*((1-k)*math.sin(a) - l*k*math.sin((1-k)*a/k))
self.t.setpos(self.xc + x, self.yc + y)
# drawing is now done so hide the turtle cursor
3       self.t.hideturtle()

### 2.3.5　创建动画

update()方法展示了一段一段绘制曲线来创建动画时所使用的绘图方法。

　     # update by one step
def update(self):
# skip the rest of the steps if done
1       if self.drawingComplete:
return
# increment the angle
2         self.a += self.step
# draw a step
R, k, l = self.R, self.k, self.l
# set the angle
x= self.R*((1-k)*math.cos(a) + l*k*math.cos((1-k)*a/k))
y = self.R*((1-k)*math.sin(a) - l*k*math.sin((1-k)*a/k))
self.t.setpos(self.xc + x, self.yc + y)
# if drawing is complete, set the flag
4         if self.a >= 360*self.nRot:
self.drawingComplete = True
# drawing is now done so hide the turtle cursor
self.t.hideturtle()

### 2.3.6　SpiroAnimator类

SpiroAnimator类让我们同时绘制随机的螺线。该类使用一个计时器，每次绘制曲线的一段。这种技术定期更新图像，并允许程序处理事件，如按键、鼠标点击，等等。但是，这种计时器技术需要对绘制代码进行一些调整。

　 # a class for animating Spirographs
class SpiroAnimator:
# constructor
def __init__(self, N):
# set the timer value in milliseconds
1          self.deltaT = 10
# get the window dimensions
2          self.width = turtle.window_width()
self.height = turtle.window_height()
# create the Spiro objects
3          self.spiros = []
for i in range(N):
# generate random parameters
4             rparams = self.genRandomParams()
# set the spiro parameters
5              spiro = Spiro(*rparams)
self.spiros.append(spiro)
# call timer
6              turtle.ontimer(self.update, self.deltaT)

### 2.3.7　genRandomParams()方法

　     # generate random parameters
def genRandomParams(self):
width, height = self.width, self.height
1         R = random.randint(50, min(width, height)//2)
2         r = random.randint(10, 9*R//10)
3         l = random.uniform(0.1, 0.9)
4        xc = random.randint(-width//2, width//2)
5       yc = random.randint(-height//2, height//2)
6        col = (random.random(),
random.random(),
random.random())
7         return (xc, yc, col, R, r, l)

### 2.3.8　重新启动程序

# restart spiro drawing
def restart(self):
for spiro in self.spiros:
# clear
spiro.clear()
# generate random parameters
rparams = self.genRandomParams()
# set the spiro parameters
spiro.setparams(*rparams)
# restart drawing
spiro.restart()

### 2.3.9　update()方法

　     def update(self):
# update all spiros
1         nComplete = 0
for spiro in self.spiros:
# update
2             spiro.update()
# count completed spiros
3             if spiro.drawingComplete:
nComplete += 1
# restart if all spiros are complete
4         if nComplete == len(self.spiros):
self.restart()
# call the timer
5         turtle.ontimer(self.update, self.deltaT)

update()方法使用一个计数器nComplete来记录已画的Spiro对象的数目。在1行初始化后，它遍历Spiro对象的列表，在2行更新它们，如果一个Spiro完成，就在3行将计数器加1。

### 2.3.10　显示或隐藏光标

    # toggle turtle cursor on and off
def toggleTurtles(self):
for spiro in self.spiros:
if spiro.t.isvisible():
spiro.t.hideturtle()
else:
spiro.t.showturtle()

### 2.3.11　保存曲线

　 # save drawings as PNG files
def saveDrawing():
# hide the turtle cursor
1         turtle.hideturtle()
# generate unique filenames
2         dateStr = (datetime.now()).strftime("%d%b%Y-%H%M%S")
fileName = 'spiro-' + dateStr
print('saving drawing to %s.eps/png' % fileName)
# get the tkinter canvas
3         canvas = turtle.getcanvas()
# save the drawing as a postscipt image
4         canvas.postscript(file = fileName + '.eps')
# use the Pillow module to convert the postscript image file to PNG
5        img = Image.open(fileName + '.eps')
6         img.save(fileName + '.png', 'png')
# show the turtle cursor
7        turtle.showturtle()

turtle程序采用tkinter创建的用户界面（UI）窗口，在3和4行，利用tkinter的canvas对象，将窗口保存为嵌入式PostScript（EPS）文件格式。由于EPS是矢量格式，你可以用高分辨率打印它，但PNG用途更广，所以在5行用Pillow打开EPS文件，并在6行将它保存为PNG文件。最后，在7行，取消隐藏海龟光标。

### 2.3.12　解析命令行参数和初始化

1     parser = argparse.ArgumentParser(description=descStr)

help="The three arguments in sparams: R, r, l.")

# parse args
3     args = parser.parse_args()

　    # set the width of the drawing window to 80 percent of the screen width
1     turtle.setup(width=0.8)

# set the cursor shape to turtle
2     turtle.shape('turtle')

# set the title to Spirographs!
3     turtle.title("Spirographs!")
# add the key handler to save our drawings
4    turtle.onkey(saveDrawing, "s")
# start listening
5     turtle.listen()

# hide the main turtle cursor
6     turtle.hideturtle()

　     # check for any arguments sent to --sparams and draw the Spirograph
1    if args.sparams:
2        params = [float(x) for x in args.sparams]
# draw the Spirograph with the given parameters
col = (0.0, 0.0, 0.0)
3       spiro = Spiro(0, 0, col, *params)
4        spiro.draw()
else:
# create the animator object
5         spiroAnim = SpiroAnimator(4)
# add a key handler to toggle the turtle cursor
6         turtle.onkey(spiroAnim.toggleTurtles, "t")
# add a key handler to restart the animation
7        turtle.onkey(spiroAnim.restart, "space")

# start the turtle main loop
8     turtle.mainloop()

20911 0
【HEVC学习与研究】38、HEVC编码过程中的块分割结构
【本文主要分为前后两部分，前半部分基本是Vivienne Sze、Madhukar BudagaviGary和J. Sullivan所编著的《High Efficiency Video Coding (HEVC) ——Algorithms and Architectures》的第三章前半部分的笔记，后半部分是在HM-10.0中对Intra预测时块分割相应的代码研究。
1306 0
DL之RNN：人工智能为你写代码——基于TF利用RNN算法实现生成编程语言代码(C++语言)、训练&测试过程全记录（二）
DL之RNN：人工智能为你写代码——基于TF利用RNN算法实现生成编程语言代码(C++语言)、训练&测试过程全记录
29 0
numpy基础代码操练
In [20]: b[0,:,1] Out[20]: array([1, 5, 9]) In [21]: b[0,:,1] Out[21]: array([1, 5, 9]) In [22]: b[0,:,-1] Out[22]: array([ 3, 7, 11]) ...
929 0
05.Java网络编程（代码实践）

786 0
+关注

12049

0

《2021云上架构与运维峰会演讲合集》

《零基础CSS入门教程》

《零基础HTML入门教程》