next up previous contents
Next: A..5 考えていること Up: A..4 2006年1月の再挑戦 Previous: A..4 2006年1月の再挑戦

A..4.1 NewHeat1Dv4.java

各「コマ」を JPEG ファイルとして出力するようにした NewHeat1Dv4.java である。 これはファイル入出力をするため、アプレットでなく、 アプリケーションにしてある。

それら JPEG ファイルを TMPEGEnc で MPEG ファイルに変換することに成功した。 作成した MPEG ファイルを http://nalab.mind.meiji.ac.jp/~mk/labo/java/NewHeat1Dv4.mpgにおいておく。

MPEG 作成の要点は

(1)
イメージのサイズは縦横ともに 8 の倍数にする。
(2)
JPEGファイルの名前は「連番」とする。固定した名前+連続した非負整数とし、 番号は飛びがないようにしておく。
(3)
TMPEGEnc で「ストリームの種類」は ``System (Videoのみ)'', 「設定」の「フレームレート」で標準より少しフレーム・レートを落とす。 「映像ソース(V)」として、最初の JPEG ファイル名を指定する。 「出力ファイル名」は好きなようにつけて、[圧縮開始] ボタンを押す。


   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 }


next up previous contents
Next: A..5 考えていること Up: A..4 2006年1月の再挑戦 Previous: A..4 2006年1月の再挑戦
Masashi Katsurada
平成20年2月28日