Java Chaos Game 噪聲遊戲兩則

Java Chaos Game噪聲遊戲兩則

[簡介]

最近一直在讀《深奧的簡潔》,裏面有一章介紹了幾種使用噪聲產生分形圖的方法,感覺很有意思,於是嘗試使用計算機模擬了一下,效果還不錯(噪聲法比傳統迭代法在編程上好實現一些,後來發現這類算法還不少,搜索chaos game可以找到更多)。

本篇程序源文件及其依賴jar包已經打包,可以到這裏GitHub下載。



[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);
	}
}



[模擬結果]


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章