畑政義写像
畑政義写像 HATA map
@see http://aquioux.net/blog/?p=232
@author YOSHIDA, Akio (Aquioux)
/**
* Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/a2ii
*/
package {
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
[SWF(width = "465", height = "465", frameRate = "10", backgroundColor = "#000000")]
/**
* 畑政義写像 HATA map
* @see http://aquioux.net/blog/?p=232
* @author YOSHIDA, Akio (Aquioux)
*/
public class Main extends Sprite {
private var model_:HataMap; // 畑政義写像エンジン
private var viewer_:Viewer; // ビューア
/**
* コンストラクタ
*/
public function Main() {
setup();
addEventListener(Event.ENTER_FRAME, update);
}
// 初期化
private function setup():void {
var sw:Number = stage.stageWidth;
var sh:Number = stage.stageHeight;
// 写像クラス(Model)
model_ = new HataMap();
model_.setup(sw, sh);
// ビューア
viewer_ = new Viewer();
viewer_.setup(sw, sh);
addChild(viewer_);
// スライダー
var sliders:PSliders = new PSliders();
sliders.setup(model_, viewer_);
addChild(sliders);
// ボタン
var buttons:PButtons = new PButtons();
buttons.setup(sliders);
buttons.y = stage.stageHeight - buttons.height;
addChild(buttons);
model_.update();
}
// ループ
private function update(e:Event):void {
viewer_.update(model_.data);
}
}
}
//package {
/**
* 畑政義写像エンジン
* @author YOSHIDA, Akio (Aquioux)
*/
/*public*/ class HataMap {
public function get data():Vector.<Number> { return _data; }
private var _data:Vector.<Number>; // 描画座標
public function get a():Complex { return _a; }
public function set a(value:Complex):void { _a = value; }
private var _a:Complex = new Complex(0.0, 0.0);
public function get b():Complex { return _b; }
public function set b(value:Complex):void { _b = value; }
private var _b:Complex = new Complex(1.0, 1.0);
public function get c():Complex { return _c; }
public function set c(value:Complex):void { _c = value; }
private var _c:Complex = new Complex(0.0, 0.0);
public function get d():Complex { return _d; }
public function set d(value:Complex):void { _d = value; }
private var _d:Complex = new Complex(1.0, -1.0);
private const GENERATION:int = 11; // 再帰世代
private var sw_:Number; // ステージ幅
private var sh_:Number; // ステージ高
private var maxWidth_:int; // 表示幅の最大値
private var maxHeight_:int; // 表示高の最大値
private var numOfCoordinate_:int; // プロットする座標の数(プロットする点の数 * 2)
private var minX_:Number = 0.0; // プロットする点のX座標の最小値
private var minY_:Number = 0.0; // プロットする点のX座標の最大値
private var maxX_:Number = 0.0; // プロットする点のY座標の最小値
private var maxY_:Number = 0.0; // プロットする点のY座標の最大値
private var scale_:Number = 1.0; // 表示スケール
/**
* コンストラクタ
*/
public function HataMap() {
_a.r = Math.random() * 2 - 1;
_a.i = Math.random() * 2 - 1;
_b.r = Math.random() * 2 - 1;
_b.i = Math.random() * 2 - 1;
_c.r = Math.random() * 2 - 1;
_c.i = Math.random() * 2 - 1;
_d.r = Math.random() * 2 - 1;
_d.i = Math.random() * 2 - 1;
}
/**
* 初期化
* @param sw ステージ幅
* @param sh ステージ高
*/
public function setup(sw:Number, sh:Number):void {
// ステージサイズ
this.sw_ = sw;
this.sh_ = sh;
// 描画領域
maxWidth_ = (int(sw / 100) - 0.5) * 100;
maxHeight_ = (int(sh / 100) - 0.5) * 100;
//プロットする座標の数
var len:uint = GENERATION + 1;
numOfCoordinate_ = 0;
for (var i:int = 0; i < len; i++) {
numOfCoordinate_ += Math.pow(2, i);
}
numOfCoordinate_ *= 2;
}
/**
* ループ
*/
public function update():void {
// hataMap, plot 共に使用される各変数の初期化
_data = new Vector.<Number>();
minX_ = 0.0;
minY_ = 0.0;
maxX_ = 0.0;
maxY_ = 0.0;
// 写像実行
mapping(Complex.COMPLEX_0, 0);
// 写像処理の再帰が完了してからプロット実行
plot(minX_, minY_, maxX_ - minX_, maxY_ - minY_);
}
// 写像処理
private function mapping(z1:Complex, generation:int):void {
// プロット座標として待避
_data.push(z1.r, z1.i);
// 座標の最大値と最小値を待避
if (minX_ > z1.r) minX_ = z1.r;
if (minY_ > z1.i) minY_ = z1.i;
if (maxX_ < z1.r) maxX_ = z1.r;
if (maxY_ < z1.i) maxY_ = z1.i;
// ループの終了判定
if (generation < GENERATION) {
// 再帰
var z2:Complex = new Complex(z1.r, -z1.i); // z~
var z3:Complex = new Complex(z1.r - 1, z1.i); // z - 1
var z4:Complex = new Complex(z2.r - 1, z2.i); // z~ - 1
var zF1:Complex = Complex.add(
Complex.multiply(_a, z1),
Complex.multiply(_b, z2)
);
var zF2:Complex = Complex.add(
Complex.multiply(_c, z3),
Complex.multiply(_d, z4)
);
zF2 = Complex.add(zF2, Complex.COMPLEX_1);
var next:int = generation + 1;
mapping(zF1, next); // f1(z) で再帰
mapping(zF2, next); // F2(z) で再帰
}
}
// プロット
private function plot(offsetX:Number, offsetY:Number, w:Number, h:Number):void {
scale_ = Math.min(maxWidth_ / w, maxHeight_ / h); // スケールの計算
var offsetX2:Number = (sw_ - w * scale_) / 2; // プロット開始X座標のオフセットを計算
var offsetY2:Number = (sh_ - h * scale_) / 2; // プロット開始Y座標のオフセットを計算
var len:uint = numOfCoordinate_;
for (var i:int = 0; i < len; i += 2) {
var posX:Number = _data[i] - offsetX;
var posY:Number = _data[i + 1] - offsetY;
_data[i] = posX * scale_ + offsetX2;
_data[i + 1] = posY * scale_ + offsetY2;
}
}
}
//}
//package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.filters.BitmapFilterQuality;
import flash.filters.BlurFilter;
import flash.geom.ColorTransform;
import flash.geom.Point;
import flash.geom.Rectangle;
import frocessing.color.ColorHSV;
/**
* BitmapData 書き込みおよび表示
* @author YOSHIDA, Akio (Aquioux)
*/
/*public*/ class Viewer extends Bitmap {
/*
* ColorTransform によるフェードアウトのための定義
*/
public function set fade(value:ColorTransform):void { _fade = value; }
private var _fade:ColorTransform = new ColorTransform(1, 1, 1, 0.9);
/*
* Blur filter によるフェードアウトのための定義
*/
public function set blur(value:BlurFilter):void { _blur = value; }
private var _blur:BlurFilter = new BlurFilter(4, 4, BitmapFilterQuality.LOW);
private const ZERO_POINT:Point = new Point(0, 0);
// ColorTransform, Blur 共用
private var rect:Rectangle;
// バッファ
private var bufferBmd_:BitmapData;
// 描画色調整用
private var hsv:ColorHSV;
/**
* コンストラクタ
*/
public function Viewer() {
}
/**
* 初期化
* @param sw ステージ幅
* @param sh ステージ高
*/
public function setup(sw:Number, sh:Number):void {
bufferBmd_ = new BitmapData(sw, sh, true, 0xFF000000);
bitmapData = bufferBmd_.clone();
rect = new Rectangle(0, 0, sw, sh);
hsv = new ColorHSV();
}
/**
* ループ
* @param data 描画座標データ
*/
public function update(data:Vector.<Number>):void {
// bufferBmd_ の更新
bufferBmd_.lock();
bufferBmd_.fillRect(bufferBmd_.rect, 0x00000000);
var len:uint = data.length;
hsv.h += 1;
for (var i:int = 0; i < len; i += 2) {
bufferBmd_.setPixel32(data[i], data[i + 1], hsv.value32);
}
bufferBmd_.unlock();
// bitmapData の更新
bitmapData.colorTransform(rect, _fade);
bitmapData.applyFilter(bitmapData, rect, ZERO_POINT, _blur);
bitmapData.draw(bufferBmd_);
}
}
//}
/*package {*/
import flash.display.Sprite;
/**
* スライダー集合
* @author Aquioux
*/
/*public*/ class PSliders extends Sprite {
private var pSliders:Array;
/**
* コンストラクタ
*/
public function PSliders() {
}
/**
* 初期化
* @param hatamap 写像クラス(Model)
* @param viewer ビューア
*/
public function setup(model:HataMap, viewer:Viewer):void {
var values:Array = [
["a:", model.a],
["b:", model.b],
["c:", model.c],
["d:", model.d]
];
pSliders = [];
for (var i:int = 0; i < 4; i++) {
var pSlider:PSlider = new PSlider();
pSlider.model = model;
pSlider.viewer = viewer;
pSlider.setup(values[i][0], values[i][1]);
addChild(pSlider);
pSlider.y = 15 * i;
pSliders.push(pSlider);
}
}
// ボタンから呼び出される
public function update(val:Array):void {
for (var i:int = 0; i < 4; i++) {
var pSlider:PSlider = pSliders[i];
pSlider.outerUpdate(val[i]);
}
}
}
//}
//package {
import caurina.transitions.Tweener;
import com.bit101.components.HSlider;
import com.bit101.components.Label;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.ColorTransform;
/**
* 個別スライダー
* @author YOSHIDA, Akio (Aquioux)
*/
/*public*/ class PSlider extends Sprite {
public function set model(value:HataMap):void { model_ = value; }
private var model_:HataMap; // 写像クラス(Model)への参照
public function set viewer(value:Viewer):void { viewer_ = value; }
private var viewer_:Viewer; // ビューアへの参照
private var z_:Complex; // 対象の複素数への参照
private var label0_:Label; // 変数名
private var label1_:Label; // 実数部の値
private var label2_:Label; // 虚数部の値
private var slider1_:HSlider; // 実数部を操作する
private var slider2_:HSlider; // 虚数部操作する
private const RATE:int = 10000;
/**
* コンストラクタ
*/
public function PSlider() {
}
/**
* 初期化
* @param text どの変数かを表示するためのテキスト
* @param target 対象の複素数
*/
public function setup(text:String, z:Complex):void {
z_ = z;
label0_ = new Label(this, 0, 0, text); // どの変数かを表示する
label1_ = new Label(this, 20, 0, String(z.r)); // 実数部の値を表示する
slider1_ = new HSlider(this, 70, 5, handler1); // 実数部の値を変更する
label2_ = new Label(this, 180, 0, String(z.i)); // 虚数部の値を表示する
slider2_ = new HSlider(this, 230, 5, handler2); // 虚数部の値を変更する
slider1_.setSliderParams( -RATE, RATE, z_.r * RATE);
slider2_.setSliderParams( -RATE, RATE, z_.i * RATE);
var colorTransform:ColorTransform = new ColorTransform(0, 0, 0, 1, 255, 255, 255, 0);
label0_.transform.colorTransform = colorTransform;
label1_.transform.colorTransform = colorTransform;
label2_.transform.colorTransform = colorTransform;
slider1_.alpha = 0.5;
slider2_.alpha = 0.5;
}
// 実数部に関わるハンドラ
private function handler1(e:Event):void {
var value:Number = e.target.value / RATE;
label1_.text = String(value);
z_.r = value;
innerUpdate();
}
// 虚数部に関わるハンドラ
private function handler2(e:Event):void {
var value:Number = e.target.value / RATE;
label2_.text = String(value) + " i";
z_.i = value;
innerUpdate();
}
// 内部由来の更新
private function innerUpdate():void{
model_.update();
viewer_.update(model_.data);
}
// 外部由来の更新
public function outerUpdate(z:Complex):void {
var r:Number = z.r;
var i:Number = z.i;
Tweener.addTween(z_,
{
"r":r,
"i":i,
time:2.5,
transition:"easeNone",
onUpdate:outerUpdate2
}
);
}
private function outerUpdate2():void {
var r:Number = z_.r;
var i:Number = z_.i;
label1_.text = String(r);
label2_.text = String(i) + " i";
slider1_.value = r * RATE;
slider2_.value = i * RATE;
innerUpdate();
}
}
//}
//package {
import com.bit101.components.PushButton;
import flash.display.Sprite;
import flash.events.MouseEvent;
/**
* プリセットボタン集合
* @author Aquioux
*/
/*public*/ class PButtons extends Sprite {
// スライダーへの参照
private var sliders_:PSliders;
// 各ボタンの値
private const VALUES:Array = [
["Koch", Complex.COMPLEX_0, new Complex(0.5, -0.25), Complex.COMPLEX_0, new Complex(0.5, 0.25) ],
["Levy C", Complex.COMPLEX_0, new Complex(-0.5, 0.5), Complex.COMPLEX_0, new Complex(-0.5, -0.5) ],
["Leaf", new Complex(0.7, 0.2), Complex.COMPLEX_0, Complex.COMPLEX_0, new Complex(2 / 3, 0.0) ],
["Branch", Complex.COMPLEX_0, new Complex(0.5, 0.3), Complex.COMPLEX_0, new Complex(2 / 3, 0.0) ],
["Wave", new Complex(0.55, -0.45), Complex.COMPLEX_0, new Complex(0.6, 0.2), Complex.COMPLEX_0 ],
["Cloud", new Complex(2/3, -0.5), Complex.COMPLEX_0, new Complex(-0.2, 0.5), Complex.COMPLEX_0 ],
["Shine", new Complex(1.0, -1.0), Complex.COMPLEX_0, new Complex(-1.0, -1.0), new Complex(-1.0, 1.0) ],
["Cross", new Complex(0.0, Math.SQRT1_2), Complex.COMPLEX_0, new Complex(0.5, 0.0), Complex.COMPLEX_0 ],
["Pole", new Complex(0.25, -0.25), new Complex(-0.2, -0.3), Complex.COMPLEX_0, new Complex(-0.8, 0.0) ],
["Triangle", Complex.COMPLEX_0, new Complex(0.5, -0.5), Complex.COMPLEX_0, new Complex(0.5, 0.5) ],
["Saw", Complex.COMPLEX_0, new Complex(0.0, -0.5), new Complex(0.8, 0.0), Complex.COMPLEX_0 ],
["Grid", Complex.COMPLEX_0, new Complex(0.0, 0.5), Complex.COMPLEX_0, new Complex(0.0, -0.5) ],
["Thunder", new Complex(-0.5, -0.2), Complex.COMPLEX_0, Complex.COMPLEX_0, new Complex(0.0, 2 / 3) ],
["Diamond", new Complex(0.0, 0.75), new Complex(0.25, 0.0), new Complex(0.0, 0.75), new Complex(0.25, 0.0) ],
["RadioActive", Complex.COMPLEX_0, new Complex(0.5, 1.0), Complex.COMPLEX_0, new Complex(0.5, -1.0) ],
["Frost", new Complex(0.25, 0.5), Complex.COMPLEX_0, Complex.COMPLEX_0, new Complex(0.75, 0.0) ],
["Burr", new Complex(-0.5, 0.35), new Complex(0.5, -0.45), new Complex(0.0, 0.225), new Complex(Math.SQRT1_2, -0.35) ],
["WindMill", Complex.COMPLEX_0, new Complex(-1.0, -1.0), Complex.COMPLEX_0, new Complex(-1.0, 1.0) ]
];
/**
* コンストラクタ
*/
public function PButtons() {
}
/**
* 初期化
* @param sliders スライダー集合
*/
public function setup(sliders:PSliders):void {
sliders_ = sliders;
var w:int = 52;
var h:int = 20;
var pButtons:Array = [];
for (var yCnt:int = 0; yCnt < 2; yCnt++) {
for (var xCnt:int = 0; xCnt < 9; xCnt++) {
var pButton:PButton = new PButton();
var cnt:int = yCnt * 9 + xCnt;
pButton.setup(VALUES[cnt][0], VALUES[cnt][1], VALUES[cnt][2], VALUES[cnt][3], VALUES[cnt][4]);
pButton.addEventListener(MouseEvent.CLICK, clickHandler);
pButton.width = w;
pButton.height = h;
addChild(pButton);
pButton.x = w * xCnt - 1;
pButton.y = h * yCnt;
pButtons.push(pButton);
}
}
}
// 各ボタンのイベントハンドラ
private function clickHandler(e:MouseEvent):void {
var pButton:PButton = PButton(e.target);
sliders_.update([pButton.a, pButton.b, pButton.c, pButton.d]);
}
}
//}
//package {
import com.bit101.components.PushButton;
/**
* 個別プリセットボタン
* @author YOSHIDA, Akio (Aquioux)
*/
/*public*/ class PButton extends PushButton {
public function set sliders(value:PSliders):void { sliders_ = value; }
private var sliders_:PSliders; // スライダーへの参照
public function get a():Complex { return _a; }
private var _a:Complex;
public function get b():Complex { return _b; }
private var _b:Complex;
public function get c():Complex { return _c; }
private var _c:Complex;
public function get d():Complex { return _d; }
private var _d:Complex;
/**
* コンストラクタ
*/
public function PButton() {
}
/**
* 初期化
* @param label ボタンのラベル
* @param a 複素数 a
* @param b 複素数 b
* @param c 複素数 c
* @param d 複素数 d
*/
public function setup(label:String, a:Complex, b:Complex, c:Complex, d:Complex):void {
this.label = label;
_a = a;
_b = b;
_c = c;
_d = d;
}
}
//}
//package {
/**
* 複素数クラス
* @author YOSHIDA, Akio (Aquioux)
*/
/*public*/ class Complex {
/*
* 実数部 real number
*/
public function get r():Number { return _r; }
public function set r(value:Number):void { _r = value; }
private var _r:Number;
/*
* 虚数部 imaginary number
*/
public function get i():Number { return _i; }
public function set i(value:Number):void { _i = value; }
private var _i:Number;
/*
* コンストラクタ
* @param r 実数部値
* @param i 虚数部値
*/
public function Complex(r:Number = 0.0, i:Number = 0.0) {
_r = r;
_i = i;
}
// public な定数
/*
* 実数 0
*/
public static const COMPLEX_0:Complex = new Complex(0.0, 0.0);
/*
* 実数 1
*/
public static const COMPLEX_1:Complex = new Complex(1.0, 0.0);
/*
* 純虚数 i
*/
public static const COMPLEX_i:Complex = new Complex(0.0, 1.0);
// public な関数
/*
* 2項加算(ハミルトンの定義)
*/
static public function add(z0:Complex, z1:Complex):Complex {
return new Complex(z0.r + z1.r, z0.i + z1.i);
}
/*
* 2項乗算(ハミルトンの定義)
*/
static public function multiply(z0:Complex, z1:Complex):Complex {
return new Complex((z0.r * z1.r) - (z0.i * z1.i), (z0.r * z1.i) + (z0.i * z1.r));
}
}
//}