ジュリア集合 (z = z ^ D + c)
/**
* Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/iGI3
*/
// forked from Aquioux's ジュリア集合
// forked from Aquioux's マンデルブロ集合
package {
import com.bit101.components.HSlider;
import com.bit101.components.PushButton;
import com.bit101.components.VSlider;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextField;
[SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#000000")]
/**
* ジュリア集合の描画
* @author Aquioux(Yoshida, Akio)
* @see http://aquioux.net/blog/?p=1293
* initial state "r : -0.37" & "i : 0.61" & "z ^ 7 + c"
*/
public class Main extends Sprite {
private const W:int = 450;
private const H:int = 450;
private const SLIDER_LONG:int = 450;
private const SLIDER_SHORT:int = 465 - 450;
private const SLIDER_RATIO:int = 100;
private const SLIDER_VALUE_MIN:Number = -2.0;
private const SLIDER_VALUE_MAX:Number = 2.0;
private const START_REAL_NUMBER:Number = -0.37;
private const START_IMAGINARY_NUMBER:Number = 0.61;
private var colors_:Vector.<uint>;
private var bmd_:BitmapData;
private var hslider:HSlider;
private var vslider:VSlider;
private var textField1:TextField;
private var textField2:TextField;
public function Main():void {
colors_ = new Vector.<uint>();
var degree:int = 45;
var step:Number = 270 / degree;
for (var i:int = 0; i < degree; i++) colors_[i] = CycleRGB.getColor(i * step + 180);
colors_.reverse();
colors_.fixed = true;
Julia.notSetColors = colors_;
bmd_ = new BitmapData(W, H, false, 0x0);
addChild(new Bitmap(bmd_));
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
stage.addEventListener(Event.MOUSE_LEAVE, mouseLeaveHandler);
hslider = new HSlider(this, 0, H);
hslider.width = SLIDER_LONG;
hslider.height = SLIDER_SHORT;
hslider.setSliderParams(SLIDER_VALUE_MIN * SLIDER_RATIO, SLIDER_VALUE_MAX * SLIDER_RATIO, START_REAL_NUMBER * SLIDER_RATIO);
vslider = new VSlider(this, W, 0);
vslider.width = SLIDER_SHORT;
vslider.height = SLIDER_LONG;
vslider.setSliderParams(SLIDER_VALUE_MIN * SLIDER_RATIO, SLIDER_VALUE_MAX * SLIDER_RATIO, START_IMAGINARY_NUMBER * SLIDER_RATIO);
var buttonWidth:int = 75;
var button0:PushButton = new PushButton(this, 0, H - 20, "z ^ 2 + c", button0Handler);
var button1:PushButton = new PushButton(this, buttonWidth, H - 20, "z ^ 3 + c", button1Handler);
var button2:PushButton = new PushButton(this, buttonWidth * 2, H - 20, "z ^ 4 + c", button2Handler);
var button3:PushButton = new PushButton(this, buttonWidth * 3, H - 20, "z ^ 5 + c", button3Handler);
var button4:PushButton = new PushButton(this, buttonWidth * 4, H - 20, "z ^ 6 + c", button4Handler);
var button5:PushButton = new PushButton(this, buttonWidth * 5, H - 20, "z ^ 7 + c", button5Handler);
button0.width = buttonWidth;
button1.width = buttonWidth;
button2.width = buttonWidth;
button3.width = buttonWidth;
button4.width = buttonWidth;
button5.width = buttonWidth;
textField1 = new TextField();
textField2 = new TextField();
textField1.y = 0;
textField2.y = 15;
addChild(textField1);
addChild(textField2);
mouseUpHandler(null);
button5Handler(null);
}
private function mouseUpHandler(e:MouseEvent):void {
hsliderHandler();
vsliderHandler();
}
private function mouseLeaveHandler(e:Event):void {
mouseUpHandler(null);
}
private function draw():void {
bmd_.lock();
bmd_.setVector(bmd_.rect, Julia.update(W, H));
bmd_.unlock();
}
private function hsliderHandler():void {
var value:Number = hslider.value / SLIDER_RATIO;
textField1.text = "r : " + String(value);
Julia.realNumber = value;
draw();
}
private function vsliderHandler():void {
var value:Number = vslider.value / SLIDER_RATIO;
textField2.text = "i : " + String(value);
Julia.imaginalyNumber = value;
draw();
}
private function button0Handler(e:Event):void {
Julia.expo = 2;
draw();
}
private function button1Handler(e:Event):void {
Julia.expo = 3;
draw();
}
private function button2Handler(e:Event):void {
Julia.expo = 4;
draw();
}
private function button3Handler(e:Event):void {
Julia.expo = 5;
draw();
}
private function button4Handler(e:Event):void {
Julia.expo = 6;
draw();
}
private function button5Handler(e:Event):void {
Julia.expo = 7;
draw();
}
}
}
//package {
/**
* ジュリア集合描画クラス
* @author Aquioux(Yoshida, Akio)
*/
/*public*/ class Julia {
/**
* ジュリア集合に該当する部分の色
*/
public static function set setColor(value:uint):void { _setColor = value; }
private static var _setColor:uint = 0x000000;
/**
* 発散部分の色階調
*/
public static function set notSetColors(value:Vector.<uint>):void { _notSetColors = value; }
private static var _notSetColors:Vector.<uint>;
/**
* 表示位置オフセットX座標値
*/
public static function set offsetX(value:Number):void { _offsetX = value; }
private static var _offsetX:Number = 0.0;
/**
* 表示位置オフセットY座標値
*/
public static function set offsetY(value:Number):void { _offsetY = value; }
private static var _offsetY:Number = 0.0;
/**
* 漸化式の c の実数
*/
static public function set realNumber(value:Number):void { _cRl = value; }
private static var _cRl:Number = 0.0;
/**
* 漸化式の c の虚数
*/
static public function set imaginalyNumber(value:Number):void { _cIm = value; }
private static var _cIm:Number = 0.0;
/**
* ズーム値
*/
public static function set zoom(value:Number):void { _zoom = value; }
private static var _zoom:Number = 1.0;
/**
* 漸化式の z の冪乗の指数
*/
static public function set expo(value:int):void { _expo = value; }
private static var _expo:int = 2;
/**
* 複素数平面を走査
* @param width 複素数平面の幅
* @param height 複素数平面の高
* @return 複素数平面の各点ごとの発散濃度を格納した Vector
*/
public static function update(width:int, height:int):Vector.<uint> {
// 発散時の色が外部から指定されていなければ設定する
if (!_notSetColors) {
_notSetColors = new Vector.<uint>(256, true);
for (var i:int = 0; i < 256; i++) _notSetColors[i] = i << 16 | i << 8 | i;
}
// 複素数平面走査のインクリメントステップを計算する
var target:int = (width < height) ? width : height;
var step:Number = 4 / (_zoom * target);
// 複素数平面の走査開始座標を計算する
var startRl:Number = -width * step / 2 + _offsetX;
var startIm:Number = -height * step / 2 - _offsetY;
// 返り値となる Vector
var data:Vector.<uint> = new Vector.<uint>(width * height, true);
var idx:int = 0;
var degree:int = _notSetColors.length;
// 複素数平面の走査
var zIm:Number = startIm;
// Y軸方向ループ変数の初期化
var y:int = height;
while (y--) {
// 複素数実数部の初期化
var zRl:Number = startRl;
// X軸方向ループ変数の初期化
var x:int = width;
while (x--) {
// ジュリア集合に該当する色で color を初期化しておく
var color:uint = _setColor;
// 発散のチェック
var result:int = checkDivergence(zRl, zIm, _cRl, _cIm, degree);
// 発散したときは、ジュリア集合でない色に color を置き換える
if (result >= 0) color = _notSetColors[result];
data[idx++] = color;
// 複素数の実数部のインクリメント
zRl += step;
}
// 複素数の虚数部のインクリメント
zIm += step;
}
return data;
}
/**
* 漸化式 z_n1 = z_n^2 + c を最大 degree 回ループして発散するか否か調べる
* @param zRl 複素数 z の初期値実数部
* @param zIm 複素数 z の初期値虚数部
* @param cRl 複素数 c の実数部
* @param cIm 複素数 c の虚数部
* @param degree 発散チェックの最大ループ回数
* @return 発散濃度評価値
* @private
*/
private static function checkDivergence(zRl:Number, zIm:Number, cRl:Number, cIm:Number, degree:int):int {
// z_n の各要素の二乗
var zRlSqr:Number; // 実数部
var zImSqr:Number; // 虚数部
var r:Number; // 複素数の冪乗を簡単に計算するために使う局座標(距離)
var t:Number; // 複素数の冪乗を簡単に計算するために使う局座標(偏角)
var r2:Number; // 冪乗計算結果(距離)
var t2:Number; // 冪乗計算結果(偏角)
var i:int = degree;
var j:int;
while (i--) {
// 発散の評価
zRlSqr = zRl * zRl;
zImSqr = zIm * zIm;
if (zRlSqr + zImSqr > 4) break;
// 発散していなかった場合、再評価へ向けて z_n の値を更新する
// 複素数を局座標化
r = Math.sqrt(zRlSqr + zImSqr);
t = Math.atan2(zIm, zRl);
// オイラーの公式による冪乗計算
r2 = r; // 距離
j = _expo;
while (--j) r2 *= r;
t2 = t * _expo; // 偏角
zRl = Math.cos(t2) * r2 + cRl;
zIm = Math.sin(t2) * r2 + cIm;
}
return i;
}
}
//}
//package {
/**
* コサインカーブによる色循環
* @author Aquioux(Yoshida, Akio)
*/
/*public*/ class CycleRGB {
private static const DEGREE90:Number = Math.PI / 2; // 90度(弧度法形式)
private static const DEGREE180:Number = Math.PI; // 180度(弧度法形式)
public static function getColor(angle:Number):uint {
var radian:Number = angle * Math.PI / 180;
var valR:uint = (Math.cos(radian) + 1) * 0xFF >> 1;
var valG:uint = (Math.cos(radian + DEGREE90) + 1) * 0xFF >> 1;
var valB:uint = (Math.cos(radian + DEGREE180) + 1) * 0xFF >> 1;
return valR << 16 | valG << 8 | valB;
}
}
//}