各「コマ」を 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 }