[簡介]
最近一直在讀《深奧的簡潔》,里面有一章介紹了幾種使用噪聲產生分形圖的方法,感覺很有意思,于是嘗試使用計算機模擬了一下,效果還不錯(噪聲法比傳統迭代法在編程上好實現一些,后來發現這類算法還不少,搜索chaosgame可以找到更多)。
[Sierpinski三角形的噪聲產生法]
在這些噪聲游戲中,Sierpinski(謝爾賓斯基)三角形的生成規則可謂是最簡單的:
1.在平面上選取三個點,標記為1、2、3,作為大三角形的頂點。
2.選擇其中一點,作為“當前點”(比如選擇1號)。
3.產生1~3的隨機數,在該數表達的頂點與“當前點”的中點繪制一個新點,并將新點作為“當前點”。
4.重復步驟3,即可逼近圖案。
*.注意隨機數最好不要使用以時間作為種子的產生方式。
[模擬程序]
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]; //創建三個基準點 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); //設置三點位置 basePoint[0].setCentralY(60); basePoint[1].setCentralX(60); basePoint[1].setCentralY(550); basePoint[2].setCentralX(740); basePoint[2].setCentralY(550); crtPoint = basePoint[0]; //將0號點作為當前點 this.setKeyListener(this); UES.pushKeyBoardIO(this); for (int i = 0;i < times;i++){ generateNew(); } } @Override public void doKeyBord(KeyFactor whom, int keyCode, Boolean ispressed) { //掛載回調 if(ispressed){ if(keyCode == KeyEvent.VK_SPACE){ //空格對應創建一個新點 generateNew(); } else if(keyCode == KeyEvent.VK_A){ //A對應創建100個新點 for (int i = 0;i < 100;i++){ generateNew(); } } else if(keyCode == KeyEvent.VK_B){ //B對應創建1000個新點 for (int i = 0;i < 1000;i++){ generateNew(); } } } } public void generateNew(){ Obj flagPoint = basePoint[RandomSet.getRandomNum(0, 2)]; //隨機選擇基準點之一 float nx = (flagPoint.getCentralX() + crtPoint.getCentralX())/2f; //計算中點 float ny = (flagPoint.getCentralY() + crtPoint.getCentralY())/2f; Obj newPoint = UES.creatObj(UESI.BGIndex); //創建新點 newPoint.addGLPoint("70DBDB",0,0); newPoint.setColor(RandomSet.getRandomColdColor()); newPoint.setCentralX(nx); //設置坐標 newPoint.setCentralY(ny); newPoint.show(); crtPoint = newPoint; //置為當前點 } public static void main(String[] args) { UESI ues = new R(); new Sierpinski(ues,0); //后面的構造參數可以設置初始點數。 }}
[模擬結果]
在B鍵按下時
[Barnsleyfern的噪聲產生法]
相比于Sierpinski三角的簡單規則性,Barnsleyfern(分形羊齒草)給人以更加復雜的印象,出于它的復雜性,混沌學科經常拿出它來證明“簡單規則也可產生復雜對象”的結論。
它的產生規則也不是很復雜:
1.首先給定”當前點”(0,0),我們用ox,oy表示橫縱坐標。
2.計算下一點(nx,ny)需要以一定隨機規則選擇下列四種迭代公式之一:
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),并將其設為當前點,重復2,即可無限逼近結果。
↑以上公式摘自Wiki:http://en.wikipedia.org/wiki/Barnsley_fern。在編程時,我發現一個問題,Wiki并未指明這個坐標的決對值與屏幕大小的關系,也并未說明x、y軸的方向,在我自己定義的坐標系下繪制總是不成功,后來我按照公式搜索,找到了這個面:http://people.sc.fsu.edu/~jburkardt/cpp_src/fern_opengl/fern.cpp。這是一個C++下的OPENGL程序,而里面用了與Wiki相同的公式,也就是說,這組公式是以Opengl的坐標系為基準的,在做了對應變換后終于成功繪制。
[模擬程序]
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坐標轉換,在設置新點位置時對應反轉。 double code = 100.0 * RandomSet.getRandomFloatIn_1(); //隨機浮點數數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); //將之前的坐標變換抵消 newPoint.setCentralY(600 - ny*60f); newPoint.show(); crtPoint = newPoint; //設置新點為當前點。 } public static void main(String[] args) { UESI ues = new R(); new Barnsleyfern(ues,0); }}
[模擬結果]
總結
以上就是本文關于Java Chaos Game噪聲游戲實例代碼的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站其他相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
新聞熱點
疑難解答
圖片精選