各「コマ」を JPEG ファイルとして出力するようにした NewHeat1Dv4.java である。 これはファイル入出力をするため、アプレットでなく、 アプリケーションにしてある。
それら JPEG ファイルを TMPEGEnc で MPEG ファイルに変換することに成功した。 作成した MPEG ファイルを http://nalab.mind.meiji.ac.jp/~mk/labo/java/NewHeat1Dv4.mpgにおいておく。
MPEG 作成の要点は
1 /*
2 * NewHeat1Dv4.java --- 1次元熱方程式
3 * コンパイルはもちろん javac NewHeat1Dv4.java
4 * 実行は java NewHeat1Dv4
5 * スレッド周辺はまだ不完全というか良く分かっていない。
6 * TMPEGEnc で MPEG ファイルを作るためにイメージのサイズを 8 の倍数にした。
7 * 実際に MPEG ファイルを作ることに成功した。
8 * 映像ソースとして最初の JPEG ファイルを指定し、
9 * ストリームの種類 System(Videoのみ), 設定でフレーム・レートを 7.992fps (つまり標準÷3)
10 * そして圧縮開始するだけである。
11 *
12 * 今後の改良計画
13 * (1) 境界条件色々に対応
14 * http://nalab.mind.meiji.ac.jp/~mk/labo/text/head-fdm-1.pdf 参照
15 * (2) スレッドをきちんと理解してきちんと書く
16 * (3) 2次元化する
17 */
18 package jp.tuyano.eclipsebook3;
19
20 import java.awt.Button;
21 import java.awt.Color;
22 import java.awt.Frame;
23 import java.awt.Graphics;
24 import java.awt.Label;
25 import java.awt.TextField;
26 import java.awt.event.ActionEvent;
27 import java.awt.event.ActionListener;
28 import java.awt.event.WindowAdapter;
29 import java.awt.event.WindowEvent;
30 import java.awt.image.BufferedImage;
31 import java.io.File;
32 import javax.imageio.ImageIO;
33
34
35 public class NewHeat1Dv4 extends Frame implements Runnable,ActionListener {
36
37 private static final long serialVersionUID = 1L;
38 /**
39 *
40 */
41 static final int ImgX = 496, ImgY = 496;
42 static final int WinX = ImgX + 200, WinY = ImgY;
43 Thread th = null;
44 BufferedImage im = null;
45 Graphics bg = null;
46 int i, n = -1, nMax;
47 int N;
48 double lambda, Tmax, dt, theta;
49 double h, tau;
50 int skip;
51 double [] x, u, newu;
52 double ratiox, ratioy, X0, Y0;
53 private boolean result = false;
54 private int jpeg_file_number = 0;
55 // GUI
56 private String[] labelStr={"N", "lamba", "Tmax", "dt", "theta"};
57 private Label[] label;
58 private String[] txStr={"100", "0.5", "1.0", "0.01", "0.5"};
59 private TextField[] tf;
60 private String[] btStr = {"Start", "End"};
61 private Button[] bt;
62 // テキスト・フィールドに入力されたパラメーターを読む
63 private void readParameters() {
64 N = Integer.parseInt(tf[0].getText());
65 lambda = Double.valueOf(tf[1].getText()).doubleValue();
66 Tmax = Double.valueOf(tf[2].getText()).doubleValue();
67 dt = Double.valueOf(tf[3].getText()).doubleValue();
68 theta = Double.valueOf(tf[4].getText()).doubleValue();
69 }
70 public NewHeat1Dv4() {
71 this.setSize(WinX, WinY);
72 this.addWindowListener(new WindowAdapter() {
73 public void windowClosing(WindowEvent ev) {
74 System.exit(0);
75 }
76 });
77 setLayout(null);
78 bt = new Button[btStr.length];
79 for (int i = 0; i < bt.length; i++) {
80 bt[i] = new Button(btStr[i]);
81 bt[i].addActionListener(this);
82 bt[i].setBounds(ImgX, (i+2)*20, (WinX - ImgX)/2, 20);
83 add(bt[i]);
84 }
85 label = new Label[labelStr.length];
86 tf = new TextField[txStr.length];
87 for (int i = 0; i < labelStr.length; i++) {
88 label[i] = new Label(labelStr[i]);
89 tf[i] = new TextField(txStr[i]);
90 label[i].setBounds(ImgX, (i+bt.length+2)*20, (WinX - ImgX) / 3, 20);
91 tf[i].setBounds(ImgX + (WinX-ImgX)/3, (i+bt.length+2)*20, (WinX-ImgX)/2, 20);
92 add(label[i]);
93 add(tf[i]);
94 }
95 this.setVisible(true);
96 bt[0].setEnabled(false);
97 // ダブル・バッファリング用のバッファーを準備
98 if (im == null) {
99 im = new BufferedImage(ImgX, ImgY, BufferedImage.TYPE_3BYTE_BGR);
100 bg = im.getGraphics();
101 }
102 space(-0.1, -0.1, 1.1, 1.1);
103 // 計算開始の準備
104 initcomputation();
105 // 計算スレッドを開始する
106 this.start();
107 }
108 public void start() {
109 if (th == null) {
110 th = new Thread(this);
111 th.start();
112 }
113 }
114 public void stop() {
115 if (th != null) {
116 th = null;
117 }
118 }
119 public static void main(String[] args) {
120 new NewHeat1Dv4();
121 }
122 // 座標変換の仕組み
123 private void space(double x0, double y0, double x1, double y1) {
124 X0 = x0; Y0 = y0;
125 ratiox = ImgX / (x1 - x0);
126 ratioy = ImgY / (y1 - y0);
127 }
128 // x座標をユーザー座標からウィンドウ座標に
129 private int wx(double x) {
130 return (int)Math.rint(ratiox * (x - X0));
131 }
132 // y座標をユーザー座標からウィンドウ座標に
133 private int wy(double y) {
134 return ImgY - (int)Math.rint(ratioy * (y - Y0));
135 }
136 // 初期データ
137 private double f(double x) {
138 if (x <= 0.5)
139 return x;
140 else
141 return 1.0 - x;
142 }
143 // 現在の u[] をグラフ化する
144 private void drawGraph() {
145 for (int i = 0; i < N; i++)
146 bg.drawLine(wx(x[i]), wy(u[i]), wx(x[i+1]), wy(u[i+1]));
147 }
148 // ダブルバッファリングの定跡
149 public void paint(Graphics g) {
150 g.drawImage(im, 0, 0, this);
151 }
152 // 計算の準備 (パラメーターを読み、変数の準備)
153 private void initcomputation() {
154 // パラメーターを読む
155 readParameters();
156 // 刻み幅を決める
157 h = 1.0 / N;
158 tau = lambda * h * h;
159 //
160 skip = (int)Math.rint(dt / tau);
161 if (skip <= 0) skip = 1;
162 nMax = (int)Math.ceil(Tmax / tau);
163 // ベクトルを3本用意する
164 x = new double [N+1];
165 u = new double [N+1];
166 newu = new double [N+1];
167 //
168 n = -1;
169 }
170 // 現在のバッファー im の内容を JPEG 形式で書き出す
171 void saveJpeg() {
172 String str;
173 if (jpeg_file_number < 10)
174 str = "0000" + jpeg_file_number;
175 else if (jpeg_file_number < 100)
176 str = "000" + jpeg_file_number;
177 else if (jpeg_file_number < 1000)
178 str = "00" + jpeg_file_number;
179 else if (jpeg_file_number < 10000)
180 str = "0" + jpeg_file_number;
181 else
182 str = "" + jpeg_file_number;
183 try {
184 result = ImageIO.write(im, "jpeg", new File("test" + str + ".jpg"));
185 jpeg_file_number++;
186 }
187 catch (Exception e) {
188 e.printStackTrace();
189 result = false;
190 }
191 }
192 // 計算スレッド
193 public void run() {
194 while (th != null) {
195 if (n == -1) {
196 // 初期値を計算する
197 for (int i = 0; i <= N; i++)
198 x[i] = i * h;
199 for (i = 0; i <= N; i++)
200 u[i] = f(i * h);
201 n++;
202 repaint();
203 bg.setColor(Color.white);
204 bg.fillRect(0, 0, ImgX, ImgY);
205 bg.setColor(Color.black);
206 drawGraph();
207 saveJpeg();
208 repaint();
209 try {
210 Thread.sleep(10);
211 } catch (Exception ex) {
212 ex.printStackTrace();
213 }
214 }
215 else if (n < nMax) {
216 do {
217 for (i = 1; i < N; i++)
218 newu[i] = (1 - 2 * lambda) * u[i] + lambda * (u[i + 1] + u[i - 1]);
219 for (i = 1; i < N; i++)
220 u[i] = newu[i];
221 u[0] = 0.0;
222 u[N] = 0.0;
223 n++;
224 } while (n % skip != 0);
225 drawGraph();
226 saveJpeg();
227 repaint();
228 try {
229 Thread.sleep(10);
230 } catch (Exception ex) {
231 ex.printStackTrace();
232 }
233 // System.out.println(""+ n * tau);
234 }
235 }
236 }
237 public void actionPerformed(ActionEvent e) {
238 // TODO 自動生成されたメソッド・スタブ
239 if (e.getSource() == bt[0]) {
240 bt[0].setEnabled(false);
241 bt[1].requestFocus();
242 bt[1].setEnabled(true);
243 initcomputation();
244 start();
245 }
246 if (e.getSource() == bt[1]) {
247 bt[0].setEnabled(true);
248 bt[0].requestFocus();
249 bt[1].setEnabled(false);
250 stop();
251 }
252 }
253 }