| 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();
}
|