Loading...
网友提供的内容

用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只是分形图形的一种,还有其他的诸如函数迭代等方法,这些方法,都能产生非常漂亮的图形,嗯,就等我有时间了再研究吧。

相关文章

  1. Small Basic: 海龟先生回来啦
  2. boost::preprocessor库之文件重复与自我重复
  3. boost::preprocessor库之嵌套循环及其它
  4. MSVC对于对齐的结构无法使用stl vector的问题之解决
  5. [转载]windows下php5的安装方法

站内评论

  • 暂无评论
  • 评论: