/*
3体問題を3次元のアニメーションで表示
2001/03/13
解軌道を尾として残しておくようにした。
アニメーションを一旦停止できるように改良。
Behavior を利用。
Copyright (C) 2000-2001 TOKUNAGA Ken-ichi
tkenichi@nucba.ac.jp
universe
Scene
light
rotator
translator
zoomer
trans
ax
ay
az
amx
amy/MyAxis1>
amz
ptr[3]
Sphere(0.05f,ap)
tail[3]
*/
import mypackage.hamilton.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.media.j3d.*;
import javax.swing.*;
import javax.vecmath.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.behaviors.mouse.*;
import com.sun.j3d.utils.picking.behaviors.*;
import com.sun.j3d.utils.picking.*;
public class ThreeBody3D extends JApplet{
SimpleUniverse universe;
BranchGroup scene;
TransformGroup trans;
TransformGroup ptr[] = new TransformGroup[3];
JButton button[] = new JButton[2];
JComboBox sampleData;
JTextField tf_weight[] = new JTextField[3];
JTextField tf_q[] = new JTextField[9];
JTextField tf_p[] = new JTextField[9];
JCheckBox ch;
TimerBehavior tb = null;
double step;
double[] m = new double[3];
ThreeBody3dHam ham;
Symplectic2nd symp;
Tail[] tail = new Tail[3]; // 尾
BoundingSphere bounds;
InitialData[] initData;
public ThreeBody3D(){
Canvas3D canvas
= new Canvas3D(SimpleUniverse.getPreferredConfiguration());
Container c = getContentPane();
c.setLayout(new BorderLayout());
c.add(canvas, BorderLayout.CENTER);
// 初期値のデータ
initData = new InitialData[]{
new InitialData("Example1", new double[]{1.8,1.9,1.7},
new double[]{0.5,0.0,0.0, -0.5,0.0,-0.5, 0.0,0.0,0.5},
new double[]{0.3,-0.8,-0.4, -0.6,0.4,0.6, 0.3,0.4,-0.2}),
new InitialData("Example2", new double[]{1.8,1.9,1.7},
new double[]{0.5,0.0,0.0, 0.0,0.5,0.0, 0.0,0.0,0.5},
new double[]{0.0,-1.0,-1.0, 1.0,0.0,0.0, -1.0,1.0,1.0}),
new InitialData("Example3", new double[]{1.9,2.0,2.1},
new double[]{0.5,0.0,0.0, 0.0,0.5,0.0, -0.5,0.0,0.0},
new double[]{0.5,-1.2,0.0, 0.0,1.2,0.6, -0.5,0.0,-0.6}),
new InitialData("Example4", new double[]{1.9,2.2,1.7},
new double[]{0.5,-0.5,0.0, 0.0,0.5,-0.5, -0.5,0.0,0.5},
new double[]{0.8,-0.3,0.0, 0.0,0.3,0.9, -0.8,0.0,-0.9}),
new InitialData("Example5", new double[]{1.8,1.6,1.7},
new double[]{0.6,0.6,0.0, -0.4,0.5,-0.6, -0.1,-0.1,0.2},
new double[]{0.3,-0.8,-0.4, -0.6,0.4,0.6, 0.3,0.4,-0.2}),
new InitialData("Example6", new double[]{1.8,1.6,1.7},
new double[]{0.6,0.0,0.0, -0.5,0.5,-0.7, -0.1,-0.2,0.2},
new double[]{0.3,-0.7,-0.5, -0.6,0.3,0.7, 0.3,0.4,-0.2}),
new InitialData("Example7", new double[]{1.8,1.9,1.7},
new double[]{0.6,0.0,0.0, -0.4,0.4,-0.6, 0.0,-0.1,0.3},
new double[]{0.3,-0.8,-0.4, -0.6,0.4,0.6, 0.3,0.4,-0.2}),
};
// UI の設定
JPanel pan = new JPanel(new GridLayout(4,8));
Color[] col = {Color.red, new Color(0,192,0), Color.blue};
pan.add(new Label("Weight"));
pan.add(new Label("x"));
pan.add(new Label("y"));
pan.add(new Label("z"));
pan.add(new Label("px"));
pan.add(new Label("py"));
pan.add(new Label("pz"));
ch = new JCheckBox("STATUS");
pan.add(ch);
for(int i=0;i<3;i++){
tf_weight[i] = new JTextField();
tf_weight[i].setForeground(col[i]);
pan.add(tf_weight[i]);
for(int j=0;j<3;j++){
tf_q[3*i+j] = new JTextField();
tf_q[3*i+j].setForeground(col[i]);
pan.add(tf_q[3*i+j]);
}
for(int j=0;j<3;j++){
tf_p[3*i+j] = new JTextField();
tf_p[3*i+j].setForeground(col[i]);
pan.add(tf_p[3*i+j]);
}
if(i<2){
button[i] = new JButton();
pan.add(button[i]);
}else{
sampleData = new JComboBox(initData);
pan.add(sampleData);
}
}
button[0].setText("START");
button[1].setText("INITIALIZE");
button[0].addActionListener(new B_start());
button[1].addActionListener(new B_initialize());
sampleData.addActionListener(new B_sample());
c.add(pan,BorderLayout.SOUTH);
universe = new SimpleUniverse(canvas);
universe.getViewingPlatform().setNominalViewingTransform();
scene = new BranchGroup();
trans = new TransformGroup();
scene.setCapability(BranchGroup.ALLOW_DETACH);
trans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
trans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
trans.setCapability(TransformGroup.ENABLE_PICK_REPORTING);
// マウス操作の設定
bounds = new BoundingSphere(new Point3d(),100.0);
MouseRotate rotator = new MouseRotate(trans);
rotator.setSchedulingBounds(bounds);
scene.addChild(rotator);
MouseTranslate translator = new MouseTranslate(trans);
translator.setSchedulingBounds(bounds);
scene.addChild(translator);
MouseZoom zoomer = new MouseZoom(trans);
zoomer.setSchedulingBounds(bounds);
scene.addChild(zoomer);
// 軸の設定
MyAxis1 ax = new MyAxis1(10.0f,0.0f,0.0f,0.1f,0,
new Color3f(1.0f,0.0f,1.0f));
MyAxis1 ay = new MyAxis1(0.0f,10.0f,0.0f,0.1f,0,
new Color3f(0.0f,1.0f,1.0f));
MyAxis1 az = new MyAxis1(0.0f,0.0f,10.0f,0.1f,0,
new Color3f(1.0f,1.0f,0.0f));
MyAxis1 amx = new MyAxis1(-10.0f,0.0f,0.0f,0.1f,1,
new Color3f(1.0f,0.0f,1.0f));
MyAxis1 amy = new MyAxis1(0.0f,-10.0f,0.0f,0.1f,1,
new Color3f(0.0f,1.0f,1.0f));
MyAxis1 amz = new MyAxis1(0.0f,0.0f,-10.0f,0.1f,1,
new Color3f(1.0f,1.0f,0.0f));
trans.addChild(ax);
trans.addChild(ay);
trans.addChild(az);
trans.addChild(amx);
trans.addChild(amy);
trans.addChild(amz);
// 照明の設定
DirectionalLight light =
new DirectionalLight( new Color3f(1.0f, 1.0f, 1.0f),
new Vector3f(-0.5f, -0.5f, -0.7f) );
light.setInfluencingBounds(bounds);
scene.addChild(light);
// 球を動かすための TransformGroup
for(int i=0;i<3;i++){
ptr[i] = new TransformGroup();
ptr[i].setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
ptr[i].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
ptr[i].setCapability(TransformGroup.ENABLE_PICK_REPORTING);
}
// 球の設定
Material mat[] = new Material[3];
mat[0] = new Material();
mat[0].setDiffuseColor( new Color3f(0.8f, 0.0f, 0.0f) );
mat[1] = new Material();
mat[1].setDiffuseColor( new Color3f(0.0f, 0.8f, 0.0f) );
mat[2] = new Material();
mat[2].setDiffuseColor( new Color3f(0.0f, 0.0f, 0.8f) );
Appearance ap[] = new Appearance[3];
ap[0] = new Appearance();
ap[0].setMaterial(mat[0]);
ap[1] = new Appearance();
ap[1].setMaterial(mat[1]);
ap[2] = new Appearance();
ap[2].setMaterial(mat[2]);
ptr[0].addChild(new Sphere(0.03f,ap[0]));
ptr[1].addChild(new Sphere(0.03f,ap[1]));
ptr[2].addChild(new Sphere(0.03f,ap[2]));
tail[0] = new Tail(500);
tail[1] = new Tail(500);
tail[2] = new Tail(500);
tail[0].setColor(new Color3f(0.8f,0.0f,0.0f));
tail[1].setColor(new Color3f(0.0f,0.8f,0.0f));
tail[2].setColor(new Color3f(0.0f,0.0f,0.8f));
// 粒子と尾を描画
trans.addChild(ptr[0]);
trans.addChild(ptr[1]);
trans.addChild(ptr[2]);
trans.addChild(tail[0]);
trans.addChild(tail[1]);
trans.addChild(tail[2]);
// 初期条件設定
getStatus();
// 表示
Background bg = new Background(new Color3f(0.8f,0.8f,0.8f));
bg.setApplicationBounds(bounds);
scene.addChild(tb);
scene.addChild(bg);
scene.addChild(trans);
universe.addBranchGraph(scene);
}
// 状態を表示。
public void showStatus(){
if(ham != null){
for(int i=0;i<3;i++){
tf_weight[i].setText(Double.toString(ham.m[i]));
}
}
if(symp != null){
for(int i=0;i<9;i++){
tf_q[i].setText(Double.toString(symp.getQValue(i)));
tf_p[i].setText(Double.toString(symp.getPValue(i)));
}
}
}
// 状態を取得 ham と symp を新しくする。
// 粒子の位置と尾も初期化する。
// 描画はしない。
// 粒子と尾を scene から外した状態で実行すること。
public void getStatus(){
try{
ham = new ThreeBody3dHam(
Double.valueOf(tf_weight[0].getText()).doubleValue(),
Double.valueOf(tf_weight[1].getText()).doubleValue(),
Double.valueOf(tf_weight[2].getText()).doubleValue());
for(int i=0;i<9;i++){
ham.setPosition(i,
Double.valueOf(tf_q[i].getText()).doubleValue());
ham.setMomentum(i,
Double.valueOf(tf_p[i].getText()).doubleValue());
}
}catch(NumberFormatException exc){
ham = new ThreeBody3dHam(initData[0]);
}
symp = new Symplectic2nd(ham,0.01);
showStatus();
// 粒子の初期状態を設定
Transform3D t3d = new Transform3D();
t3d.setTranslation(new Vector3d
(symp.getQValue(0),
symp.getQValue(1),
symp.getQValue(2)));
ptr[0].setTransform(t3d);
t3d.setTranslation(new Vector3d
(symp.getQValue(3),
symp.getQValue(4),
symp.getQValue(5)));
ptr[1].setTransform(t3d);
t3d.setTranslation(new Vector3d
(symp.getQValue(6),
symp.getQValue(7),
symp.getQValue(8)));
ptr[2].setTransform(t3d);
// 尾のデータを作る
// 初期データは全て同じ
for(int i=0;i<3;i++){
tail[i].reset(symp.getQValue(0+3*i),
symp.getQValue(1+3*i),
symp.getQValue(2+3*i));
}
}
class B_start implements ActionListener{
public void actionPerformed(ActionEvent evt){
if(tb != null){
tb.setEnable(false);
universe.getLocale().removeBranchGraph(scene);
for(int i=0;i