/**惑星形成シミュレーション ver 0.5
* ワン・クラス・高速タイプ+作用反作用&エネルギー正規化+2面バッファ
* &パラメータ設定可
*/
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Graphics2D; // rotation
import java.awt.Color;
import java.util.Random;
import java.util.StringTokenizer;
import java.awt.Image;
import java.awt.image.BufferedImage; // double buffering
//
public class PlanetarySystem5 extends Applet implements Runnable{
//汎用定数
public double AU = 149597870000.0; //天文単位
//Appletに関するフィールド
public static boolean test=true;
public static final int APPLET_WIDTH =300;//アプレットウィンドウ幅
public static final int APPLET_HEIGHT=300;//アプレットウィンドウ高さ
public static final int APPLET_DEPTH =300;//アプレットウィンドウ仮想奥行き
public static final Color BG_COLOR = Color.black; //初期背景色
public static final Color CLEAR_COLOR= Color.white; //消去色
public static final Color FILL_COLOR = Color.red; //描画色
public Graphics2D appGraph; //アプレット画像インスタンス
public BufferedImage memImg; // 2面画像バッファ
public Graphics2D memGraph; // 2面画像バッファの描画対象
public Thread thread;//スレッド
public boolean clearGraphicsFlag;//画面消去用フラグ
//再生制御に関するフィールド
public boolean running=false; //シミュレーション開始フラグ
public int stepRunning=0; //ステップ再生スタック
public int stepRunningValue; //ステップ再生時のステップ数
public double dt;//微少時間
public long time;//累積時間
//系全体に関するフィールド
public double G; //万有引力定数
public int minorbodies; //メンバ小天体数
public boolean energyNormalizationSwitch;//エネルギー正規化スイッチ
public int edgeMode; //端処理モード
public int conflictionMode; //天体同士衝突モード
public int randomSeedMode; //乱数シードモード
public double reflectionCV; //垂直反射係数
public double reflectionCH; //水平反射係数
public Random random; //乱数クラス
public long randomSeed; //乱数シード値
public double msum; //質量合計
public double rsum; //半径合計
public double distributionSize;//天体初期分布範囲
public double mmin;//天体最小質量
public double mmax;//天体最大質量
public double pmin;//天体最小運動量
public double pmax;//天体最大運動量
public double rmin;//天体最小半径
public double rmax;//天体最大半径
//天体データ配列
public double[] x; //x座標
public double[] y; //y座標
public double[] z; //z座標
public double[] px;//運動量x成分
public double[] py;//運動量y成分
public double[] pz;//運動量z成分
public double[] m; //質量
public double[] r; //半径
public double[] xx;//2DApplet消去用x座標
public double[] yy;//2DApplet消去用y座標
public double[] zz;//2DApplet消去用z座標
public boolean[] isConflicted;//衝突フラグ
//ウィンドウ変数
public double scale;//表示される領域の幅(=高さ=奥行き)
public double scale0;//表示最小座標
public double scale1;//表示最大座標
public int radiusMode;//描画半径モード
public int radiusMax;//描画半径最大
public boolean perspectiveSwitch;//遠近法スイッチ
//Applet初期化
public void init(){
appGraph = (Graphics2D)this.getGraphics();//画像クラス取得
// double buffering
memImg = new BufferedImage((int)APPLET_WIDTH,
(int)APPLET_HEIGHT,
BufferedImage.TYPE_INT_BGR);
memGraph = memImg.createGraphics();
}
//Applet描画---------------------------------------------
//天体描画メソッド
public void drawMinorbodies(int i,Color color){
if((x[i]>=scale0)&&(x[i]<=scale1)&&(y[i]>=scale0)&&(y[i]<=scale1)&&(z[i]>=scale0)&&(z[i]<=scale1)){//表示領域内なら
double x_,y_,r_;
x_=x[i]/scale*APPLET_WIDTH;//x
y_=y[i]/scale*APPLET_HEIGHT;//y
r_=radiusMax;//z
if(radiusMode==0){r_ = r_ * r[i]/rsum;}//半径に比例
if(radiusMode==1){r_ = r_ * m[i]/msum;}//質量に比例
if(perspectiveSwitch){//遠近法ONなら
r_ = r_ * (z[i]/scale+0.5);
}
if(r_<3){r_=3;}
memGraph.setColor(color);
memGraph.fillOval((int)(x_-r_/2.0)+APPLET_WIDTH/2,(int)(y_-r_/2)+APPLET_HEIGHT/2,(int)r_,(int)r_);//消去
}
}
//1ステップ前天体描画メソッド
public void drawPreviousMinorbodies(int i,Color color){
if((xx[i]>=scale0)&&(xx[i]<=scale1)&&(yy[i]>=scale0)&&(yy[i]<=scale1)&&(zz[i]>=scale0)&&(zz[i]<=scale1)){//表示領域内なら
double x_,y_,r_;
x_=xx[i]/scale*APPLET_WIDTH;//x
y_=yy[i]/scale*APPLET_HEIGHT;//y
r_=radiusMax;//z
if(radiusMode==0){r_ = r_ * r[i]/rsum;}//半径に比例
if(radiusMode==1){r_ = r_ * m[i]/msum;}//質量に比例
if(perspectiveSwitch){//遠近法ONなら
r_ = r_ * (zz[i]/scale+0.5);
}
if(r_<3){r_=3;}
memGraph.setColor(color);
memGraph.fillOval((int)(x_-r_/2.0)+APPLET_WIDTH/2,(int)(y_-r_/2)+APPLET_HEIGHT/2,(int)r_,(int)r_);//消去
}
}
//再描画
public void paint(Graphics g){/*nop*/}
//任意描画
public void paintDirectly(){
//天体描画
memGraph.setColor(CLEAR_COLOR);
memGraph.fillRect(0,0,APPLET_WIDTH,APPLET_HEIGHT);
for(int i=0;iscale1){x[a]=scale1;px[a]=-Math.abs(px[a])*reflectionCV; py[a]=px[a] * reflectionCH; pz[a]= pz[a] * reflectionCH;}
if(y[a]>scale1){y[a]=scale1;py[a]=-Math.abs(py[a])*reflectionCV; pz[a]=px[a] * reflectionCH; px[a]= px[a] * reflectionCH;}
if(z[a]>scale1){z[a]=scale1;pz[a]=-Math.abs(pz[a])*reflectionCV; px[a]=px[a] * reflectionCH; py[a]= py[a] * reflectionCH;}
if(x[b]scale1){x[b]=scale1;px[b]=-Math.abs(px[b])*reflectionCV; py[b]=py[a] * reflectionCH; pz[b]= pz[b] * reflectionCH;}
if(y[b]>scale1){y[b]=scale1;py[b]=-Math.abs(py[b])*reflectionCV; pz[b]=pz[a] * reflectionCH; px[b]= px[b] * reflectionCH;}
if(z[b]>scale1){z[b]=scale1;pz[b]=-Math.abs(pz[b])*reflectionCV; px[b]=px[a] * reflectionCH; py[b]= py[b] * reflectionCH;}
}else if(edgeMode==1){
if(x[a]scale1 && px[a]>0){x[a]=scale0;}
if(y[a]>scale1 && py[a]>0){y[a]=scale0;}
if(z[a]>scale1 && pz[a]>0){z[a]=scale0;}
if(x[b]scale1 && px[b]>0){x[b]=scale0;}
if(y[b]>scale1 && py[b]>0){y[b]=scale0;}
if(z[b]>scale1 && pz[b]>0){z[b]=scale0;}
}
//エネルギー再計算
if(energyNormalizationSwitch){
l2 = (x[b]-x[a])*(x[b]-x[a]) + (y[b]-y[a])*(y[b]-y[a]) + (z[b]-z[a])*(z[b]-z[a]);
Er = Math.abs(getEnergy(a,b,l2)/E0);
//正規化
px[a]=px[a]/Math.sqrt(Er*0.5);
py[a]=py[a]/Math.sqrt(Er*0.5);
pz[a]=pz[a]/Math.sqrt(Er*0.5);
px[b]=px[b]/Math.sqrt(Er*0.5);
py[b]=py[b]/Math.sqrt(Er*0.5);
pz[b]=pz[b]/Math.sqrt(Er*0.5);
}
return false;
}
//エネルギー計算メソッド
public double getEnergy(int a,int b,double l2){
return (px[a]*px[a] + py[a]*py[a] + pz[a]*pz[a])/(2*m[a])//運動エネルギー
+(px[b]*px[b] + py[b]*py[b] + pz[b]*pz[b])/(2*m[b])//運動エネルギー
-G*m[a]*m[b]/Math.sqrt(l2); //万有引力ポテンシャル
}
//計算-----------------------------------------------
public void calc(){
//運動量変化・衝突計算
for(int i=0;i0){
paintDirectly();//描画
calc(); //計算
time+=dt; //時間累積
stepRunning--;
}
}
}
public void start(){
if(thread == null){
thread = new Thread(this);
thread.start();
}
}
//シミュレーション制御-------------------
public void startSim(){
clearGraphicsFlag=true;
running = true;
}
public void stopSim(){
running = false;
}
public void StepSim(String s){
clearGraphicsFlag=true;
stepRunning = stepRunningValue;
}
//javascriptからパラメータ読み込み---------------------
public void recieveParameters(String s){
StringTokenizer st=new StringTokenizer(s,":");
st.nextToken();
stepRunningValue = Integer.parseInt(st.nextToken());
dt = precode(st.nextToken());
scale = precode(st.nextToken())*AU;
radiusMax = Integer.parseInt(st.nextToken());
perspectiveSwitch = st.nextToken().equals("1");
radiusMode = Integer.parseInt(st.nextToken());
edgeMode = Integer.parseInt(st.nextToken());
reflectionCV = precode(st.nextToken());
reflectionCH = precode(st.nextToken());
randomSeedMode = Integer.parseInt(st.nextToken());
G = precode(st.nextToken());
randomSeed = Long.parseLong(st.nextToken());
conflictionMode = Integer.parseInt(st.nextToken());
energyNormalizationSwitch = st.nextToken().equals("1");
minorbodies = Integer.parseInt(st.nextToken());
distributionSize = precode(st.nextToken()) * AU;
mmin = precode(st.nextToken());
mmax = precode(st.nextToken());
rmin = precode(st.nextToken());
rmax = precode(st.nextToken());
pmin = precode(st.nextToken());
pmax = precode(st.nextToken());
scale0= -scale/2.0;
scale1= +scale/2.0;
initialize();
}
//小天体関連配列設定&乱数使用
public void initialize(){
time=0;
if(randomSeedMode==0){
randomSeed=System.currentTimeMillis();
}
random = new Random(randomSeed);
x=new double[minorbodies];
y=new double[minorbodies];
z=new double[minorbodies];
px=new double[minorbodies];
py=new double[minorbodies];
pz=new double[minorbodies];
m=new double[minorbodies];
r=new double[minorbodies];
xx=new double[minorbodies];
yy=new double[minorbodies];
zz=new double[minorbodies];
isConflicted=new boolean[minorbodies];
rsum=0.0;
msum=0.0;
for(int i=0;i