ロジスティック写像の分岐図
/**
* Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/w6mF
*/
package {
//import aquioux.display.colorUtil.RGBWheel;
import com.bit101.components.HUISlider;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "#ffffff")]
/**
* ロジスティック写像の分岐図
* x -> a * x * (1 - x) 漸化式
* 0 <= a <= 4, 0 <= x0 <= 1
* @see http://aquioux.net/blog/?p=3848
* @author YOSHIDA, Akio
*/
public class Main extends Sprite {
// 描画サイズ
private const IMAGE_WIDTH:int = 400;
private const IMAGE_HEIGHT:int = 400;
// ロジスティック写像漸化式のループ回数
private const LOGISTIC_LOOP_LIMIT:int = 10000;
// 描画用ループカウンター
private var drawLoopCnt_:int; // 最大値は IMAGE_WIDTH
// パラメータ a
private var a_:Number; // パラメータ a
private var aShift_:Number; // 描画開始 a 値
private var aAdd_:Number; // a 増分
private const A_REPEAT_LIMIT:int = 250; // 横軸 1 ピクセルごとの a の計算回数
// 色用パラメータ
private var angle_:Number; // RGBWheel 用角度
private var angleAdd_:Number; // 角度増分
// ビューア
private var viewBmd_:BitmapData;
static private const FILL_COLOR:uint = 0x000000;
/**
* コンストラクタ
*/
public function Main():void {
// 背景を黒にする
var back:Shape = new Shape();
var g:Graphics = back.graphics;
g.beginFill(FILL_COLOR);
g.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
g.endFill();
addChild(back);
// ビューア
viewBmd_ = new BitmapData(IMAGE_WIDTH, IMAGE_HEIGHT, false, FILL_COLOR);
var bm:Bitmap = new Bitmap(viewBmd_);
bm.x = (stage.stageWidth - IMAGE_WIDTH) / 2 >> 0;
bm.y = (stage.stageHeight - IMAGE_HEIGHT) / 2 >> 0;
addChild(bm);
// スライダー
var slider:HUISlider = new HUISlider(this, 0, bm.y + bm.height + 5, "a:start point");
slider.width = stage.stageWidth -10;
slider.labelPrecision = 7;
slider.tick = Math.pow(10, -slider.labelPrecision);
slider.setSliderParams(0, 4, 3.5699456);
slider.addEventListener(MouseEvent.MOUSE_UP, function():void { start(slider.value) } );
// 初回の描画
start(slider.value);
}
// 描画開始
private function start(a:Number):void {
// イベントハンドラ削除
removeEventListener(Event.ENTER_FRAME, update);
// ビューア初期化
viewBmd_.fillRect(viewBmd_.rect, FILL_COLOR);
// a 変動用ループカウンター & 描画X軸座標
drawLoopCnt_ = 0;
// パラメータ a
a_ = a;
aAdd_ = (4 - a_) / (IMAGE_WIDTH * A_REPEAT_LIMIT);
// 色用パラメータ
angle_ = Math.random() * Math.PI * 2;
angleAdd_ = (Math.random() + 1) * Math.PI / (IMAGE_WIDTH * A_REPEAT_LIMIT);
// 描画ループ
addEventListener(Event.ENTER_FRAME, update);
}
// 描画ループ
private function update(event:Event):void {
// 描画
viewBmd_.lock();
for (var j:int = 0; j < A_REPEAT_LIMIT; j++) {
// 計算
a_ += aAdd_;
var currentX:Number = Math.random();
var i:int = LOGISTIC_LOOP_LIMIT;
while (i--) currentX = a_ * currentX * (1 - currentX);
// 描画
angle_ += angleAdd_;
viewBmd_.setPixel(drawLoopCnt_, (1 - currentX) * IMAGE_HEIGHT - 1, RGBWheel.getRadianColor(angle_));
}
viewBmd_.unlock();
// 次のループへ向けて
++drawLoopCnt_;
// 終了判定
if (drawLoopCnt_ > IMAGE_WIDTH) removeEventListener(Event.ENTER_FRAME, update);
}
}
}
//package aquioux.display.colorUtil {
/**
* コサインカーブで色相環的に RGB を計算
* @author YOSHIDA, Akio
*/
/*public*/ class RGBWheel {
/**
* 彩度(HSV の彩度 S と同じ扱い)
*/
static public function get s():Number { return _s; }
static public function set s(value:Number):void {
if (value < 0.0) value = 0.0;
if (value > 1.0) value = 1.0;
_s = value;
}
static private var _s:Number = 1.0;
/**
* 明度(HSV の明度 V と同じ扱い)
*/
static public function get v():Number { return _v; }
static public function set v(value:Number):void {
if (value < 0.0) value = 0.0;
if (value > 1.0) value = 1.0;
_v = value;
}
static private var _v:Number = 1.0;
/**
* 角度 angle に応じた RGB を得る(弧度法指定 radian)
* @param radian 角度(弧度法)
* @return 色(0xRRGGBB)
*/
static public function getRadianColor(radian:Number):uint {
var r:uint = (Math.cos(radian) + 1) * 0xff >> 1;
var g:uint = (Math.cos(radian + 2.0943951023931953) + 1) * 0xff >> 1;
var b:uint = (Math.cos(radian - 2.0943951023931953) + 1) * 0xff >> 1;
// 2.0943951023931953 = Math.PI * 2 / 3 radian(= 120 degree)
if (_s != 1.0) {
r += shiftS(r);
g += shiftS(g);
b += shiftS(b);
}
if (_v != 1.0) {
r -= shiftV(r);
g -= shiftV(g);
b -= shiftV(b);
}
return r << 16 | g << 8 | b;
}
/**
* 角度 angle に応じた RGB を得る(度数法指定 degree)
* @param degree 角度(度数法)
* @return 色(0xRRGGBB)
*/
static public function getDegreeColor(degree:Number):uint {
return getRadianColor(degree * 0.017453292519943295);
}
/**
* 彩度の反映
* @param gray 諧調(0~255)
* @return 諧調のシフト値
* @private
*/
static private function shiftS(gray:uint):uint {
return (0xff - gray) * (1 - _s) >> 0;
}
/**
* 明度の反映
* @param gray 諧調(0~255)
* @return 諧調のシフト値
* @private
*/
static private function shiftV(gray:uint):uint {
return gray * (1 - _v) >> 0;
}
}
//}