//内藤さんのプログラムを改良 //変更点: ベクトル場 初期値入力 描画範囲 // import java.applet.*; import java.awt.*; import java.awt.event.*; public class Oregonator_vector1 extends Applet implements MouseListener,ActionListener { //スクリーン1 private Image img1; private Graphics gra1; //スクリーン2 private Image img2; private Graphics gra2; // Runge Kutta 法のための引数 private double h; private double [] t; private double [] x; private double [] z; //ユーザーとのインターフェイス private double q,eps,xx0,zz0,tt,tt0,cf, x_max, x_min, y_max, y_min, x_margin, y_margin; private int n; private Label la1,la2,la3,la4,la5,la6,la7,la8,la9,la10,la11,la12,la13; private TextField tf1,tf2,tf3,tf4,tf5,tf6,tf7,tf8,tf9,tf10,tf11,tf12,tf13; private Button bt1,bt2,bt3,bt4,bt5; // x-z 座標系の変換パラメーター private double ratiox,ratioy,X0,Y0; private int WX = 650, WY = 650; private boolean IsIn1(double x, double y) { return (x_min <= x && x <= x_max && y_min <= y && y <= y_max); } // x-z 座標変換の準備 private void space1(double x0, double y0, double x1, double y1) { X0 = x0; Y0 = y0; ratiox = WX / (x1 - x0); ratioy = WY / (y1 - y0); } // x-z ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系) private int wx(double x) { return (int)(ratiox * (x - X0)); } //逆写像 private double wxinv(int ix) { return ix/ratiox + X0 ; } // x-z ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系) private int wy(double y) { return WY - (int)(ratioy * (y - Y0)); } //逆写像 private double wyinv(int iy) { return (WY - iy)/ratioy + Y0 ; } // x-t,z-t 座標系の変換パラメーター private double ratioa,ratiob,A0,B0; private int WA = 350, WB =330; // x-t,z-t 描写範囲 private double b_max = 1.5; private double b_min = -0.5; private boolean IsIn2(double a, double b) { return (tt0 <= a && a <= tt && b_min <= b && b <= b_max); } // x-t,z-t 座標変換の準備 private void space2(double b0,double b1) { A0 = tt0; B0 = b0; ratioa = WA / (tt - tt0); ratiob = WB / (b1 - b0); } // x-t,z-t ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系) private int wa(double a) { return (int)(ratioa * (a - A0)); } // x-t,z-t ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系) private int wb(double b) { return WB - (int)(ratiob * (b - B0)); } //数値の読み取り private void ReadFields(){ q = Double.valueOf(tf1.getText()).doubleValue(); eps = Double.valueOf(tf2.getText()).doubleValue(); xx0 = Double.valueOf(tf3.getText()).doubleValue(); zz0 = Double.valueOf(tf4.getText()).doubleValue(); h = Double.valueOf(tf5.getText()).doubleValue(); tt = Double.valueOf(tf6.getText()).doubleValue(); cf = Double.valueOf(tf7.getText()).doubleValue(); x_min = Double.valueOf(tf10.getText()).doubleValue(); x_max = Double.valueOf(tf11.getText()).doubleValue(); y_min = Double.valueOf(tf12.getText()).doubleValue(); y_max = Double.valueOf(tf13.getText()).doubleValue(); x_margin = (x_max-x_min)/20; y_margin = (y_max-y_min)/20; n = (int)(10*(Math.abs(tt/h)+1)); } //関数の定義,ベクトル場の定義 private double f(double x, double z) { return(x*(1-x)-cf*z*(x-q)/(q+x))/eps; } private double g(double x, double z) { return(x-z); } //ベクトルの設定 //ベクトルの長さを均一にする double norm(double x, double y) { return Math.sqrt(x*x+y*y); } void arrow(double x0, double y0, double vx, double vy) { /* ベクトルを引く関数をつくる */ double angle = 15 * Math.PI / 180.0; double cos = Math.cos(angle), sin = Math.sin(angle); double Norm = norm(vx, vy); double fx = 0.04 * (x_max - x_min), fy = 0.04 * (y_max - y_min); vx /= Norm; vy /= Norm; vx *= fx; vy *= fy; double xe = x0 + vx, ye = y0 + vy; vx *= - 0.2; vy *= -0.2; double vx1= vx*cos-vy*sin; double vy1= vx*sin+vy*cos; double vx2= vx*cos+vy*sin; double vy2=-vx*sin+vy*cos; if (IsIn1(x0, y0) && IsIn1(xe, ye)) { line1(x0, y0, xe, ye); line1(xe, ye, xe+vx1, ye+vy1); line1(xe, ye, xe+vx2, ye+vy2); } } //線を引くメソッドを定義 private void line1(double x0, double y0, double x1, double y1) { gra1.drawLine(wx(x0),wy(y0),wx(x1),wy(y1)); } private void line2(double x0, double y0, double x1, double y1) { gra2.drawLine(wa(x0),wb(y0),wa(x1),wb(y1)); } //ルンゲクッタ法 private void runge() { double t,k1,k2,k3,k4,l1,l2,l3,l4; // x = new double [n+1]; z = new double [n+1]; h=(tt-tt0)/n; x[0]=xx0; z[0]=zz0; for(int j=1; j<=n; j++){ t=tt0+h*(j-1); k1=h*f(x[j-1],z[j-1]); l1=h*g(x[j-1],z[j-1]); k2=h*f(x[j-1]+k1/2.0,z[j-1]+l1/2.0); l2=h*g(x[j-1]+k1/2.0,z[j-1]+l1/2.0); k3=h*f(x[j-1]+k2/2.0,z[j-1]+l2/2.0); l3=h*g(x[j-1]+k2/2.0,z[j-1]+l2/2.0); k4=h*f(x[j-1]+k3,z[j-1]+l3); l4=h*g(x[j-1]+k3,z[j-1]+l3); x[j]=x[j-1]+(k1+2.0*k2+2.0*k3+k4)/6.0; z[j]=z[j-1]+(l1+2.0*l2+2.0*l3+l4)/6.0; } } //パラメーター表示 public void init() { setCursor(new Cursor(Cursor.HAND_CURSOR)); //tf la bt のレイアウト setLayout(null); add(la1 = new Label("qの値:")); la1.setBounds (650,10,90,20); add(la2 = new Label("εの値:")); la2.setBounds (835,10,90,20); add(la3 = new Label("初期値のx座標:")); la3.setBounds (650,30,90,20); add(la4 = new Label("初期値のz座標:")); la4.setBounds (835,30,90,20); add(la5 = new Label("時間刻み幅:")); la5.setBounds (650,50,90,20); add(la6 = new Label("t座標の上限:")); la6.setBounds (835,50,90,20); add(la7 = new Label("fの値:")); la7.setBounds (650,70,90,20); add(la8 = new Label("区間の分割数:")); la8.setBounds (835,70,90,20); add(la9 = new Label("平衡点の座標:")); la9.setBounds (650,160,80,20); add(la10 = new Label(" x の範囲")); la10.setBounds (650,185,50,20); add(la11 = new Label("〜")); la11.setBounds (750,185,20,20); add(la12 = new Label(" z の範囲")); la12.setBounds (650,205,50,20); add(la13 = new Label("〜")); la13.setBounds (750,205,20,20); //初期値などの代入 add(tf1 = new TextField("" +8E-4)); tf1.setBounds (745,10,80,20); add(tf2 = new TextField("" +1E-2)); tf2.setBounds (930,10,80,20); add(tf3 = new TextField("" +0.01)); tf3.setBounds (745,30,80,20); add(tf4 = new TextField("" +0.01)); tf4.setBounds (930,30,80,20); add(tf5 = new TextField("" +0.001)); tf5.setBounds (745,50,80,20); add(tf6 = new TextField("" +20.0)); tf6.setBounds (930,50,80,20); add(tf7 = new TextField("" +0.6)); tf7.setBounds (745,70,80,20); add(tf8 = new TextField("" +100000)); tf8.setBounds (930,70,80,20); add(tf9 = new TextField("")); tf9.setBounds (730,160,350,20); add(tf10 = new TextField("" +0.0)); tf10.setBounds (700,185,50,20); add(tf11 = new TextField("" +1.0)); tf11.setBounds (770,185,50,20); add(tf12 = new TextField("" +0.0)); tf12.setBounds (700,205,50,20); add(tf13 = new TextField("" +1.0)); tf13.setBounds (770,205,50,20); //ボタンの設定 //スクリーン 1 Startボタン add(bt1 = new Button("Start 1")); bt1.addActionListener(this); bt1.setBounds (650,100,175,20); //ベクトル場 start ボタン add(bt2 = new Button("ベクトル場表示")); bt2.addActionListener(this); bt2.setBounds (650,120,175,20); //スクリーン 1 Clear ボタン add(bt3 = new Button("Clear 1")); bt3.addActionListener(this); bt3.setBounds (650,140,175,20); //スクリーン 2 Startボタン add(bt4 = new Button("Start 2")); bt4.addActionListener(this); bt4.setBounds (825,100,175,20); //スクリーン 2 Clearボタン add(bt5 = new Button("Clear 2")); bt5.addActionListener(this); bt5.setBounds (825,120,175,20); //スクリーンの設定 //スクリーン 1 の確保 img1=createImage(WX,WY); gra1=img1.getGraphics(); gra1.setColor(new Color(230,255,230)); gra1.fillRect(0,0,WX,WY); // 座標変換 ReadFields(); space1(x_min-x_margin, y_min-y_margin, x_max+x_margin, y_max+y_margin); // ラベル gra1.setColor(Color.black); gra1.drawString("オレゴネータ(2変数版 )の解曲線",200,30); //スクリーン 2 の確保 img2=createImage(WA,WB); gra2=img2.getGraphics(); gra2.setColor(new Color(230,255,230)); gra2.fillRect(0,0,WA,WB); //ラベル gra2.setColor(Color.red); gra2.drawString("t−x",100,10); gra2.setColor(Color.orange); gra2.drawString("t−z",150,10); gra2.setColor(Color.black); gra2.drawString("のグラフ",200,10); addMouseListener(this); } public void paint(Graphics g){ update(g); } public void update(Graphics g){ g.drawImage(img1,0,0,this); g.drawImage(img2,655,320,this); } //ボタン操作 public void actionPerformed(ActionEvent e) { //ボタン 1 if(e.getSource() == bt1) { // 初期値などを取得 ReadFields(); // Runge Kutta 法で解を計算 runge(); // 解曲線を描く space1(x_min-x_margin, y_min-y_margin, x_max+x_margin, y_max+y_margin); gra1.setColor(Color.blue); for(int j=1; j<=n; j++) { if (IsIn1(x[j-1], z[j-1]) && IsIn1(x[j], z[j])) { line1( x[j-1], z[j-1], x[j], z[j]); } } gra1.setColor(Color.lightGray); for (double i=x_min; i<=x_max ; i=i+0.1){ line1( i, y_min, i, y_max); } for (double i=y_min; i<=y_max; i=i+0.1){ line1( x_min, i, x_max, i); } // ラベルを描く gra1.setColor(Color.black); line1( x_min, 0.0, x_max, 0.0); line1( 0.0, y_min, 0.0, y_max); gra1.drawString("0",wx(0.0),wy(0.0)); gra1.drawString("オレゴネータ(2変数版 )の解曲線",200,30); for(double i=0.5; i<=x_max; i=i+0.5){ gra1.drawString(""+i,wx(i),wy(0.0)); } for(double i=0.5; i<=y_max; i=i+0.5){ gra1.drawString(""+i,wx(0.0),wy(i)); } repaint(); //平衡点を計算する ReadFields(); double x_h =(1-cf-q+Math.sqrt(Math.pow(cf+q-1,2)+4*q*(1+cf)))/2; //平衡点をプロット gra1.setColor(Color.red); double h1= x_h-(x_max-x_min)/100; double h2= x_h+(x_max-x_min)/100; double h3= x_h-(x_max-x_min)/100; double h4= x_h+(x_max-x_min)/100; line1( h1, x_h, h2, x_h); line1( x_h, h3, x_h, h4); //平衡点を表示させる String he=Double.toString(x_h); tf9.setText("("+ he + "," + he +")"); } //ボタン 2 //ベクトル場表示 else if(e.getSource() == bt2){ ReadFields(); gra1.setColor(Color.green); double dx = (x_max - x_min) / 20, dy = (y_max - y_min) / 20; for(double x=x_min; x<=x_max; x += dx){ /* 矢印を書く */ for(double y=y_min; y<=y_max; y += dy){ arrow(x, y, f(x,y), g(x,y)); } } repaint(); } //ボタン 3 // 相曲線とベクトル場をクリア // ...相図をクリアしてグリッドなど描き直し else if(e.getSource() == bt3) { gra1.setColor(new Color(230,255,230)); gra1.fillRect(0,0,WX,WY); // ラベルを描く gra1.setColor(Color.black); gra1.drawString("オレゴネータ(2変数版 )の解曲線",200,30); repaint(); //初期値をはじめの値にする tf3.setText("" +0.01); tf4.setText("" +0.01); //平衡点の値を消す tf9.setText("" ); } //ボタン 4 // 解曲線 (t,x(t)), (t,z(t)) を描く else if(e.getSource() == bt4) { double TT,TT0; // 初期値などを取得 ReadFields(); space2(b_min, b_max); //座標軸 gra2.setColor(Color.black); line2( tt0, 0.0, tt, 0.0); line2( tt0, b_min, tt0, b_max); gra2.drawString( ""+tt0 ,wa(tt0),wb(0.0)); gra2.drawString( "1.0",wa(tt0),wb(1.0)); gra2.drawString("t",wa(0.9*tt),wb(0.0)); gra2.drawString(" x,z",wa(tt0),wb(1.4)); runge(); for (int j=1; j<=n; j++) { TT =tt0+h*j; TT0=tt0+h*(j-1); if (IsIn2(TT0, x[j-1]) && IsIn2(TT, x[j])) { gra2.setColor(Color.red); line2(TT0,x[j-1],TT, x[j]); x[j-1]=x[j]; TT0=TT; } if (IsIn2(TT0, z[j-1]) && IsIn2(TT, z[j])) { gra2.setColor(Color.orange); line2(TT0, z[j-1], TT, z[j]); z[j-1]=z[j]; TT0=TT; } } repaint(); } //ボタン 5 // 解曲線 (t,x(t)), (t,z(t)) 消去 else if(e.getSource() == bt5) { gra2.setColor(new Color(230,255,230)); gra2.fillRect(0,0,WA,WB); gra2.setColor(Color.red); gra2.drawString("t−x",100,10); gra2.setColor(Color.orange); gra2.drawString("t−z",150,10); gra2.setColor(Color.black); gra2.drawString("のグラフ",200,10); repaint(); } } public void mousePressed(MouseEvent e){} public void mouseReleased(MouseEvent e){} public void mouseClicked(MouseEvent e){ //マウスによる初期値入力 // if(e.getModifiers()==){ space1(x_min-x_margin,y_min-y_margin,x_max+x_margin,y_max+y_margin); int xx=e.getX(); int zz=e.getY(); double x_m=wxinv(xx); double z_m=wyinv(zz); String xx0=Double.toString(x_m); String zz0=Double.toString(z_m); tf3.setText(xx0); tf4.setText(zz0); // 初期値などを取得 ReadFields(); // Runge Kutta 法で解を計算 runge(); // 解曲線を描く gra1.setColor(new Color(0,0,200)); for(int j=1; j<=n; j++) { if (IsIn1(x[j-1], z[j-1]) && IsIn1(x[j], z[j])) { line1( x[j-1], z[j-1], x[j], z[j]); } } repaint(); } public void mouseEntered(MouseEvent e){} public void mouseExited(MouseEvent e){} }