65.9K
CodeProject 正在变化。 阅读更多。
Home

创建分形圣诞树

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (30投票s)

2002年12月23日

3分钟阅读

viewsIcon

247974

downloadIcon

4240

此程序探索如何使用简单的分形算法制作树。

Sample Image - fractalTree.jpg

什么是分形?

分形是一种在尺度上对称的形状,这意味着它放大后看起来与未放大时相同或相似。 许多自然发生的物体都表现出这种尺度的自相似性。 树木、海岸线、山脉和云朵就是一些例子。

如何制作分形?

分形通常使用递归制作。 给定一条线段,对该线段执行操作,通常会产生一个或多个新线段。 然后对新线段再次执行相同的操作。 为了防止程序进入无限循环,递归算法通常包含一个测试,以防止它对小于单个像素的线段进行操作。

这个程序如何创建一棵树?

创建一棵树非常简单。 给定“茎”作为种子“分支”

  1. 绘制分支。
  2. 选择分支上的一个点,在该点放置两个新分支,每个分支位于当前分支的一侧。
  3. 根据用户输入,确定这两个新分支的角度和长度。
  4. 使用左分支进行递归。
  5. 使用右分支进行递归。

这只需几行代码即可完成

public void Start(Line seed)
{
    h15=Math.Abs(seed.Size.Height)/5;
    Fractal(seed, depth);
}

private void Fractal(Line l, int depth)
{
    // draw the branch in a color based on its length
    int len=l.Length;
    if (len < 3)
    {
        gr.DrawLine(pbr3, l.StartPoint, l.EndPoint);
    }
    else if (len < h15)
    {
        gr.DrawLine(pbr2, l.StartPoint, l.EndPoint);
    }
    else
    {
        gr.DrawLine(pbr1, l.StartPoint, l.EndPoint);
    }

    while ( (depth != 0) && (l.Length > 1) )
    {
        // get the second segment when we split the line
        Line l2=l.SplitAt(bp)[1];

        // if no change, then exit.
        if (l2.Length==l.Length)
        {
            return;
        }

        // get the left and right branch starting points
        Line bp1=l.SplitAt(bp+MathEx.Dev(bpDev))[1];
        Line bp2=l.SplitAt(bp+MathEx.Dev(bpDev))[1];

        // the new "master" branch starting point has no randomness
        l=l2;

        // get the left and right branches
        Line lineLeft=bp1.Branch(360-ba+MathEx.Dev(baDev), 
            (int)(bp1.Length*bl/100+MathEx.Dev(blDev)));
        Line lineRight=bp2.Branch(ba+MathEx.Dev(baDev), 
            (int)(bp2.Length*bl/100+MathEx.Dev(blDev)));

        // recurse both branches
        Fractal(lineLeft, depth-1);
        Fractal(lineRight, depth-1);
    }
}

添加随机性

您会注意到上面的代码看起来比实际需要的要复杂一些,因为有那么多 MathEx.Dev 函数调用。 这些调用会获取用户指定的 +/- 偏差,并随机调整分支角度、长度和位置。 这使得我们的树看起来更加自然!

关于用户界面的说明

该程序设置为在主要参数(分支点、角度和长度)更改时自动生成树。 更改 +/- 偏差和颜色不会自动重新生成树。 更改这些参数后,单击“生成”按钮。 添加随机性后,多次单击“生成”按钮以查看不同的树。

在较慢的计算机上,您可能需要关闭自动生成。

使用“深度”微调控件。 这控制递归的级别。 高于 4 的值可能需要很长时间才能生成树。 您可以通过将深度设置为 1,然后递增它来更好地理解该算法。

关于代码的说明

该程序包含我称之为“应用程序自动化层”的粗略原型。 尽情探索其背后的概念。 例如,GUI 是从文本文件生成的,并且颜色选择器控件是“复制的”

颜色通道(红色、绿色或蓝色)

GUI:ColorChannelPicker
STATIC s1 at (0, 3) caption "#:"
SPIN spChannel at (15, 0) size (40, 20) storage value 
    options (min:0 max:255 step:1) \
    onchange "ColorChannelChangeEvent(@, #)"
COLORBOX clrbox at (60, 0) size (20, 20) storage channelColor
GUIEND

颜色选择器(三个之一),它有三个颜色通道和最终颜色

GUI:ColorPicker
INHERIT inhRed at (0, 0) postfix R gui ColorChannelPicker
INHERIT inhGreen at (90, 0) postfix G gui ColorChannelPicker
INHERIT inhBlue at (180, 0) postfix B gui ColorChannelPicker
COLORBOX clrbox at (270, 0) size (60, 20) storage compositeColor
GUIEND

以及主要的 GUI 本身

GUI:MainForm
STATIC s1 at (10, 13) caption "Branch Point:"
STATIC s2 at (10, 33) caption "Branch Angle:"
STATIC s3 at (10, 53) caption "Branch Size:"
STATIC s4 at (150, 13) caption "%"
STATIC s5 at (150, 33) caption "degrees"
STATIC s6 at (150, 53) caption "%"

STATIC s7 at (200, 13) size (100, 15) caption 
    "Deviation +/- :" options (rightjustify)
STATIC s8 at (200, 33) size (100, 15) caption 
    "Deviation +/- :" options (rightjustify)
STATIC s9 at (200, 53) size (100, 15) caption 
    "Deviation +/- :" options (rightjustify)

SPIN spBP at (100, 10) size (50, 20) storage branchPoint 
    options (min:20 max:80 step:1) \
    onchange "AutoUpdateCheck"
SPIN spBPDev at (300, 10) size (50, 20) storage 
    bpDev options (min:0 max:9 step:1)

SPIN spBA at (100, 30) size (50, 20) storage 
    branchAngle options (min:20 max:160 step:1) \
    onchange "AutoUpdateCheck"
SPIN spBADev at (300, 30) size (50, 20) storage 
    baDev options (min:0 max:9 step:1)

SPIN spBS at (100, 50) size (50, 20) storage 
    branchSize options (min:20 max:80 step:1) \
    onchange "AutoUpdateCheck"
SPIN spBSDev at (300, 50) size (50, 20) storage 
    bsDev options (min:0 max:9 step:1)

STATIC s10 at (350, 13) caption "%"
STATIC s11 at (350, 33) caption "degrees"
STATIC s12 at (350, 53) caption "%"

STATIC s13 at (10, 83) caption "Large Branches:"
INHERIT inhColor1 at (100, 80) prefix clr1 gui ColorPicker

STATIC s14 at (10, 108) caption "Small Branches:"
INHERIT inhColor2 at (100, 105) prefix clr2 gui ColorPicker

STATIC s15 at (10, 133) caption "Leaves:"
INHERIT inhColor3 at (100, 130) prefix clr3 gui ColorPicker

BUTTON btnGenerate at (10, 170) size (80, 25) 
    caption "Generate!" \
    onselect "EventUpdateTree"
	
CHECKBOX ckAutoGen at (100, 175) size (100, 20) caption 
    "Auto Generate" storage autoUpdate

STATIC s16 at (200, 178) size (70, 15) options 
    (rightjustify) caption "Depth:"
SPIN spDepth at (275, 175) size (50, 20) storage 
    depth options (min:1 max:10 step:1) \
    onchange "AutoUpdateCheck"

OWNERDRAW fractalTree at (10, 200) options 
    (autosizeW:10 autosizeH:10) \
    onpaint "EventPaintTree()"  \
    onsize "EventUpdateTree()"

GUIEND

现有技术

多年前,我为加利福尼亚州圣地亚哥的 Reuben H. Fleet 太空剧院 (http://www.rhfleet.org/ [^]) 编写了一个程序,作为他们对称展览的一部分。 我相信该展览现在是永久性的。 该程序基于我为太空剧院制作的两个展览之一。 另一个展览展示了海岸线的自相似性。

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.