次の Heat1d_e_5.java (実行は http://nalab.mind.meiji.ac.jp/~mk/labo/java/sample/Heat1d_e_5.html) は Canvas を使うように書き直したプログラムである。
1 /* 2 * Heat1d_e_5.java -- Canvas を利用したバージョン 3 * 1998年11月20日 4 * 5 * コンパイル: javac Heat1d_e_5.java 6 * 実行: appletviewer Heat1d_e_5.java 7 * 8 * <APPLET code="Heat1d_e_5.class" width=500 height=500></APPLET> 9 * 10 * 注意 11 * 何と言っても古いので JDK1.1 以降では警告される。 12 * (1) reshape() よりも setBounds() を使えと言われる (置き換えれば OK)。 13 * (2) action() もよせ、と言われる。 14 */ 15 16 import java.applet.*; 17 import java.awt.*; 18 19 public class Heat1d_e_5 extends Applet { 20 21 private int N = 20; 22 private double lambda = 0.5; 23 private double Tmax = 0.5; 24 // ユーザーとのインターフェイス (パラメーターの入力) 25 private Label labelLambda, labelN, labelTmax; 26 private TextField inputLambda, inputN, inputTmax; 27 private Button startB; 28 // 差分法による熱方程式シミュレーション 29 private HeatCanvas c1; 30 31 // 準備 (変数の用意と座標系の初期化など) 32 public void init() { 33 // 34 setLayout(null); 35 // λ=(τ/h^2) を入力するためのテキスト・フィールド 36 labelLambda = new Label("lambda (should be <= 1/2)"); 37 add(labelLambda); 38 labelLambda.reshape(100, 10, 200, 30); 39 inputLambda = new TextField("" + lambda); 40 add(inputLambda); 41 inputLambda.reshape(300, 10, 100, 30); 42 // N (区間の分割数) を入力するためのテキスト・フィールド 43 labelN = new Label("N"); 44 add(labelN); 45 labelN.reshape(100, 45, 200, 30); 46 inputN = new TextField("" + N); 47 add(inputN); 48 inputN.reshape(300, 45, 100, 30); 49 // Tmax (計算時間) を入力するためのテキスト・フィールド 50 labelTmax = new Label("Tmax"); 51 add(labelTmax); 52 labelTmax.reshape(100, 80, 200, 30); 53 inputTmax = new TextField("" + Tmax); 54 add(inputTmax); 55 inputTmax.reshape(300, 80, 100, 30); 56 // 再計算ボタン 57 startB = new Button("Restart"); 58 add(startB); 59 startB.reshape(420, 60, 50, 30); 60 // 紙芝居「熱方程式」キャンバス 61 c1 = new HeatCanvas(); 62 add(c1); 63 c1.reshape(50, 100, 400, 400); 64 c1.compute(lambda, N, Tmax); 65 } 66 67 // ボタンを押されたら、テキスト・フィールドの内容を読み取って、再描画 68 public boolean action(Event evt, Object what) { 69 if (evt.target == startB) { 70 String str1 = inputLambda.getText(); 71 String str2 = inputN.getText(); 72 String str3 = inputTmax.getText(); 73 lambda = Double.valueOf(str1).doubleValue(); 74 N = Integer.parseInt(str2); 75 Tmax = Double.valueOf(str3).doubleValue(); 76 c1.compute(lambda, N, Tmax); 77 } 78 return true; 79 } 80 81 } 82 83 // HeatCanvas.java 84 // 1998年11月20日 85 86 class HeatCanvas extends Canvas { 87 88 static final boolean DEBUG = false; // true; 89 private static final boolean Debug = false; 90 private static final String message = "1D Heat Equation"; 91 // 問題に取って基本的なパラメーター 92 // N: 区間の分割数 93 // Tmax: 最終時刻 94 // lambda: λ=τ/h^2 95 private int N; 96 private double Tmax, lambda; 97 // 座標系の変換のためのパラメーター 98 private int CanvasX = 400, CanvasY = 400; 99 private double ratiox, ratioy, X0, Y0; 100 // 101 private HeatCanvas c1; 102 103 // コンストラクター 104 public HeatCanvas() { 105 super(); 106 space(-0.1, -0.1, 1.1, 1.1); 107 } 108 public HeatCanvas(int cx, int cy) { 109 super(); 110 CanvasX = cx; CanvasY = cy; 111 space(-0.1, -0.1, 1.1, 1.1); 112 } 113 114 public void compute(double lambda, int N, double Tmax) { 115 this.lambda = lambda; 116 this.N = N; 117 this.Tmax = Tmax; 118 repaint(); 119 } 120 121 // 初期条件 122 private double f(double x) { 123 if (x <= 0.5) 124 return x; 125 else 126 return 1.0 - x; 127 } 128 // 座標変換の準備 129 private void space(double x0, double y0, double x1, double y1) { 130 X0 = x0; Y0 = y0; 131 ratiox = CanvasX / (x1 - x0); 132 ratioy = CanvasY / (y1 - y0); 133 } 134 // ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系) 135 private int wx(double x) { 136 return (int)(ratiox * (x - X0)); 137 } 138 // ユーザー座標 (ワールド座標系) をウィンドウ座標 (デバイス座標系) 139 private int wy(double y) { 140 return CanvasY - (int)(ratioy * (y - Y0)); 141 } 142 // x[], y[] の内容をグラフにする 143 private void drawGaph(Graphics g, double x[], double u[]) { 144 for (int i= 0; i < N; i++) 145 g.drawLine(wx(x[i]), wy(u[i]), wx(x[i + 1]), wy(u[i + 1])); 146 } 147 148 public void paint(Graphics g) { 149 150 double h = 1.0 / N; 151 double tau = lambda * h * h; 152 double dt = 0.01; 153 int Jmax = (int) (Tmax / tau); 154 int skip = (int) (dt / tau + 0.5); 155 double [] u, unext, x; 156 157 // ベクトルを確保する 158 x = new double[N+1]; 159 u = new double[N+1]; 160 unext = new double[N+1]; 161 for (int i = 0; i <= N; i++) 162 x[i] = i * h; 163 164 if (Debug) { 165 // これはあんまり意味がない。 166 g.setColor(Color.pink); 167 g.fillOval(10, 10, 330, 60); 168 g.setColor(Color.red); 169 for (int i=0; i<4;i++) 170 g.drawOval(10-i, 10-i, 330+2*i, 60+2*i); 171 172 // タイトルを表示する 173 g.setColor(Color.black); 174 g.setFont(new Font("Helvetica", Font.BOLD, 24)); 175 g.drawString(message, 40, 50); 176 } 177 178 // 初期値を計算する 179 for (int i = 0; i <= N; i++) 180 u[i] = f(i * h); 181 182 // 初期値のグラフを描く 183 drawGaph(g, x, u); 184 185 // 時間に関するループ 186 for (int j = 1; j <= Jmax; j++) { 187 int i; 188 for (i = 1; i < N; i++) 189 unext[i] = (1 - 2 * lambda) * u[i] 190 + lambda * (u[i-1] + u[i+1]); 191 for (i = 1; i < N; i++) 192 u[i] = unext[i]; 193 u[0] = 0; u[N] = 0; 194 195 if (DEBUG) 196 for (i = 0; i <= N; i++) 197 System.out.println("u[" + i + "]=" + u[i]); 198 // 適当な間隔 (dt=0.01) でグラフを描く 199 if (j % skip == 0) 200 drawGaph(g, x, u); 201 } 202 } 203 }