绘制科赫曲线的程序设计

2021-10-25 03:36朱巍峰
科学技术创新 2021年30期
关键词:科赫海龟画板

朱 勤 朱巍峰

(苏州工业职业技术学院,江苏 苏州 215104)

1 科赫曲线介绍

在自然界中存在着很多自相似的结构,按照一定的比例放大或者缩小它的几何尺寸,整个结构不会发生变化。对这些几何结构的研究成为分形几何学。科赫曲线就是一种典型的分形几何。

先对科赫曲线做一个简单的介绍。给定一条水平线段(图1左)。将它分成三等份,以中间的线段为底边,向上画一个等边三角形。最后再把中间的线段移除,我们就得到了一个一阶的科赫曲线(如图1 右)。

如果在一阶科赫曲线上的每一个线段再做一次上述的操作,我们可以获得二阶的科赫曲线(图2 左)。以此类推,我们可以得到三阶的科赫曲线(图2 右)。这样的操作理论上可以进行无穷多次。结合图1,可以看出,高阶的科赫曲线的水平宽度始终是和图1 左的直线相同,所以我们也可以认为图1 左是一个零阶的科赫曲线。

图1 一阶科赫曲线

图2 二阶和三阶科赫曲线

这种曲线最早是海里格·冯·科赫提出的,所以被命名为科赫曲线。由于他的高阶曲线和雪花的形状很相似,所以也被成为雪花曲线。这种曲线的特点是具有自相似性。很容易可以看出这个曲线的局部和整体的结构是相同的。

2 绘制工具介绍

在本论文中使用了Python3 语言进行编程。这种语言发展至今已经有了一个庞大的计算生态,除了本身的开源优势以外,十四万以上的第三方库更是为它提供了无数的可能。

Python3的编程环境有很多,除了Python3 软件自带的集成开发环境(IDLE)以外,还有Anaconda 和PyCharm 等软件。不同的软件只要安装了相同的库都能实现相同的功能。笔者的编程环境使用的是Anaconda。

在python3 中要实现绘图功能,需要导入相对应的库。可以选择的功能库有很多,比如turtle 库、tkinter 库、matplotlib 库、seaborn 库等。本论文中的科赫曲线只是一个简单的二维图像,使用turtle 库就能够胜任了。

Turtle 是海龟的意思,所以也被称为“海龟库”,我们可以想象有一只小海龟,在画板上爬行,它的爬行轨迹就是画板上绘制的图像。这只海龟就是我们的画笔,只要通过一系列的指令去命令这只小海龟运动,就可以得到我们想要的图像。常用的“海龟库”指令可以控制运行方向,移动距离,旋转角度,画笔颜色,画笔宽度等参数。使用“海龟库”来绘制科赫曲线是一件非常简单而且有趣的事情。

3 程序设计

3.1 程序源代码

看上去有点复杂的科赫曲线要用程序来绘制,会不会很复杂呢?下面给出了绘制科赫曲线的源代码和部分注释。

3.2 程序分析

3.2.1 turtle 库导入

程序中第一行“import turtle as t”的作用是将turtle 库导入到程序中,这样在程序里面才可以使用turtle 库中的相关指令。为了方便写代码,将它的库名重命名为t。在下面的程序中以“t.”开头的指令,都是turtle 库中封装好的功能。编代码时只根据需要调用相关函数,设定相关参数就可以了。

3.2.2 科赫曲线绘制函数

“def DrawKoch(lenght,n):”自定义了一个功能函数,用来绘制科赫曲线,调用它时需要设定两个参数,其中length 设置的是绘制曲线的长度(参考图1 左,直线的长度),它的单位是像素,数值大小决定了整个图形的尺寸。另一个参数n 设置的是科赫曲线的阶数,以图1 和图2 为例,图1 左的n 值为0,图1 右的n值为1。图2 左的n 值为2,图2 右的n 值为3。

这个函数是本程序的核心。短短的7行代码,就能够实现绘制科赫曲线。修改参数length 就可以改变曲线的大小,修改参数n 就可以改变绘制曲线的阶数。我们先假设length 为300 像素。然后对函数进行分析。

函数中的第一层是一个if 和else的分支结构。判断条件是参数n。当n 为0 时,执行“t.fd(lenght)”其中“t.fd”的功能是让“海龟”向前移动,参数length 是移动的距离,之前我们已经假设为300 像素。很显然,当n 为0 时绘制出来的是一个零阶曲线,如图1 左所示是一条300 像素长的直线。

当我们要画一阶科赫曲线时,将参数n 设为1。那么第一层if 和else 分支结构的条件不成立,进入else 分支。这个分支中是一个循环结构。用一个angle 变量去遍历四个角度值。具体来说就是这个循环结构要执行四次,第1 次,angle 为0,第2 次angle 为60,第3 次angle 为-120,第4 次angle 为60。循环结构的循环体中有两条指令,其中“t.left(angle)”是让“海龟”向左手方向转过一定角度,角度值由参数angle 决定。所以每次循环“海龟”会先向左转一个角度,然后再执行“DrawKoch(lenght/3,n-1)”指令。这里是这个函数中最重要的地方,它调用了绘制科赫曲线本身。但是长度变为原来的1/3,由于一开始length 设置为300,所以在这里就变成了100 像素,而且阶数降1,变为0,相当于调用了函数“DrawKoch(100,0)”。分析一下可以看到n 为0,所以第一层if 和else的分支结构中判断条件成立,执行“t.fd(100)”。所以此时调用“DrawKoch(lenght/3,n-1)”的结果相当于执行“t.fd(100)”。

最后我们再回到整个循环结构,可以看出,第1 次循环,“海龟”左转0 度,然后前进100 像素。第2 次循环,“海龟”左转60度,然后前进100 像素。第3 次循环,“海龟”左转-120 度(即右转120 度),然后前进100 像素。第4 次循环,“海龟”左转60 度,然后前进100 像素。这里需要说明一点,“海龟”的初始方向是水平向右的。所以四次循环的整个移动轨迹就是图1 右的一阶科赫曲线。

如果要绘制二阶、三阶或者更高阶的科赫曲线。只要改变main 函数的参数n 就可以了。这个n 就是科赫曲线的阶数。由于在这个函数中用到了递归算法,即函数调用了自身,而每一次调用阶数都会减1,当阶数n 变为0 以后结束递归。比如在本程序中将主函数参数设置为main(300,3),那么绘制出来的就是3 阶科赫曲线,和图2 右一致。如果要绘制图2 左这样的二阶科赫曲线,可以把主函数写成main(300,2)。

3.2.3 主函数main

主函数main 是整个程序的起点,在这里需要对主要的参数进行设置。

其中“def main (lenght,n)”定义了一个主函数main。和“DrawKoch(lenght,n)”函数一样,它也要设置长度和阶数两个参数。这个函数的主要功能是对“海龟”进行一些设置。

先用“t.setup(600,600)”指令创建一个600*600 像素的画板。然后用“t.speed(0)”指令将“海龟”的爬行速度设为最大值,如果希望能够看到图像的绘制过程就需要对“t.speed(0)”中的参数进行设置了。用“t.pensize(2)”指令将“海龟”的宽度设为2 像素,如果希望曲线的更加粗,可以将宽度设置更大的值,但是需要注意曲线长度和宽度之间的比例。通过这三条指令为画图做好准备工作。

“t.pu()”是“t.penup()”的缩写形式,代表将画笔抬起,可以想象成“海龟”飞了起来,此时的“海龟”的移动不会再画板上留下痕迹。然后使用“t.goto(-150,0)”指令让“海龟”移动到画板中X 坐标为-150 像素处。需要说明的是画板的中心点是坐标原点,X轴正方向水平向右,Y 轴正方向是垂直向上。所以说“t.goto(-150,0)”应该在画板中心的左侧150 像素处。这个起点的位置需要根据科赫曲线的尺寸以及每次遍历时移动的距离来合理的调整,由于本程序中将length 长度设置为300,所以将起点设置为-150 是比较合理的。如果将length 设置为400,那么显然将起点设置为“t.goto(-200,0)”更为合适。最后再用“t.pd()”也就是“t.pendown()”,它的作用是落笔,让“海龟”回到画板上,然后再移动“海龟”就能留下爬行的轨迹了。这样我们就做好了画图的准备。

接下来调用了绘制科赫曲线的函数“DrawKoch(lenght,n)”,进行图形的绘制。绘制完毕以后使用“t.hideturtle()”将“海龟”隐藏。最后使用“t.done()”指令保持画板,如果不加入“t.done()”指令,在隐藏了“海龟”以后,画板会自动关闭,绘制好的图画一闪即逝,不利于观察绘制结果。

3.2.4 函数调用

在整个程序中用到了两次def 开头的指令。分别定义了绘制科赫曲线的函数以及主函数。需要说明的是函数在定义以后如果没有被调用是不起作用的。所以在程序的最后调用主函数main,同时设定长度为300 像素,阶数为3。运行程序以后就能够得到一个三阶的科赫曲线。

4 结论

本文设计了一个科赫曲线的绘制程序。这个程序可以在python3的环境中直接使用,只要简单的修改最后一行主函数的参数值,理论上可以实现任意大小,任意阶数的科赫曲线绘制。

在程序中稍加改动可以实现更多的效果。比如使用“t.screensize()”指令就可以对画板参数进行设置,比如做如下设置t.screensize(800,600,“black”),其中的“800,600”参数就是画板的尺寸,“black”是将画板背景色设为黑色。也可以使用“t.pencolor()”指令来设置画笔的颜色。例如使用“t.pencolor(”white“)“将画笔颜色设为白色。在本文中的程序中这两个参数都没有设置,则会使用默认值,画板默认为白色,画笔默认为黑色。因此画出来的是白底黑线的图案。

如果我们在main 函数中“DrawKoch(lenght,n)“指令下方添加“t.right(120)“,这个指令是向右旋转指令,参数120 是角度值120度。这样在画完一个科赫曲线以后,会向右旋转120 度。然后再次调用“DrawKoch(lenght,n)”,画第二个科赫曲线。画完后再向右转120,然后画第三个科赫曲线。这样就得到黑色夜空下的一片白色雪花。如果在绘图过程中改变画笔的颜色,就可以得到一片彩色的雪花了。

本文中使用的主要编程思路是使用递归的算法,让函数自己调用自己,从而用简短的程序实现了复杂的绘图过程。只要通过修改函数中的参数就可以实现不同尺寸,不同阶数的曲线绘制。常见的分形几何图除了科赫曲线以外,还有谢尔宾斯基三角形、谢尔宾斯基地毯、列维曲线、龙形曲线、分形树、海岸线等。这些分形图的绘制也可以用本文提供的程序结构来实现,只要把绘制程序中的算法部分替换掉就可以了。

猜你喜欢
科赫海龟画板
递归加权科赫网络中平均的齐次与非齐次加权接收时间(英)
可怕:一块塑料便可“杀死”一只海龟
细菌造就微观界巨量
海龟泡饭汤
不疯魔不成医
海龟
海龟
七彩画板
七彩画板
七彩画板