我没有任何编程分形的经验。当然,我看过著名的 Mandelbrot 图像等。
你能给我提供分形的简单算法吗?
编程语言真的无所谓,但我最熟悉actionscript、C#、Java。
我知道如果我在谷歌上搜索分形,我会得到很多(复杂的)信息,但我想从一个简单的算法开始并使用它。
也欢迎提出改进基本算法的建议,比如如何将它们制作成可爱的颜色等。
Mandelbrot 编程很容易。
我的 quick-n-dirty 代码如下(不保证没有错误,但大纲很好)。
这是轮廓:Mandelbrot 集完全位于半径为 2 的圆内的复数网格中。
因此,首先扫描该矩形区域中的每个点。每个点代表一个复数 (x + yi)。迭代那个复数:
[new value] = [old-value]^2 + [original-value]
同时跟踪两件事:
1.) 迭代次数
2.) [new-value] 与原点的距离。
如果达到最大迭代次数,则完成。如果与原点的距离大于 2,则完成。
完成后,根据您完成的迭代次数为原始像素着色。然后移动到下一个像素。
public void MBrot()
{
float epsilon = 0.0001; // The step size across the X and Y axis
float x;
float y;
int maxIterations = 10; // increasing this will give you a more detailed fractal
int maxColors = 256; // Change as appropriate for your display.
Complex Z;
Complex C;
int iterations;
for(x=-2; x<=2; x+= epsilon)
{
for(y=-2; y<=2; y+= epsilon)
{
iterations = 0;
C = new Complex(x, y);
Z = new Complex(0,0);
while(Complex.Abs(Z) < 2 && iterations < maxIterations)
{
Z = Z*Z + C;
iterations++;
}
Screen.Plot(x,y, iterations % maxColors); //depending on the number of iterations, color a pixel.
}
}
}
遗漏的一些细节是:
1.) 准确了解复数的平方是什么以及如何计算它。
2.) 弄清楚如何将 (-2,2) 矩形区域转换为屏幕坐标。
您确实应该从Mandelbrot 集开始,并了解它的真正含义。
其背后的想法相对简单。你从一个复杂变量的函数开始
f(z) = z 2 + C
其中 z 是一个复变量,C 是一个复常数。现在从 z = 0 开始对其进行迭代,即计算 z 1 = f(0)、z 2 = f(z 1 )、z 3 = f(z 2 ) 等等。序列z 1 , z 2 , z 3 , ... 有界的常数C 的集合是Mandelbrot 集合(维基百科页面上图中的黑色集合)。
在实践中,要绘制 Mandelbrot 集,您应该:
关于分形的惊人事实是,我们如何从简单且看似无害的要求中获得极其复杂的集合(特别是 Mandelbrot 集合的边界)。
享受!
如果复数让您头疼,那么可以使用 L 系统来表示范围广泛的分形。这需要几个层进行交互,但每个层本身都很有趣。
首先你需要一只乌龟。前进、后退、左、右、上笔、下笔。即使没有 L 系统驱动,使用海龟几何图形也可以制作许多有趣的形状。搜索“LOGO 图形”或“海龟图形”。完整的LOGO系统实际上是使用无括号剑桥波兰语语法的Lisp编程环境。但是您不必走那么远就可以使用海龟概念获得一些漂亮的照片。
然后你需要一个层来执行一个 L 系统。L-systems 与Post-systems和Semi-Thue 系统有关,和 virii 一样,它们跨越了图灵完备性的边界。这个概念是字符串重写。它可以实现为宏扩展或具有额外控件以绑定递归的过程集。如果使用宏扩展(如下例所示),您仍然需要一个过程集来将符号映射到海龟命令,以及一个遍历字符串或数组的过程以运行编码的海龟程序。对于有界递归过程集(例如),您可以在过程中嵌入海龟命令,并为每个过程添加递归级别检查或将其分解到处理函数中。
这是使用宏扩展和一组非常简短的海龟命令的后记中毕达哥拉斯树的示例。有关 python 和 mathematica 的一些示例,请参阅我的代码高尔夫挑战。
有一本很棒的书叫Chaos and Fractals,每章末尾都有简单的示例代码,用于实现一些分形或其他示例。很久以前,当我读那本书时,我将每个示例程序(用一些基本方言)转换成一个在网页上运行的 Java 小程序。小程序在这里:http ://hewgill.com/chaos-and-fractals/
其中一个示例是一个简单的 Mandelbrot 实现。
另一个要学习的优秀分形是谢尔宾斯基三角形分形。
基本上,画一个三角形的三个角(等边是首选,但任何三角形都可以),然后在其中一个角处开始一个点 P。将 P 随机移动到 3 个角中的任何一个,并在那里画一个点。再次将 P 移动到任何随机角的一半,绘制并重复。
你会认为随机运动会产生随机结果,但事实并非如此。
谢尔宾斯基三角形和科赫曲线是火焰分形的特殊类型。火焰分形是一种非常通用的迭代函数系统,因为它使用非线性函数。
IFS:es 的算法如下:
Start with a random point.
重复以下多次(至少一百万,取决于最终图像大小):
Apply one of N predefined transformations (matrix transformations or similar) to the point. An example would be that multiply each coordinate with 0.5.
Plot the new point on the screen.
如果该点在屏幕外,则在屏幕内随机选择一个新点。
如果你想要漂亮的颜色,让颜色取决于最后使用的转换。
我会从一些简单的东西开始,比如Koch Snowflake。这是一个简单的过程,取一条线并对其进行转换,然后递归地重复该过程,直到它看起来整洁。
一些超级简单的事情,比如取 2 个点(一条线)并添加一个第 3 个点(制作一个角),然后在创建的每个新部分上重复。
fractal(p0, p1){
Pmid = midpoint(p0,p1) + moved some distance perpendicular to p0 or p1;
fractal(p0,Pmid);
fractal(Pmid, p1);
}
mandelbrot 集是通过重复评估一个函数直到它溢出(某个定义的限制),然后检查溢出需要多长时间来生成的。
伪代码:
MAX_COUNT = 64 // if we haven't escaped to infinity after 64 iterations,
// then we're inside the mandelbrot set!!!
foreach (x-pixel)
foreach (y-pixel)
calculate x,y as mathematical coordinates from your pixel coordinates
value = (x, y)
count = 0
while value.absolutevalue < 1 billion and count < MAX_COUNT
value = value * value + (x, y)
count = count + 1
// the following should really be one statement, but I split it for clarity
if count == MAX_COUNT
pixel_at (x-pixel, y-pixel) = BLACK
else
pixel_at (x-pixel, y-pixel) = colors[count] // some color map.
笔记:
value 是一个复数。复数 (a+b i) 的平方得到 (a a-b*b+2*a b i)。您必须使用复杂类型,或者在循环中包含该计算。
这是我使用纯 JavaScript 和 HTML 为 Mandelbrot 分形编写的代码笔。
希望代码很容易理解。
最复杂的部分是缩放和平移坐标系。制作彩虹调色板也很复杂。
function mandel(x,y) {
var a=0; var b=0;
for (i = 0; i<250; ++i) {
// Complex z = z^2 + c
var t = a*a - b*b;
b = 2*a*b;
a = t;
a = a + x;
b = b + y;
var m = a*a + b*b;
if (m > 10) return i;
}
return 250;
}
有时我编程分形是为了好玩和挑战。你可以在这里找到它们。该代码是使用 P5.js 库以 Javascript 编写的,可以直接从 HTML 源代码中读取。
对于那些我见过的算法非常简单,只需找到核心元素,然后一遍又一遍地重复它。我用递归函数来做,但可以用不同的方法来做。
上面的人正在使用寻找 sierpinski 和 Koch 的中点,我更建议复制形状,缩放它们,然后翻译它们以实现“分形”效果。sierpinski 的 Java 伪代码如下所示:
public ShapeObject transform(ShapeObject originalCurve)
{
Make a copy of the original curve
Scale x and y to half of the original
make a copy of the copied shape, and translate it to the right so it touches the first copied shape
make a third shape that is a copy of the first copy, and translate it halfway between the first and second shape,and translate it up
Group the 3 new shapes into one
return the new shape
}