/**惑星形成シミュレーション 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