0%

Fractals and Chaos | 分形与混沌

分形与混沌(Chapter 2)

笔者在上一篇博客中简单地介绍了几种分形体,现在就让我们试着在Java环境中实现一些简单的分形体。

简单IFS(Iterated Functions Systems )分形

一如既往,我们首先实现一个界面及其监听器来方便我们画图。读者如果不了解具体方法可参照笔者之前的博客,这里不再赘述。

我们先来画一个简单的球形:

1
2
3
4
5
6
7
8
9
10
double x = 0, y = 0;
double a = -1.7, b = -2, c = -2, d = -2;
for (int i = 0; i < 100000; i++) {
x = d * Math.sin(a * x) - Math.sin(b * y);
y = c * Math.cos(a * x) + Math.cos(b * y);
int m = (int) ((d * Math.sin(a * x) - Math.sin(b * y)) * 100 + 400);
int n = (int) ((c * Math.cos(a * x) + Math.cos(b * y)) * 100 + 400);
gr.drawLine(m, n, m, n);
gr.setColor(new Color(250, i % 255, i % 155));
}

代码中的 a、b、c、d 为我们拟定的参数,它们决定了整个分形图形的形状。我们将参数代入公式,用 for循环 来实现100000次的递归,每递归一次画一个点。 要注意的是,画在JFrame上的点应为整数,所以我们在画之前须将坐标 m、n 强制转型为整型。
在这里插入图片描述
如果我们将参数稍加修改(double a = -2, b =-30, c = -1.9, d = 1.9;)则有:

在这里插入图片描述

类似地,还有:

1
2
3
4
5
6
7
8
9
10
11
12
double x = 0f;
double y = 0f;
double a = -1.7, b = 1.8, c = -1.9, d = 0.4;
for (int i = 0; i < 255000; i++) {
double temx = Math.sin(a * y) + c * Math.cos(a * x);
double temy = Math.sin(b * x) + d * Math.cos(b * y);
int x1 = (int) (temx * 130 + 400);
int y1 = (int) (temy * 130 + 400);
gr.setColor(new Color(100, i % 255, i % 155));
gr.drawLine(x1, y1, x1, y1);
x = temx; y = temy;
}
在这里插入图片描述

是不是很神奇呢? 读者可以自己尝试着修改参数。期待你们的作品哦。

随机参数画法(Gallery of Randomly Generated IFS)

这里的实现思路基本与简单IFS相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
double x = 0, y = 0;
double rda[] = { 0.1400, 0.4300, 0.4500, 0.4900 };
double rdb[] = { 0.0100, 0.5200, -0.4900, 0.0000 };
double rdc[] = { 0.0000, -0.4500, 0.4700, 0.0000 };
double rdd[] = { 0.5100, 0.5000, 0.4700, 0.5100 };
double rde[] = { -0.0800, 1.4900, -1.6200, 0.0200 };
double rdf[] = { -1.3100, -0.7500, -0.7400, 1.6200 };
for (int i = 0; i < 1000000; i++) {
Random ran = new Random();
int rr = ran.nextInt(4);
double temx = rda[rr] * x + rdb[rr] * y + rde[rr];
double temy = rdc[rr] * x + rdd[rr] * y + rdf[rr];
int x1 = (int) (temx * 100 + 400);
int y1 = (int) (temy * 100 + 400);
gr.setColor(new Color(224,76,49));
gr.drawLine(x1, y1, x1, y1);
x = temx; y = temy;
}

要注意的是,这里需要运用随机数组,每组参数(a、b、c、d )的值如代码中展示。我们运用随机数Random ran = new Random(); int rr = ran.nextInt(4);来锚定每次选取哪一组参数。执行结果如下:

如图所示,我们得到了一个IFS枫叶。在这里,分形图形的自相似性质就非常明显了。照此思路,我们尝试修改参数:

1
2
3
4
5
6
double rda[] = { 0.0000 ,0.7248 ,0.1583 , 0.3386 };
double rdb[] = { 0.2439 , 0.0337 , -0.1297, 0.3694 };
double rdc[] = { 0.0000 , -0.0253 , 0.3550, 0.2227 };
double rdd[] = { 0.3053, 0.7426, 0.3676 , -0.0756 };
double rde[] = { 0.0000, 0.2060, 0.1383, 0.0679 };
double rdf[] = { 0.0000, 0.2538, 0.1750, 0.0826 };
在这里插入图片描述

再比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
double x = 0, y = 0;
double rda[] = { 0.2020, 0.1380 };
double rdb[] = { -0.8050, 0.6650 };
double rdc[] = { -0.6890, -0.5020 };
double rdd[] = { -0.3420, -0.2220 };
double rde[] = { -0.3730, 0.6600 };
double rdf[] = { -0.6530, -0.2770 };
for (int i = 0; i < 1000000; i++) {
Random ran = new Random();
int rr = ran.nextInt(2);
double temx = rda[rr] * x + rdb[rr] * y + rde[rr];
double temy = rdc[rr] * x + rdd[rr] * y + rdf[rr];
int x1 = (int) (temx * 550 + 330);
int y1 = (int) (temy * 550 + 670);
gr.setColor(new Color(250, i % 255, i % 155));
gr.drawLine(x1, y1, x1, y1);
x = temx; y = temy;
}
在这里插入图片描述

小结

IFS分形是分形学科重要的分支之一。它的算法相对简单,但却依然能绘制出瑰丽的图形,体现着几何之美。探索之路,永无止境,分形还有着无穷的秘密等待我们去发掘。IFS分形还可以用来实现一些缓冲动画与空间矩阵,在以后的博客中,笔者会一一为读者介绍 。下篇博客将会介绍一些简单的谢尔宾斯基(Sierpinski)分形,敬请期待。

在这里插入图片描述