次の 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 }