/* 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