创建分形圣诞树






4.94/5 (30投票s)
2002年12月23日
3分钟阅读

247974

4240
此程序探索如何使用简单的分形算法制作树。
什么是分形?
分形是一种在尺度上对称的形状,这意味着它放大后看起来与未放大时相同或相似。 许多自然发生的物体都表现出这种尺度的自相似性。 树木、海岸线、山脉和云朵就是一些例子。
如何制作分形?
分形通常使用递归制作。 给定一条线段,对该线段执行操作,通常会产生一个或多个新线段。 然后对新线段再次执行相同的操作。 为了防止程序进入无限循环,递归算法通常包含一个测试,以防止它对小于单个像素的线段进行操作。
这个程序如何创建一棵树?
创建一棵树非常简单。 给定“茎”作为种子“分支”
- 绘制分支。
- 选择分支上的一个点,在该点放置两个新分支,每个分支位于当前分支的一侧。
- 根据用户输入,确定这两个新分支的角度和长度。
- 使用左分支进行递归。
- 使用右分支进行递归。
这只需几行代码即可完成
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/ [^]) 编写了一个程序,作为他们对称展览的一部分。 我相信该展览现在是永久性的。 该程序基于我为太空剧院制作的两个展览之一。 另一个展览展示了海岸线的自相似性。
许可证
本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。
作者可能使用的许可证列表可以在此处找到。