Python项目——万花尺
程序员文章站
2023-10-27 15:43:52
用turtle模块创建图形使用参数方程利用数学方程生成曲线用线段画曲线用定时器来生成图形动画将图形保存为图像文件利用海龟画图绘制圆import mathimport turtle#Python的turtle模块来创建图案#draw the circle using turtledef drawCircleTurtle(x,y,r): #move to the dtart of circle turtle.up()#调用up告诉python提笔,即让笔离开虚拟的纸 tu....
- 用turtle模块创建图形
- 使用参数方程
- 利用数学方程生成曲线
- 用线段画曲线
- 用定时器来生成图形动画
- 将图形保存为图像文件
利用海龟画图绘制圆
import math
import turtle#Python的turtle模块来创建图案
#draw the circle using turtle
def drawCircleTurtle(x,y,r):
#move to the dtart of circle
turtle.up()#调用up告诉python提笔,即让笔离开虚拟的纸
turtle.setpos(x+r,y)#绘图前先定义海龟的位置
turtle.down()#调用down,开始绘图
#draw the circle
for i in range(0,365,5):#步长为5,变量i为角度参数
a = math.radians(i)#将角度转换为弧度
turtle.setpos(x+r*math.cos(a),y+r*math.sin(a))#绘制圆的参数方程
drawCircleTurtle(100,100,50)#调用圆形绘图函数
turtle.mainloop()#调用mainloop(),保持tkinter窗口打开
万花尺
- Spiro函数创造新turtle对象
- getParams()方法:初始化Spiro对象
- restart()方法:重置Spiro对象的绘制参数
- draw()方法:用连续的线段绘制曲线
- update()方法:利用线段绘制曲线创建动画
- SpiroAnimator类:同时绘制随机螺线
- genRandomParams()方法:生成随机参数
- restart()方法:重新启动程序
- update()方法:由定时器调用,以动画的形式更新所有的Spiro对象
- toggleTurtles()方法:显示或隐藏光标
- saceDrawing()方法:绘制保存PNG图像文件
import sys, random, argparse
import numpy as np
import math
import turtle
import random
from PIL import Image
from datetime import datetime
from fractions import gcd
#a class tat draws a Spirough
class Spiro:
#constructor
def __init__(self,xc,yc,col,R,r,l):
#creat the turtle object
self.t = turtle.Turtle()#创建一个新的turtle对象
#set the cursor shape
self.t.shape('turtle')#在光标的位置设置海龟
#set the step in degrees
self.step = 5#将参数绘图角度的增量设置为5
#setr the drawing cpmplete flag
self.drawingComplete = False#设置提个标志,在动画中使用它,它会产生一组螺线
#set the parameters
self.setparams(xc,yc,col,R,r,l)#调用设置函数
#initialize the drawing
self.restart()#调用设置函数
# set the parameters
def setparams(self, xc, yc, col, R, r, l) :
# the Spirograph parameters
self.xc = xc # 保存曲线中心坐标
self.yc = yc
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 GCO
gcdVal = gcd(self.r, self.R) # Python模块feacyion内置的gcd()方法来计算半径的GCD
self.nRot = self.r // gcdVal # 确定曲线的周期性
# get ratio of radii
self.K = r / float(R)
# set the color
self.t.color(*col)
# store the current angle
self.a = 0 # 保存当前角度,用来创建动画
"""restart()方法重置Spiro对象绘制参数,让他准备好重画"""
# restart the drawing
def restart(self) :
# set the flag
self.drawingComplete = False # 布置布尔标志drawingComplete ,确定绘图是否完成
# show the turtle
self.t.showturtle() # 显示海龟图标
# go to the first point
self.t.up() # 提笔
R, K, l = self.R, self.K, self.l # 设置局部变量
a = 0.0
x = R * ((l - K) * math.cos(a) + l * K * math.cos((l - K) * a / K)) # 计算角度a设为0时,x和y坐标
y = R*((l - K) * math.sin(a) - l * K * math.sin((l - K) * a / K))
self.t.setpos(self.xc + x, self.yc + y) # 移动到下一个位置而不画线
self.t.down() # 落笔
# draw the whole thing
def draw(self) :
# draw the rest of the points
R, K, l = self.R, self.K, self.l
for i in range(0, 360 * self.nRot + 1, self.step) : # 遍历i的所有范围,以度表示,
a = math.radians(i)
x = R * ((l - K) * math.cos(a) + l * K * math.cos((l - K) * a / K)) # 计算参数i的每个值对应的x,y的坐标
y = R((l - K) * math.sin(a) - l * K * math.sin((l - K) * a / K))
self.t.setpos(self.xc + x, self.yc + y)
# drwing is now done sp hide the turtle cursor
self.t.hideturtle()
# update by on stepe
def update(self) :
# skip the rest of dteps if done
if self.drawingComplete : # update()方法检查drawingComplete标志是否设置
return # 若果没有设置,则继续代码其余部分
# increment the angle
self.a += self.step # update()增加当前的角度
# draw a step
R, K, l = self.R, self.K, self.l
# set the angle
a = math.radians(self.a) # 计算当前的角度对应的(x,y)坐标,并将海龟的位置蝶弄到那里,过程画线
x = R * ((l - K) * math.cos(a) + l * K * math.cos((l - K) * a / K))
y = R*((l - K) * math.sin(a) - l * K * math.sin((l - K) * a / K))
self.t.setpos(self.xc + x, self.yc + y)
# if drawing is complete,set the flag
if self.a >= 360 * self.nRot : # 检查角度是否达到这条特定曲线定制的完整范围
self.drawingComplete = True # 达到范围设置drawingComplete,即完成绘图
# drawing is now done so hide the turtle cursor
self.t.hideturtle() # 调用函数隐藏绘图光标
#clear everything
def clear(self):
self.t.clear()
#a classfor animal Spirographs
class SpiroAnimator:
#construtor
def __init__(self,N):
#set the timer value in milliseconds
self.deltaT = 10#以毫秒为单位的时间间隔,用于定时器
#get the window dimensions
self.width = turtle.window_width()#海龟窗口的尺寸
self.height = turtle.window_height()
#creat the Spiro objects
self.spiros = []#创建空数组,其中将填入spiro对象
for i in range(N):
#generate random parameters
rparams = self.genRandomParams()#调用辅助方法genRandomParams()
#set tge spiro parameters
spiro = Spiro(*rparams)#创建新的spiro对象,并将其添加到Spiro对象列表,rparams为元组,但是构造函数需要参数列表,*rparams将元组转换为参数列表
self.spiros.append(spiro)
#call timer
turtle.ontimer(self.update,self.deltaT)# turtle.ontimer()方法每隔deltaT毫秒调用update()
# restart spieo drawing
def restart(self) :
for spiro in self.spiros : # 变量所有的spiro对象,清除以前绘制的每条螺线
# clear
spiro.clear()
# generate random parameters
rparams = self.genRandomParams()
# set the spiro parameters
spiro.setparams(*rparams) # 分配新的螺线参数
# restart drawing
spiro.restart() # 重启程序
# generate random parameters
def genRandomParams(self) : # randint()方法:返回指定范围内的随机数
width, height = self.width, self.height
R = random.randint(50, min(width, height) // 2) # R设置为50至窗口短边一半的随机整数
r = random.randint(10, 9 * R // 10) # r设置为R的10%-90%之间
l = random.uniform(0.1, 0.9) # ubiform()方法 l为0.1-0.9之间的随机小数
xc = random.randint(-width // 2, width // 2) # 屏幕内随机选择x,y坐标,选择屏幕上的一个随机点作为螺线的中心
yc = random.randint(-height // 2, height // 2)
col = (random. random(), # 随机设置红,绿,蓝色的成份
random. random(),
random. random())
return (xc, yc, col, R, r, l) # 计算的参数作为一个元祖返回
"""update()方法:由定时器调用,以动画的形式更新所有的Spiro对象"""
def update(self) : # 使用计算器nComplete来记录已画的Spiro对象的数目
# update all spiros
nComplete = 0 # 初始化
for spiro in self.spiros : # 遍历Spiro对象的列表
# update
spiro.update() # 更新
# count completed spiros
if spiro.drawingComplete : # 如果一个Spiro完成,计算器加1
nComplete += 1
# restart if all spiros are complete
if nComplete == len(self.spiros) : # 检查计算器,看所有对象是否已经完成
self.restart()
# call the timer
turtle.ontimer(self.update, self.deltaT) # 调用计时器的方法,在deltaT毫秒后再次调用update()方法
# 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()
def saveDrawing():
#hide the turtle cursor
turtle.hideturtle()#隐藏海龟图标
#generate unique filenames
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
canvas = turtle.getcanvas()
#save the drawing as a postscipt image
canvas.postscript(file = fileName + '.eps')#利用canvas对象,将图像保存为嵌入式EPS文件格式
#use the Pillow module to convert the postscript image file to png
img = Image.open(fileName + '.eps')#打开EPS文件,将其保存为png格式
img.save(fileName + '.png','png')
#show the turtle cursor
turtle.showturtle()#取消隐藏的海龟图标
#main() function
def main():
#use sys.argv if needed
print('generate spirograph...')
#creat parser
descStr = """This program draws Spirographs using the Turtle module.
When run with no arguments,this program draws random Spirogrphs.
Terminology:
R:radius of outer circle
r:radius of inner circle
l:ratio of hole distance to r
"""
"""解析命令行和参数初始化"""
parser = argparse.ArgumentParser(description = descStr)#创建参数解析对象#argoarse为python的解析包
#add expected arguments
parser.add_argument('--sparams',nargs=3,dest='sparams',required=False,#向解析器添加--sparams可选参数
help = "THe three arguments in sparams:R,r,l,")
# parse args
args = parser.parse_args()#调用函数进行解析
#set the width od the drawing windoe to 80 percent of the screen width
turtle.setup(width=0.8)#将绘图窗口的宽度设置为80%的屏幕宽度
#set the cursoe shape to turtle
turtle.shape('turtle')#设置光标的图像为海龟
#set the title to Spirographs!
turtle.title('Spirographs!')#设置窗口标题
#add the key handle to save our drawings
turtle.onkey(saveDrawing,"s")#按s键保存图像
#start listening
turtle.listen()#让窗口监听用户事件
#hide the main turtle cursor
turtle.hideturtle()#隐藏海龟图标
#check for any arguments sent ti --sparams and draw the Spirograph
if args.sparams:#检查是否有参数传给--sparms,如果有,就从字符串中提取,并用‘列表解析’将它们转换为浮点数
params = [float(x) for x in args.sparams]
#draw the Spirograph with the given parameters
col = (0.0,0.0,0.0)
spiro = Spiro(0,0,col,*params)
spiro.draw()
else:#若果命令行没有采纳数,就进入随机模式
#create the animator object
spiroAnim = SpiroAnimator(4)#创建4幅图像
#add a kry handler to toggle the turtle cursor
turtle.onkey(spiroAnim.toggleTurtles,"t")#按键t切换海龟光标
#add a key handler to restart the animation
turtle.onkey(spiroAnim.restart,"space")#处理空格键盘space
#start the turtle main loop
turtle.mainloop()#调用mianloop():tikinter窗口打开
#call main
if __name__ == '__main__':
main()
为什么是两个图像?而不是四个图像?
如何向sparams赋值
本文地址:https://blog.csdn.net/qq_43163978/article/details/107574465