| Upper Directory |
////////////////////////////////////////////////////////// /* Bezier Surface, Copyright 2001-2010 Ryoichi Mizuno */ /* ryoichi[at]mizuno.org */ /* Dept. of Complexity Science and Engineering */ /* at The University of Tokyo */ ////////////////////////////////////////////////////////// |
import java.awt.*; import java.applet.*; import java.awt.event.*; public class mandelbrotSet extends Applet implements Runnable { // マンデルブロー集合 // Z(n+1) = Z(n) * Z + C // Z(0) = a + b * i // C = p + q * i Thread th = null; Image mainImg, bufImg, infoImg; Graphics mainGraph, bufGraph, infoGraph; float a = 0.0f; // ジュリア実部 float b = 0.0f; // ジュリア虚部 float p, q; // マンデルブロ実部, 虚部 int iteration = 200; // 反復回数 float threshold = 4.0f; // 発散閾値 limit range = new limit(); // 計算範囲 limit rangePrev = new limit(); // 前回の計算範囲 int sX0, sX1, sY0, sY1, sBuf; // 選択領域 int w, h; // ウィンドウサイズ int margin = 50; // 余白 int mX, mY; // マウスポインタの位置 boolean goFlag = true, dragFlag = false; // フラグ boolean colorTblFlag = true; // フラグ boolean undoFlag = false; // フラグ Button redraw, undo, db, hf, colorMethod; // GUI ボタン Button reset; // GUI ボタン Button apply, initParam; // GUI ボタン TextField juliaRe, juliaIm; // GUI テキストフィールド TextField thresholdTF, iterationTF; // GUI テキストフィールド Label juliaReLab, juliaImLab; // GUI ラベル Label thresholdLab, iterationLab; // GUI ラベル int gap = 10; // GUI 間の距離 Applet applet = this; // 初期化 public void init() { // ウィンドウサイズの取得 w = getSize().width; h = getSize().height; // メインフレームの設定 mainImg = createImage(w, h); mainGraph = mainImg.getGraphics(); // バッファフレームの設定 bufImg = createImage(w, h); bufGraph = bufImg.getGraphics(); // インフォメーションフレームの設定 infoImg = createImage(100, 10); infoGraph = infoImg.getGraphics(); // 計算範囲の初期化 initRange(); // 前回の計算範囲の初期化 initRangePrev(); // GUIの設定 setGUI(); // マウスモーションの設定 setMouseMotion(); // 背景色の設定 setBackground(Color.white); } // 計算範囲の初期化 public void initRange() { range.min.x = -2.0f; range.max.x = 1.0f; range.min.y = -1.5f; range.max.y = 1.5f; } // 前回の計算範囲の初期化 public void initRangePrev() { rangePrev.min.x = -2.0f; rangePrev.max.x = 1.0f; rangePrev.min.y = -1.5f; rangePrev.max.y = 1.5f; } // GUIの設定 public void setGUI() { // レイアウトの設定 setLayout(null); // ボタンの作成 add(redraw = new Button("Redraw")); add(undo = new Button("Undo")); add(db = new Button("X2")); add(hf = new Button("/2")); add(colorMethod = new Button("Hue Coloration")); add(reset = new Button("Reset")); // ボタンの配置 redraw.setBounds(margin * 2 + 50 * 0 + gap * 0, h - margin * 2 + 25, 50, 20); undo.setBounds(margin * 2 + 50 * 1 + gap * 2, h - margin * 2 + 25, 50, 20); db.setBounds(margin * 2 + 50 * 2 + 25 * 0 + gap * 4, h - margin * 2 + 25, 25, 20); hf.setBounds(margin * 2 + 50 * 2 + 25 * 1 + gap * 5, h - margin * 2 + 25, 25, 20); colorMethod.setBounds(margin * 2 + 50 * 2 + 25 * 2 + gap * 7, h - margin * 2 + 25, 100, 20); reset.setBounds(w - margin * 2 - 50, h - margin * 2 + 25, 50, 20); // undo ボタンの無効化 setEnableDisableUndoButton(); // colorMethod ボタンのラベルの設定 setColorMethodLabel(); // アクションリスナーの設定 redraw.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){actRedraw();}}); undo.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){actUndo();}}); db.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){actDb();}}); hf.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){actHf();}}); colorMethod.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){actColorMethod();}}); reset.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){actReset();}}); // テキストフィールドなどの作成 add(juliaRe = new TextField(java.lang.Float.toString(a), 50)); add(juliaReLab = new Label("Julia Re:")); add(juliaIm = new TextField(java.lang.Float.toString(b), 50)); add(juliaImLab = new Label("Julia Im:")); add(thresholdTF = new TextField(java.lang.Float.toString(threshold), 50)); add(thresholdLab = new Label("Threshold:")); add(iterationTF = new TextField(java.lang.Integer.toString(iteration), 50)); add(iterationLab = new Label("Iteration:")); add(apply = new Button("Apply")); add(initParam = new Button("Initialize")); // テキストフィールドなどの配置 juliaRe.setBounds(margin * 2 + 50 * 0 + gap * 0, h - margin * 2 + 70, 50, 20); juliaReLab.setBounds(margin * 2 + 50 * 0 + gap * 0, h - margin * 2 + 50, 50, 20); juliaIm.setBounds(margin * 2 + 50 * 1 + gap * 1, h - margin * 2 + 70, 50, 20); juliaImLab.setBounds(margin * 2 + 50 * 1 + gap * 1, h - margin * 2 + 50, 50, 20); thresholdTF.setBounds(margin * 2 + 50 * 2 + gap * 3, h - margin * 2 + 70, 50, 20); thresholdLab.setBounds(margin * 2 + 50 * 2 + gap * 3, h - margin * 2 + 50, 60, 20); iterationTF.setBounds(margin * 2 + 50 * 3 + gap * 5, h - margin * 2 + 70, 50, 20); iterationLab.setBounds(margin * 2 + 50 * 3 + gap * 5, h - margin * 2 + 50, 50, 20); apply.setBounds(w - margin * 2 - 50 - 60 - gap * 2, h - margin * 2 + 70, 50, 20); initParam.setBounds(w - margin * 2 - 60, h - margin * 2 + 70, 60, 20); // アクションリスナーの設定 apply.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){actApply();}}); initParam.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){actInitParam();}}); } // redraw の実行 public void actRedraw() { goFlag = true; repaint(); } // undo の実行 public void actUndo() { if(undoFlag) { undoFlag = false; setEnableDisableUndoButton(); restoreRange(); initRangePrev(); actRedraw(); } } coordinate rangeWidht = new coordinate(); // db の実行 public void actDb() { bcackupRange(); undoFlag = true; setEnableDisableUndoButton(); rangeWidht.x = (range.max.x - range.min.x) / 4.0f; rangeWidht.y = (range.max.y - range.min.y) / 4.0f; range.min.x += rangeWidht.x; range.max.x -= rangeWidht.x; range.min.y += rangeWidht.y; range.max.y -= rangeWidht.y; actRedraw(); } // hf の実行 public void actHf() { bcackupRange(); undoFlag = true; setEnableDisableUndoButton(); rangeWidht.x = (range.max.x - range.min.x) / 2.0f; rangeWidht.y = (range.max.y - range.min.y) / 2.0f; range.min.x -= rangeWidht.x; range.max.x += rangeWidht.x; range.min.y -= rangeWidht.y; range.max.y += rangeWidht.y; actRedraw(); } // colorMethod の実行 public void actColorMethod() { if(colorTblFlag) colorTblFlag = false; else colorTblFlag = true; setColorMethodLabel(); actRedraw(); } // apply の実行 public void actApply() { a = Float.valueOf(juliaRe.getText()).floatValue(); b = Float.valueOf(juliaIm.getText()).floatValue(); threshold = Float.valueOf(thresholdTF.getText()).floatValue(); iteration = Integer.valueOf(iterationTF.getText()).intValue(); actRedraw(); } // initParam の実行 public void actInitParam() { a = 0.0f; b = 0.0f; threshold = 4.0f; iteration = 200; juliaRe.setText(java.lang.Float.toString(a)); juliaIm.setText(java.lang.Float.toString(b)); thresholdTF.setText(java.lang.Float.toString(threshold)); iterationTF.setText(java.lang.Integer.toString(iteration)); actRedraw(); } // 計算範囲のバックアップ public void bcackupRange() { rangePrev.min.x = range.min.x; rangePrev.max.x = range.max.x; rangePrev.min.y = range.min.y; rangePrev.max.y = range.max.y; } // 計算範囲のレストア public void restoreRange() { range.min.x = rangePrev.min.x; range.max.x = rangePrev.max.x; range.min.y = rangePrev.min.y; range.max.y = rangePrev.max.y; } // reset の実行 public void actReset() { // フラグの初期化 goFlag = true; dragFlag = false; colorTblFlag = true; undoFlag = false; // 計算範囲の初期化 initRange(); // 前回の計算範囲の初期化 initRangePrev(); // undo ボタンの無効化 setEnableDisableUndoButton(); // colorMethod ボタンのラベルの設定 setColorMethodLabel(); actRedraw(); } // ボタンの有効化・無効化 public void setEnableDisableButton() { if(goFlag) { redraw.setEnabled(false); undo.setEnabled(false); db.setEnabled(false); hf.setEnabled(false); colorMethod.setEnabled(false); reset.setEnabled(false); apply.setEnabled(false); initParam.setEnabled(false); } else { redraw.setEnabled(true); setEnableDisableUndoButton(); db.setEnabled(true); hf.setEnabled(true); colorMethod.setEnabled(true); reset.setEnabled(true); apply.setEnabled(true); initParam.setEnabled(true); } } // undo ボタンの有効化・無効化 public void setEnableDisableUndoButton() { if(undoFlag) undo.setEnabled(true); else undo.setEnabled(false); } // colorMethod ボタンのラベルの設定 public void setColorMethodLabel() { if(colorTblFlag) colorMethod.setLabel("Hue Coloration"); else colorMethod.setLabel("Color Table"); } // マウスモーションの設定 public void setMouseMotion() { addMouseMotionListener ( new MouseMotionAdapter() { // マウスムーブ public void mouseMoved(MouseEvent e) { // マウスポインタの位置の取得 mX = e.getX(); mY = e.getY(); // グラフに入っている場合 if(mX > margin && mX < margin + (w - margin * 2) && mY > margin && mY < margin + (h - margin * 3)) { // マウスポインタの形状を変える setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); // 座標の表示 initInfo(); infoGraph.setColor(Color.black); infoGraph.drawString("C = " + java.lang.Float.toString(getWdX(mX)).substring(0,5) + " + " + java.lang.Float.toString(getWdY(mY)).substring(0,5) + "i", 0, 10); repaint(); } // グラフに入っていない場合 else { // マウスポインタの形状をデフォルトに戻す setCursor(Cursor.getDefaultCursor()); // 座標の表示(無効化) initInfo(); infoGraph.setColor(Color.black); infoGraph.drawString("C = 0.000 + 0.000i", 0, 10); repaint(); } } // マウスドラッグ public void mouseDragged(MouseEvent e) { // マウスポインタの位置の取得 mX = e.getX(); mY = e.getY(); // フラグを立てる dragFlag = true; // bufImg に mainImg を挿入 bufGraph.drawImage(mainImg, 0, 0, applet); // 矩形領域を強制的にグラフ内におさめる if(mX < margin) mX = margin; else if(mX > margin + (w - margin * 2)) mX = margin + (w - margin * 2); if(mY < margin) mY = margin; else if(mY > margin + (h - margin * 3)) mY = margin + (h - margin * 3); // 矩形領域を描画 bufGraph.setColor(Color.black); bufGraph.drawLine(mX, mY, mX, sY0); bufGraph.drawLine(mX, mY, sX0, mY); bufGraph.drawLine(sX0, sY0, sX0, mY); bufGraph.drawLine(sX0, sY0, mX, sY0); // 座標の表示 initInfo(); infoGraph.setColor(Color.black); infoGraph.drawString("C = " + java.lang.Float.toString(getWdX(mX)).substring(0,5) + " + " + java.lang.Float.toString(getWdY(mY)).substring(0,5) + "i", 0, 10); repaint(); } } ); addMouseListener ( new MouseAdapter() { // マウスプレス public void mousePressed(MouseEvent e) { // マウスポインタの位置の取得 mX = e.getX(); mY = e.getY(); // グラフに入っている場合 if(mX > margin && mX < margin + (w - margin * 2) && mY > margin && mY < margin + (h - margin * 3)) { // マウスポインタの位置を選択領域の始点に代入 sX0 = mX; sY0 = mY; // mainImg に bufImg を格納 mainGraph.drawImage(bufImg, 0, 0, applet); } } // マウスリリース public void mouseReleased(MouseEvent e) { // マウスポインタの位置の取得 mX = e.getX(); mY = e.getY(); if(dragFlag) { // フラグを折る dragFlag = false; // 選択領域を強制的にグラフ内におさめる if(mX < margin) mX = margin; else if(mX > margin + (w - margin * 2)) mX = margin + (w - margin * 2); if(mY < margin) mY = margin; else if(mY > margin + (h - margin * 3)) mY = margin + (h - margin * 3); // マウスポインタの位置を選択領域の終点に代入 sX1 = mX; sY1 = mY; // 選択領域の調整 if(sX0>sX1){sBuf = sX0; sX0 = sX1; sX1 = sBuf;} if(sY0<sY1){sBuf = sY1; sY1 = sY0; sY0 = sBuf;} // 計算範囲のバックアップ bcackupRange(); // フラグを立てる undoFlag = true; // undo ボタンの有効化 setEnableDisableUndoButton(); // 計算領域の取得 range.min.x = getWdX(sX0); range.max.x = getWdX(sX1); range.min.y = getWdY(sY0); range.max.y = getWdY(sY1); // フラグを立てる goFlag = true; // 再計算 repaint(); } } } ); } // スタート public void start() { th = new Thread(this); th.start(); } // ストップ public void stop(){goFlag = false;} // ラン public void run() { while(goFlag) { repaint(); try{Thread.sleep(10);} catch(InterruptedException e){} } } // アップデート public void update(Graphics g) { if(goFlag) { // ボタンの有効化・無効化 setEnableDisableButton(); // バッファフレームの初期化 initBuf(); // インフォメーションフレームの初期化 initInfo(); infoGraph.setColor(Color.black); infoGraph.drawString("C = 0.000 + 0.000i", 0, 10); // マンデルブロ集合の描画 drawMandlbrotSet(g); // スレッド停止 goFlag = false; // ボタンの有効化・無効化 setEnableDisableButton(); } else if(dragFlag){paint(g);} // 座標の表示 g.drawImage(infoImg, margin + (w - margin *2) - 100, 30, this); } // 描画 public void paint(Graphics g) { // 表示 if(bufImg != null) g.drawImage(bufImg, 0, 0, this); } // バッファフレームの初期化 public void initBuf() { bufGraph.setColor(Color.white); bufGraph.fillRect(0, 0, w, h); bufGraph.setColor(Color.black); bufGraph.drawRect(0, 0, w - 1, h - 1); bufGraph.setColor(Color.white); bufGraph.fillRect(margin, margin, w - margin * 2, h - margin * 3); } // インフォメーションフレームの初期化 public void initInfo() { infoGraph.setColor(Color.white); infoGraph.fillRect(0, 0, 100, 10); } // グリッドの描画 public void drawGrid() { bufGraph.setColor(Color.black); bufGraph.drawRect(margin, margin, w - margin * 2, h - margin * 3); // タイトルの描画 bufGraph.drawString("Mandelbrot Set", 25, 20); // 軸の説明の描画 bufGraph.drawString("[Re]", margin + (w - margin * 2) + 5, margin + (h - margin * 3) + 20); bufGraph.drawString("[Im]", margin - 35, margin - 5); // 最小値・最大値の描画 String strRangeMinX = java.lang.Float.toString(range.min.x) + "00000"; String strRangeMaxX = java.lang.Float.toString(range.max.x) + "00000"; String strRangeMinY = java.lang.Float.toString(range.min.y) + "00000"; String strRangeMaxY = java.lang.Float.toString(range.max.y) + "00000"; bufGraph.drawString(strRangeMinX.substring(0, 5), margin, margin + (h - margin * 3) + 15); bufGraph.drawString(strRangeMaxX.substring(0, 5), margin + (w - margin *2) - 25, margin + (h - margin * 3) + 15); bufGraph.drawString(strRangeMinY.substring(0, 5), 15, margin + (h - margin * 3)); bufGraph.drawString(strRangeMaxY.substring(0, 5), 15, margin + 10); } // 軸の描画 public void drawAxis() { int scOriginX, scOriginY; // 原点のスクリーン座標を求める scOriginX = getScX(0.0f); scOriginY = getScY(0.0f); //bufGraph.drawString(scOriginX + ", " + scOriginY, 10, 30); // 原点のy座標が描画領域に入っていればx軸を描画 if(scOriginY > margin && scOriginY < (h - margin * 2) ) { bufGraph.setColor(Color.black); bufGraph.drawLine(margin, scOriginY, w - margin, scOriginY); } // 原点のx標が描画領域に入っていればy軸を描画 if(scOriginX > margin && scOriginX < (h - margin) ) { bufGraph.setColor(Color.black); bufGraph.drawLine(scOriginX, margin, scOriginX, h - margin * 2); } } Color color[] = {Color.blue.brighter(), Color.blue, Color.cyan, Color.green.brighter(), Color.green, Color.yellow.brighter(), Color.yellow, Color.orange.brighter(), Color.orange, Color.pink, Color.pink.darker(), Color.magenta, Color.red.brighter(), Color.red}; int colorLength = color.length; // マンデルブロ集合の描画 public void drawMandlbrotSet(Graphics g) { int idxX, idxY, t; float a1, b1, a2, b2, p, q; Color cHSB, cRGBA; for (idxX = margin; idxX < w - margin; idxX++) { // グリッドの描画 drawGrid(); // pの取得 p = getWdX(idxX); for (idxY = margin; idxY < h - margin * 2; idxY++) { // qの取得 q = getWdY(idxY); a1 = a; b1 = b; for (t = 0; t < iteration; t++) { a2 = a1 * a1 - b1 * b1 + p; b2 = 2.0f * a1 * b1 + q; if (a2 * a2 + b2 * b2 > threshold) { if(colorTblFlag) { // カラーテーブルを使った描画 bufGraph.setColor(color[t % colorLength]); bufGraph.fillOval(idxX, idxY, 1, 1); } else { // 色相を使った描画 cHSB = Color.getHSBColor((float)t / (float) iteration, 1.0f, 1.0f); bufGraph.setColor(cHSB); bufGraph.fillOval(idxX, idxY, 1, 1); } break; } a1 = a2; b1 = b2; } } // 軸の描画 drawAxis(); // 描画 paint(g); } } // ワールド座標をスクリーン座標に変換(x) public int getScX(float inWdX) { float outScX; outScX = (inWdX - range.min.x) / (range.max.x - range.min.x) * (float)(w - margin * 2); outScX += margin; return (int)outScX; } // ワールド座標をスクリーン座標に変換(y) public int getScY(float inWdY) { float outScY; outScY = -(inWdY - range.min.y) / (range.max.y - range.min.y) * (float)(h - margin * 3); outScY += (float)(h - margin * 2); return (int)outScY; } // スクリーン座標をワールド座標に変換(x) public float getWdX(int inScX) { float outWdX; outWdX = (float)(inScX - margin) * (range.max.x - range.min.x) / (float)(w - margin * 2); outWdX += range.min.x; return outWdX; } // スクリーン座標をワールド座標に変換(y) public float getWdY(int inScY) { float outWdY; outWdY = -(float)(inScY - (h - margin * 2)) * (range.max.y - range.min.y) / (float)(h - margin * 3); outWdY += range.min.y; return outWdY; } } class coordinate { public float x; public float y; } class limit { coordinate min = new coordinate(); coordinate max = new coordinate(); } |