用Small Basic来绘制分形图
前几天,笔记本的屏幕碎了,虽然心痛,但破碎的屏幕让我联想到了很早以前见过的分形图形,但以前没怎么研究过这个东西,这次却产生了玩玩这个的念头。没过两天,无意间又发现了Small Basic: 一个类似LOGO语言的语言,又让我回忆起了小时候玩过的海龟先生。于是,这两个念头一结合:何不用Small Basic的海龟来画画分形图呢?
上网搜索了一些分形图的基本知识,这里先不提那些抽象的教条,咱们来看个实例吧。下面是我在wikipedia上找到的Koch Square图形的l-system定义:
- 变量:F
- 常量:+ -
- 开始形状:F
- 替换规则:F = F + F - F - F + F
不要怕,呵呵,其实这就是一个l-system定义,它描述了一个叫做Koch Square的图形。让我们看看它怎么描述这个图形吧。F是指向前画一个单位的长度;+号代表逆时针旋转90度;-号代表顺时针旋转90度。一个分型图需要两个条件:一个是起始形状,另一个则是如何变幻的规则。在我们这个例子中,起始形状就是向前画一条线,而变幻规则则是一系列的动作:向前画一单元;逆时针旋转90度;再画一单元的线;顺时针旋转90度;…
来看看例子吧,设n为我们准备将替换规则迭代到起始形状上的次数:
当 n=0 时,也就是不将替换规则迭代到开始形状中去,换句话说,就是我们的起始形状:
这时,我们完成这个图形的动作很简单,就是: F
好,当n=1时,我们需要将替换规则迭代一次到开始形状中去,将会产生:
完成这个图形的动作就是: F + F - F - F + F, 也就是一次迭代规则。
好,当n=2时,我们将上式中的所有F再次迭代为迭代规则里的动作,这样,动作就比较多了,是:
F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F
产生的图形如下:
嗯,很明显,继续迭代下去,这动作就太多了,而且这么机械的动作(移动,旋转)不正好适合我们的海龟先生来做么?
好,根据这个规则,我们写下面一段Small Basic代码:
' file: koch_square.sb
' Mr.Turtle will draw a Koch Square for us
' l-system rules:
' variables : F
' constants : + -
' start : F
' rules : F = F + F - F - F + F
' set some default values
angle = 90
length = 3
iteration = 5
' set the graphic panel color
GraphicsWindow.BackgroundColor = "Black"
GraphicsWindow.PenColor = "LightGreen"
' move Mr.Turtle to the left-down corner for start
Turtle.Speed = 9
Turtle.Turn(-90)
Turtle.PenUp()
Turtle.Move(300)
Turtle.Turn(-90)
Turtle.Move(200)
Turtle.Turn(-90)
Turtle.PenDown()
' let's do it!
DrawStart()
' draw one rule
' if iteration is 0, stop further recursion
' otherwise, do recursion
Sub DrawRule
iteration = iteration - 1
If (iteration = 0) Then
Turtle.Move(length)
Turtle.Turn(-angle)
Turtle.Move(length)
Turtle.Turn(angle)
Turtle.Move(length)
Turtle.Turn(angle)
Turtle.Move(length)
Turtle.Turn(-angle)
Turtle.Move(length)
Else
DrawRule()
Turtle.Turn(-angle)
DrawRule()
Turtle.Turn(angle)
DrawRule()
Turtle.Turn(angle)
DrawRule()
Turtle.Turn(-angle)
DrawRule()
EndIf
iteration = iteration + 1
EndSub
' draw the start shape
Sub DrawStart
DrawRule()
EndSub
其中,iteration为迭代次数n,我们将其设为5(这个会比较耗时间,你可以尝试将其设为3),然后让海龟先生为我们“绣”出一副最简单的分形图吧(因为海龟先生画的很慢很仔细,所以我可以相信他是在“绣花”)。
下图为迭代5次的结果:
嗯,没错,这就是一幅传说中的分形图了,虽然是很简单的,但我们也可以看出一些分形图的特征:
- 自相似性:取线段的某一小块,其形状和整体形状很相似
- 无限细分:嗯,理论上,无论你将某部分线段放大,都是一个曲折的线段,理论上你不可能得到一条完全直的线段,当然,我们的海龟先生的生命是有限的,它无法将有限的生命投入到无限的锈图之中。
在l-system中,起始形状叫做Axiom,迭代规则叫做motif。我们再来看看另一个l-system定义的图形:Koch Curve:
Koch {
Angle 60
Axiom F - - F - - F
F = F + F - - F + F
}
这里,我们的角度不再是90度了,而是60度,起始形状是个等边三角形:
那么,让海龟先生为我们画画吧:
' file: koch_curve.sb
' Mr.Turtle will draw a Koch Curve for us
' l-system rules:
' variables : F
' angle : 60
' constants : + -
' start : F - - F - - F
' rules : F = F + F - - F + F
' set some default values
angle = 60
length = 5
iteration = 4
' set the graphic panel color
GraphicsWindow.BackgroundColor = "Black"
GraphicsWindow.PenColor = "LightGreen"
' move Mr.Turtle to the left-down corner for start
Turtle.Speed = 9
Turtle.PenUp()
Turtle.Turn(90)
Turtle.Move(150)
Turtle.Turn(90)
Turtle.Move(150)
Turtle.Turn(90)
Turtle.PenDown()
' let's do it!
DrawStart()
' hide Mr.Turtle
Turtle.Hide()
' draw one rule
' if iteration is 0, stop further recursion
' otherwise, do recursion
Sub DrawRule
iteration = iteration - 1
If (iteration = 0) Then
Turtle.Move(length)
Turtle.Turn(-angle)
Turtle.Move(length)
Turtle.Turn(angle)
Turtle.Turn(angle)
Turtle.Move(length)
Turtle.Turn(-angle)
Turtle.Move(length)
Else
DrawRule()
Turtle.Turn(-angle)
DrawRule()
Turtle.Turn(angle)
Turtle.Turn(angle)
DrawRule()
Turtle.Turn(-angle)
DrawRule()
EndIf
iteration = iteration + 1
EndSub
' draw the start shape
Sub DrawStart
DrawRule()
Turtle.Turn(angle)
Turtle.Turn(angle)
DrawRule()
Turtle.Turn(angle)
Turtle.Turn(angle)
DrawRule()
EndSub
下面是迭代3次的图形:
下面是迭代4次的图形:
也许你会说了:老所怎么这么空啊,画这么多无聊的线段,其实,由简单的规则创造复杂的图形,这是很有趣的事情,比如以下这些图,都是l-system做出来的,而且是3D的,l-system在模拟植物方面非常有效。
当然,网上还有很多不错的作品,而且,l-system只是分形图形的一种,还有其他的诸如函数迭代等方法,这些方法,都能产生非常漂亮的图形,嗯,就等我有时间了再研究吧。









十月 30th, 2008 at 07:57
早起的人儿有沙发!化悲痛为智慧,很强大,你也很有耐心。
十月 30th, 2008 at 09:01
老时建议老所开个培训班啊。
十月 30th, 2008 at 13:31
经Shawn推荐到这里,学习了~
十月 30th, 2008 at 15:47
@大学生乱弹琴 看了你的帖子,好巧,同时写了一个关于分形图的帖子:)
十月 30th, 2008 at 15:49
@自然堂 呵呵,多谢啦,我希望自己写的东西都尽量简单,通俗易懂,容易上手。
十月 30th, 2008 at 15:49
@leehow 嗯,同意,要学神功,必先找刺激,哈哈
十月 30th, 2008 at 17:58
你的评论框怎么搞的啊
十月 30th, 2008 at 18:01
@醉倚西风
http://www.wmd-editor.com/
十月 30th, 2008 at 20:29
@Soloman 那看来你人生中的刺激还不少。
十月 30th, 2008 at 20:35
@leehow 这是夸我呢?还是骂我呢?晕~
十月 30th, 2008 at 20:47
我是过来受刺激的
十月 30th, 2008 at 20:50
@basil 有志气!
十月 30th, 2008 at 20:54
@Soloman 你想多了,明显是在夸你,我连受刺激的资格都没有。
十月 30th, 2008 at 20:56
@leehow 我帮你,你们家什么东西贵,给我,我帮你砸,哈哈~
十月 30th, 2008 at 21:51
@Soloman 那我真是受宠若惊啊,可惜只有几个锅碗瓢盆。
十月 31st, 2008 at 00:31
@Soloman 我推荐人家来,结果我自己忘了来。。。
十月 31st, 2008 at 00:33
@Shawn 你都推荐了人了,你自己肯定是来过散,肯定看过散
十月 31st, 2008 at 00:35
@Soloman 看过,但是没多大兴趣。。。我的意思是,我忘了留言。
十月 31st, 2008 at 11:31
长见识,,但是看着头疼,
我原来也学过一段时间程序,但因为过于注重UI而暂时放弃了,
我说老所你是不是会写个Ubuntu新版的文章呢
十月 31st, 2008 at 11:48
学习了,能加gt,神侃否!
十月 31st, 2008 at 14:39
哇,原来数学如此美丽…… 哈哈!
十月 31st, 2008 at 14:40
@iColor 这段程序是非常容易读的,直接将L-System的公式套成程序就搞定了。我UI也做不好,以前用MFC,太麻烦了,最近看上了wxWidget这个界面库,支持很多语言的。
Ubuntu新版?其实你如果知道apt的工作原理,这些版本都不存在,只存在一个持续维护的主干版,不过也分三个:stable, testing, sid。我喜欢Debian以及Debian儿子Ubuntu的地方就在这,安装一次后,安装盘就可以仍了,呵呵。
十月 31st, 2008 at 14:41
@Jor 恩,还有更漂亮和更有意思的用法,待我慢慢写来哈,呵呵~
十月 31st, 2008 at 14:42
@jk 刚用上gtalk: soloman817@gmail.com
十月 31st, 2008 at 15:30
潜心研究技术的人可敬啊…未来的高科技靠你们了…
十月 31st, 2008 at 15:53
@Yacca 潜心研究美剧的人啊…帮我分析每部看得半懂的美剧的任务就靠你啦…
十一月 13th, 2008 at 19:49
就是我不学这个,不然我就靠你啦 。。。O(∩_∩)O哈哈~