[簡(jiǎn)介]
最近一直在讀《深?yuàn)W的簡(jiǎn)潔》,里面有一章介紹了幾種使用噪聲產(chǎn)生分形圖的方法,感覺(jué)很有意思,于是嘗試使用計(jì)算機(jī)模擬了一下,效果還不錯(cuò)(噪聲法比傳統(tǒng)迭代法在編程上好實(shí)現(xiàn)一些,后來(lái)發(fā)現(xiàn)這類算法還不少,搜索chaosgame可以找到更多)。
[sierpinski三角形的噪聲產(chǎn)生法]
在這些噪聲游戲中,sierpinski(謝爾賓斯基)三角形的生成規(guī)則可謂是最簡(jiǎn)單的:
1.在平面上選取三個(gè)點(diǎn),標(biāo)記為1、2、3,作為大三角形的頂點(diǎn)。
2.選擇其中一點(diǎn),作為“當(dāng)前點(diǎn)”(比如選擇1號(hào))。
3.產(chǎn)生1~3的隨機(jī)數(shù),在該數(shù)表達(dá)的頂點(diǎn)與“當(dāng)前點(diǎn)”的中點(diǎn)繪制一個(gè)新點(diǎn),并將新點(diǎn)作為“當(dāng)前點(diǎn)”。
4.重復(fù)步驟3,即可逼近圖案。
*.注意隨機(jī)數(shù)最好不要使用以時(shí)間作為種子的產(chǎn)生方式。
[模擬程序]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
package com.geiv.chaos; import java.awt.event.keyevent; import com.thrblock.util.randomset; import geivcore.defaultfactor; import geivcore.keyfactor; import geivcore.keylistener; import geivcore.r; import geivcore.uesi; import geivcore.enginedata.obj.obj; public class sierpinski extends defaultfactor implements keylistener{ uesi ues; obj[] basepoint; obj crtpoint; public sierpinski(uesi ues, int times){ this .ues = ues; basepoint = new obj[ 3 ]; //創(chuàng)建三個(gè)基準(zhǔn)點(diǎn) for ( int i = 0 ;i < 3 ;i++){ basepoint[i] = ues.creatobj(uesi.bgindex); basepoint[i].addglpoint( "70dbdb" , 0 , 0 ); basepoint[i].show(); } basepoint[ 0 ].setcentralx( 400 ); //設(shè)置三點(diǎn)位置 basepoint[ 0 ].setcentraly( 60 ); basepoint[ 1 ].setcentralx( 60 ); basepoint[ 1 ].setcentraly( 550 ); basepoint[ 2 ].setcentralx( 740 ); basepoint[ 2 ].setcentraly( 550 ); crtpoint = basepoint[ 0 ]; //將0號(hào)點(diǎn)作為當(dāng)前點(diǎn) this .setkeylistener( this ); ues.pushkeyboardio( this ); for ( int i = 0 ;i < times;i++){ generatenew(); } } @override public void dokeybord(keyfactor whom, int keycode, boolean ispressed) { //掛載回調(diào) if (ispressed){ if (keycode == keyevent.vk_space){ //空格對(duì)應(yīng)創(chuàng)建一個(gè)新點(diǎn) generatenew(); } else if (keycode == keyevent.vk_a){ //a對(duì)應(yīng)創(chuàng)建100個(gè)新點(diǎn) for ( int i = 0 ;i < 100 ;i++){ generatenew(); } } else if (keycode == keyevent.vk_b){ //b對(duì)應(yīng)創(chuàng)建1000個(gè)新點(diǎn) for ( int i = 0 ;i < 1000 ;i++){ generatenew(); } } } } public void generatenew(){ obj flagpoint = basepoint[randomset.getrandomnum( 0 , 2 )]; //隨機(jī)選擇基準(zhǔn)點(diǎn)之一 float nx = (flagpoint.getcentralx() + crtpoint.getcentralx())/2f; //計(jì)算中點(diǎn) float ny = (flagpoint.getcentraly() + crtpoint.getcentraly())/2f; obj newpoint = ues.creatobj(uesi.bgindex); //創(chuàng)建新點(diǎn) newpoint.addglpoint( "70dbdb" , 0 , 0 ); newpoint.setcolor(randomset.getrandomcoldcolor()); newpoint.setcentralx(nx); //設(shè)置坐標(biāo) newpoint.setcentraly(ny); newpoint.show(); crtpoint = newpoint; //置為當(dāng)前點(diǎn) } public static void main(string[] args) { uesi ues = new r(); new sierpinski(ues, 0 ); //后面的構(gòu)造參數(shù)可以設(shè)置初始點(diǎn)數(shù)。 } } |
[模擬結(jié)果]
在b鍵按下時(shí)
[barnsleyfern的噪聲產(chǎn)生法]
相比于sierpinski三角的簡(jiǎn)單規(guī)則性,barnsleyfern(分形羊齒草)給人以更加復(fù)雜的印象,出于它的復(fù)雜性,混沌學(xué)科經(jīng)常拿出它來(lái)證明“簡(jiǎn)單規(guī)則也可產(chǎn)生復(fù)雜對(duì)象”的結(jié)論。
它的產(chǎn)生規(guī)則也不是很復(fù)雜:
1.首先給定”當(dāng)前點(diǎn)”(0,0),我們用ox,oy表示橫縱坐標(biāo)。
2.計(jì)算下一點(diǎn)(nx,ny)需要以一定隨機(jī)規(guī)則選擇下列四種迭代公式之一:
1)以%1的概率選擇此迭代公式:
nx=0;
ny=0.16f*oy;
2)以%85的概率選擇此迭代公式:
nx=0.85*ox+0.04*oy;
ny=-0.04*ox+0.85*oy+1.6;
3)以%7的概率選擇此迭代公式:
nx=0.2*ox-0.26*oy;
ny=0.23*ox+0.22*oy+1.6;
4)以%7的概率選擇此迭代公式:
nx=-0.15*ox+0.28*oy;
ny=0.26*ox+0.24*oy+0.44;
3.繪制(nx,ny),并將其設(shè)為當(dāng)前點(diǎn),重復(fù)2,即可無(wú)限逼近結(jié)果。
↑以上公式摘自wiki:http://en.wikipedia.org/wiki/barnsley_fern。在編程時(shí),我發(fā)現(xiàn)一個(gè)問(wèn)題,wiki并未指明這個(gè)坐標(biāo)的決對(duì)值與屏幕大小的關(guān)系,也并未說(shuō)明x、y軸的方向,在我自己定義的坐標(biāo)系下繪制總是不成功,后來(lái)我按照公式搜索,找到了這個(gè)面:http://people.sc.fsu.edu/~jburkardt/cpp_src/fern_opengl/fern.cpp。這是一個(gè)c++下的opengl程序,而里面用了與wiki相同的公式,也就是說(shuō),這組公式是以opengl的坐標(biāo)系為基準(zhǔn)的,在做了對(duì)應(yīng)變換后終于成功繪制。
[模擬程序]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
package com.geiv.chaos; import geivcore.defaultfactor; import geivcore.keyfactor; import geivcore.keylistener; import geivcore.r; import geivcore.uesi; import geivcore.enginedata.obj.obj; import java.awt.color; import java.awt.event.keyevent; import com.thrblock.util.randomset; public class barnsleyfern extends defaultfactor implements keylistener{ uesi ues; obj crtpoint; public barnsleyfern(uesi ues, int times){ this .ues = ues; crtpoint = ues.creatobj(uesi.bgindex); crtpoint.addglpoint( "70dbdb" , 0 , 0 ); crtpoint.show(); crtpoint.setcentralx( 0 ); crtpoint.setcentraly( 0 ); ues.setviewoffsetx( 90 ); this .setkeylistener( this ); ues.pushkeyboardio( this ); for ( int i = 0 ;i < times;i++){ generatenew(); } } @override public void dokeybord(keyfactor whom, int keycode, boolean ispressed) { //鍵盤io的方式同上例 if (ispressed){ if (keycode == keyevent.vk_space){ generatenew(); } else if (keycode == keyevent.vk_a){ for ( int i = 0 ;i < 100 ;i++){ generatenew(); } } else if (keycode == keyevent.vk_b){ for ( int i = 0 ;i < 1000 ;i++){ generatenew(); } } } } public void generatenew(){ float nx,ny; float ox = crtpoint.getcentralx()/150f,oy = ( 600 - crtpoint.getcentraly())/60f; //這里做了opengl坐標(biāo)轉(zhuǎn)換,在設(shè)置新點(diǎn)位置時(shí)對(duì)應(yīng)反轉(zhuǎn)。 double code = 100.0 * randomset.getrandomfloatin_1(); //隨機(jī)浮點(diǎn)數(shù)數(shù)0~100 if (code >= 0 &&code <= 1 ){ nx = 0 ; ny = 0 .00f * ox + 0 .16f * oy; } else if (code > 1 && code <= 86 ){ nx = 0 .85f*ox + 0 .04f*oy; ny = - 0 .04f*ox + 0 .85f*oy + 1 .6f; } else if (code > 86 && code <= 93 ){ nx = 0 .2f*ox - 0 .26f*oy; ny = 0 .23f*ox + 0 .22f*oy + 1 .6f; } else { nx = - 0 .15f*ox + 0 .28f*oy; ny = 0 .26f*ox + 0 .24f*oy + 0 .44f; } obj newpoint = ues.creatobj(uesi.bgindex); newpoint.addglpoint( "70dbdb" , 0 , 0 ); newpoint.setcolor(color.green); newpoint.setcentralx(nx*150f); //將之前的坐標(biāo)變換抵消 newpoint.setcentraly( 600 - ny*60f); newpoint.show(); crtpoint = newpoint; //設(shè)置新點(diǎn)為當(dāng)前點(diǎn)。 } public static void main(string[] args) { uesi ues = new r(); new barnsleyfern(ues, 0 ); } } |
[模擬結(jié)果]
總結(jié)
以上就是本文關(guān)于java chaos game噪聲游戲?qū)嵗a的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!
原文鏈接:http://blog.csdn.net/shuzhe66/article/details/40113149