分形与混沌(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)分形,敬请期待。