ジュリア集合の画像の作成プログラム
ジュリア集合の画像の作成プログラム+αの機能あり
マンデルブロ集合にBurningShipと言う派生した考えがあります。
これと同じように計算の途中で絶対値を取ったら面白い画像ができたので変更可能にしました。
標準のジュリア集合はOFF、OFFです。
個人的にはOFF,ON(初期値)が好みです
フルスクリーンでご利用ください
♥0 |
Line 454 |
Modified 2011-05-17 15:46:25 |
MIT License
archived:2017-03-20 12:12:26
ActionScript3 source code
/**
* Copyright hi.kurosawa ( http://wonderfl.net/user/hi.kurosawa )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/8Hdd
*/
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
applicationComplete="initDataSet()">
<fx:Script>
<![CDATA[
//------------------------------------------
//Julia集合の画像の作成プログラム
// URL:http://programmingatelier.net/
//------------------------------------------
import mx.controls.Alert;
import mx.core.UIComponent;
import mx.graphics.codec.PNGEncoder;
import mx.graphics.codec.JPEGEncoder;
import mx.managers.CursorManager;
import mx.events.CloseEvent;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.utils.setTimeout;
//範囲指定ラインの描画用
private var spHani1:Sprite;
private var maskForSp1:Sprite;
//マンデルブロ集合の描画エリア
private var bdHani1:BitmapData;
private var bdMandelbrot:BitmapData;
//最大繰り返し数
private var intKurikaesi:int;
//カラー
private var arrColor:Array;
private var uintHassan:uint;//発散しないときのカラー
//作画中に使用するパラメータ
private var numX0:Number;
private var numY0:Number;
private var numDD:Number;
//ダブルクリック判定用
private var bolDDclic:Boolean;
private var intBMw:int; //描画サイズ
private var intBMh:int;
private var numXMin:Number; //描画範囲の座標
private var numYMin:Number;
private var numXStep:Number; //1ドットのサイズ
private var numYStep:Number;
private var intLopp:int;
//状態(0:通常、1:本領域作成中)
private var intJyoutai:int = 0;
//ファイル保存
private var filRef:FileReference;
private var numA:Number;
private var numB:Number;
private var bolAAbs:Boolean;
private var bolBAbs:Boolean;
// 初期化処理======================================================================
private function initDataSet():void {
//範囲指定の領域指定用
spHani1 = new Sprite();
uiHni1.addChild(spHani1);
//範囲指定表示がはみ出さないようにマスクをかける
maskForSp1= new Sprite();
maskForSp1.graphics.lineStyle(0, 0, 0);
maskForSp1.graphics.beginFill(0xFF);
maskForSp1.graphics.drawRect(0,0,200,200);
maskForSp1.graphics.endFill();
uiHni1.addChild(maskForSp1);
spHani1.mask = maskForSp1;
sdNumA.value = -0.06;
sdNumB.value = 0.73;
fncHaniInit();
onDisp();
}
private function fncHaniInit():void {
//{x:-0.8831999999999999,y:1.1871999999999998,d:0.27999999999999997},
numX0 = 0.0;
numY0 = 0.0;
numDD = 1.4;
//numX0 = -0.883;
//numY0 = 1.187;
//numDD = 0.27;
numA = sdNumA.value;
numB = sdNumB.value;
bolAAbs = chbAAbs.selected;
bolBAbs = chbBAbs.selected;
fncDispHani();
}
private function fncDispHani():void {
fncSerColor();
// 既存イメージの破棄...
while (uiHni1.numChildren) uiHni1.removeChildAt(0);
bdHani1 = new BitmapData(200, 200, false, 0xffffff);
var bm:Bitmap = new Bitmap(bdHani1);
uiHni1.addChild(bm);
uiHni1.addChild(spHani1);
uiHni1.addChild(maskForSp1);
spHani1.mask = maskForSp1;
var nXMin:Number = numX0 - numDD;
var nYMin:Number = numY0 - numDD;
var nXStep:Number = numDD/100.0;
var nYStep:Number = numDD/100.0;
for (var iy:int = 0; iy < 200;iy++) {
var b:Number = nYMin + iy * nYStep;
for (var ix:int = 0; ix < 200; ix++) {
var a:Number = nXMin + ix * nXStep;
bdHani1.setPixel(ix, iy, fncGetColor(a, -b));
}
}
txaA.text = numA.toString();
txaB.text = numB.toString();
chbA.selected=bolAAbs;
chbB.selected=bolBAbs;
txaX0.text = numX0.toString();
txaY0.text = numY0.toString();
txaDD.text = numDD.toString();
}
//クリック、ダブルクリック処理
private function onHniClick():void {
bolDDclic = false;
setTimeout(fncHniClick, 300);
}
private function onHniDoClick():void {
bolDDclic = true;
}
private function fncHniClick():void {
var x0:Number = numDD*((uiHni1.mouseX-100)/100);
var y0:Number = numDD*((uiHni1.mouseY-100)/100);
numX0 += x0;
numY0 += y0;
//ダブルクリックの時は拡大
if(bolDDclic == true) {numDD = numDD/sdScale.value;}
fncDispHani();
}
private function onHniMuOut():void {
var x0:Number = uiHni1.mouseX;
var y0:Number = uiHni1.mouseY;
if( x0<0 || x0>=200 || y0<0 || y0>=200) {
spHani1.graphics.clear();
}
}
private function onHniMuMv():void {
var x0:Number = uiHni1.mouseX;
var y0:Number = uiHni1.mouseY;
var siz0:Number = 100.0/sdScale.value;
spHani1.graphics.clear();
spHani1.graphics.lineStyle(1, 0xff0000,1);
spHani1.graphics.moveTo(x0, 0);
spHani1.graphics.lineTo(x0, 200);
spHani1.graphics.moveTo(0, y0);
spHani1.graphics.lineTo(200, y0);
spHani1.graphics.drawRect(x0 - siz0, y0 - siz0, siz0*2, siz0*2);
}
private function onHaniInit():void {
fncHaniInit();
}
private function onHaniReduced():void {
numDD = numDD * sdScale.value;
if (numDD > 1.4) { numDD = 1.4; }
fncDispHani();
}
private function onDisp():void {
if (intJyoutai == 0) { //実行中でない->実行中
fncJyoutai(1);
fncImgSet();
} else if(intJyoutai == 1) { //実行中->キャンセル
this.removeEventListener(Event.ENTER_FRAME,fncMandelbroLine);
Alert.show("処理を中止してよいですか?",
"Mandelbrot", Alert.YES | Alert.NO, this, alertClickRun);
return;
}
}
private function alertClickRun(evt:CloseEvent):void {
if (evt.detail == Alert.YES) { //OK
fncJyoutai(0);
}
else { //再開
this.addEventListener(Event.ENTER_FRAME, fncMandelbroLine);
}
}
private function fncImgSet():void {
var bm:Bitmap;
fncSerColor();
intBMw = nsImgW.value;
intBMh = nsImgH.value;
var iXYmax:int = intBMw;
if (intBMw < intBMh) { iXYmax = intBMh;}
numXStep = (numDD/iXYmax)*2;
numYStep = (numDD/iXYmax)*2;
numXMin = numX0 - numXStep*intBMw/2;
numYMin = numY0 - numYStep * intBMh / 2;
intLopp = 0;
while (uiGrf.numChildren) uiGrf.removeChildAt(0);
bdMandelbrot = new BitmapData(intBMw, intBMh, false, 0xffffff);
bm = new Bitmap(bdMandelbrot);
uiGrf.addChild(bm);
uiGrf.x = 0;
uiGrf.y = 0;
uiGrf.width = bdMandelbrot.width;
uiGrf.height = bdMandelbrot.height;
grpPreview.width = bdMandelbrot.width;
grpPreview.height = bdMandelbrot.height;
this.addEventListener(Event.ENTER_FRAME, fncMandelbroLine);
}
//グラデーションカラー取得
private function fncSerColor():void {
arrColor = new Array();
//最大繰返数
intKurikaesi=256;
uintHassan = cpHassan.selectedColor;
//カラーのセット
var icol0:uint = cpG0.selectedColor;
var ir0:uint = icol0 / (256 * 256); //カラーをRGBに分解
var ig0:uint = (icol0 / (256))-ir0*256;
var ib0:uint = icol0 % 256;
var icol1:uint = cpG1.selectedColor;
var ir1:uint = icol1 / (256 * 256); //カラーをRGBに分解
var ig1:uint = (icol1 / (256))-ir1*256;
var ib1:uint = icol1 % 256;
var icoln:int = nsColN.value; //intKurikaesi;
var i:int;
var ir:uint;
var ig:uint;
var ib:uint;
for(i = 0; i < icoln; i++) { //グラデーションカラー作成
ir = ir0 + (ir1 - ir0) * i / icoln;
ig = ig0 + (ig1 - ig0) * i / icoln;
ib = ib0 + (ib1 - ib0) * i / icoln;
arrColor.push(ir * 256 * 256 + ig * 256 + ib);
}
for(i = 1; i < icoln-1; i++) { //グラデーションカラー作成
ir = ir0 + (ir1 - ir0) * (icoln-i) / icoln;
ig = ig0 + (ig1 - ig0) * (icoln-i) / icoln;
ib = ib0 + (ib1 - ib0) * (icoln-i) / icoln;
arrColor.push(ir * 256 * 256 + ig * 256 + ib);
}
}
//マンデルブロ集合1行描画処理
private function fncMandelbroLine(evt:Event):void {
var nn:int = intBMh / 10;
for (var iy:int = intLopp; iy < intBMh;iy+=nn) {
var b:Number = numYMin + iy * numYStep;
for (var ix:int = 0; ix < intBMw; ix++) {
var a:Number = numXMin + ix * numXStep;
bdMandelbrot.setPixel(ix, iy, fncGetColor(a, -b));
}
}
intLopp++;
//描画終了判定
if (intLopp >= nn) {
this.removeEventListener(Event.ENTER_FRAME,fncMandelbroLine);
fncJyoutai(0);
}
}
//マンデルブロ集合の1点でのカラー
private function fncGetColor(a:Number, b:Number):uint {
var uiCol:uint = uintHassan; //発散しないときのカラー
var x:Number=a;
var y:Number=b;
var i:int = 0;
for(i=0;i<=intKurikaesi;i++){ //最大繰り返し数繰り返し
var x2:Number=x*x;
var y2:Number=y*y;
//var zx:Number = x2 - y2 +0.4;
//var zy:Number = 2 * x * y +0.2;
//var zx:Number = x2 - y2 +0.4;
//var zy:Number = 2 * x * y +0.25;
var zx:Number = x2 - y2 +numA;
var zy:Number = 2 * x * y +numB;
x=zx;
y=zy;
if(bolAAbs==true) {x=Math.abs(zx);}
if(bolBAbs==true) {y=Math.abs(zy);}
if (x2 + y2 >= 4) {
var id:int = i % arrColor.length;
uiCol= arrColor[id];
break;
}
}
return uiCol;
}
//状態に合わせた表示
public function fncJyoutai(iJyoutai:int):void {
intJyoutai = iJyoutai;
if (iJyoutai == 0) { //通常
btnDisp.label = "本領域に描画";
vgJyouken.enabled = true;
hgMkImg.enabled = true;
vgData.enabled = true;
} else {
btnDisp.label = "描画中止";
vgJyouken.enabled = false;
hgMkImg.enabled = false;
vgData.enabled = false;
}
}
public function onHainSet():void {
var A:Number = Number(txaA.text);
var B:Number = Number(txaB.text);
var x0:Number = Number(txaX0.text);
var y0:Number = Number(txaY0.text);
var dd:Number = Number(txaDD.text);
if (isNaN(A) || isNaN(B) ||isNaN(x0) || isNaN(y0) || isNaN(dd)) {
Alert.show("数値でないデータがあります。", "Mandelbrot");
return;
}
if (dd<0) {
Alert.show("DDは0以上の値を指定してください。", "Mandelbrot");
return;
}
sdNumA.value=A;
sdNumB.value=B;
chbAAbs.selected = chbA.selected;
chbBAbs.selected = chbB.selected;
numA=A;
numB=B;
bolAAbs= chbA.selected;
bolBAbs= chbB.selected;
numX0 = x0;
numY0 = y0;
numDD = dd;
fncDispHani();
}
public function onDataSet():void {
txaData.text = "{a:" + numA.toString() + ",af:" + bolAAbs.toString() + ",b:" + numB.toString() + ",bf:" +
bolBAbs.toString()+",x:" + numX0.toString() + ",y:" + numY0.toString() +
",d:"+numDD.toString()+"},\n"+txaData.text;
}
//ローカルファイルへの保存=======================================================
private function onImgSave():void {
//描画データをセット
var bmpData:BitmapData = new BitmapData(uiGrf.width, uiGrf.height);
bmpData.draw(uiGrf);
var byteArray:ByteArray;
var strSaveName:String = "Mandelbrot";
if (cmbImgFormat.selectedItem.label == "PNG") {
byteArray = new PNGEncoder().encode(bmpData);
strSaveName += ".png";
}
else {
byteArray = new JPEGEncoder().encode(bmpData);
strSaveName += ".jpg";
}
filRef = new FileReference();
filRef.addEventListener(Event.COMPLETE, onFileSave);
filRef.addEventListener(IOErrorEvent.IO_ERROR, onFileSaveErr);
filRef.save(byteArray,strSaveName);
}
//保存完了
private function onFileSave(e:Event):void {
Alert.show("ローカルファイルへ保存しました。", "Mandelbrot");
}
//保存エラー
private function onFileSaveErr(e:IOErrorEvent):void {
Alert.show("ローカルファイルへの保存を失敗しました。\n"+e.toString(),
"Mandelbrot");
}
]]>
</fx:Script>
<s:Group height="100%" width="100%">
<s:Scroller width="100%" height="100%">
<s:VGroup gap="0">
<s:HGroup paddingLeft="5" paddingTop="2" gap="2">
<s:Label text="a"/>
<s:HSlider id="sdNumA" minimum="-1" maximum="1" stepSize="0.01" width="400"
top="10" left="0" change="fncHaniInit()" />
<s:CheckBox id="chbAAbs" label="絶対値で計算" change="fncHaniInit()"/>
</s:HGroup>
<s:HGroup paddingLeft="5" gap="2">
<s:Label text="b"/>
<s:HSlider id="sdNumB" minimum="-1" maximum="1" stepSize="0.01" width="400"
top="10" left="0" change="fncHaniInit()" />
<s:CheckBox id="chbBAbs" label="絶対値で計算" change="fncHaniInit()" selected="true" />
</s:HGroup>
<mx:HRule width="100%" /> <!-- 区切り線 -->
<s:HGroup height="100%" width="100%" gap="0">
<s:VGroup height="650" width="200" gap="5">
<s:VGroup gap="2" paddingTop="5" paddingLeft="0" id="vgJyouken">
<s:HGroup verticalAlign="middle" paddingLeft="10">
<s:Label text="発散しないときのカラー"/>
<mx:ColorPicker id="cpHassan" selectedColor="0x000000"/>
</s:HGroup>
<s:Label text="発散した時のカラー" paddingLeft="10"/>
<s:VGroup gap="0" paddingLeft="10">
<s:HGroup verticalAlign="middle">
<mx:ColorPicker id="cpG0" selectedColor="0x000088"/>
<s:Label text="~"/>
<mx:ColorPicker id="cpG1" selectedColor="0xffffff"/>
<s:NumericStepper id="nsColN" width="50"
value="32" minimum="16" maximum="256"/>
</s:HGroup>
</s:VGroup>
<mx:HRule width="100%" /> <!-- 区切り線 -->
<s:VGroup gap="0" id="vgHani1">
<s:Label text="範囲指定" paddingLeft="5"/>
<s:HGroup paddingLeft="10">
<s:Label text="倍率"/>
<s:HSlider id="sdScale" minimum="1" maximum="20" stepSize="0.1" width="150"
top="10" left="0" value="5" />
</s:HGroup>
<s:Group >
<mx:UIComponent id="uiHni1" height="200" width="200" top="5" left="0"
click="onHniClick()" mouseOut="onHniMuOut()" mouseMove="onHniMuMv()"
doubleClick="onHniDoClick()" doubleClickEnabled="true" />
</s:Group>
</s:VGroup>
<s:HGroup gap="0" paddingLeft="0">
<s:Button label="初期化" width="60" id="btnHaniInit" click="onHaniInit()" />
<s:Button label="範囲指定を倍率で縮小" width="140" id="btnHaniReduced" click="onHaniReduced()"/>
</s:HGroup>
<s:Label text="シングルクリックで中心の移動" paddingLeft="10"/>
<s:Label text="ダブルクリックで拡大" paddingLeft="10"/>
</s:VGroup>
<s:HGroup gap="0" paddingLeft="50">
<s:Button label="本領域に描画" id="btnDisp" click="onDisp();" width="150" height="30" />
</s:HGroup>
<mx:HRule width="100%" /> <!-- 区切り線 -->
<s:VGroup gap="0" paddingTop="2" paddingLeft="5" id="vgData">
<s:Label text="現在の表示位置"/>
<s:Button label="値を範囲指定に反映" click="onHainSet()" width="190" />
<s:HGroup gap="0" verticalAlign="middle">
<s:Label text="AB" width="25"/>
<s:TextArea id="txaA" height="20" width="55"/>
<s:CheckBox id="chbA"/>
<s:TextArea id="txaB" height="20" width="55"/>
<s:CheckBox id="chbB"/>
</s:HGroup>
<s:HGroup gap="0" verticalAlign="middle">
<s:Label text="XYD" width="25"/>
<s:TextArea id="txaX0" height="20" width="55"/>
<s:TextArea id="txaY0" height="20" width="55"/>
<s:TextArea id="txaDD" height="20" width="55"/>
</s:HGroup>
<s:Button label="値をデータ領域にセット" click="onDataSet()" width="190"/>
<s:TextArea id="txaData" width="190" height="130" />
</s:VGroup>
</s:VGroup>
<mx:VRule height="100%" /> <!-- 区切り線 -->
<s:VGroup width="100%" height="100%" gap="0">
<mx:HRule width="100%" /> <!-- 区切り線 -->
<!-- 描画サイズ、ローカルに保存 -->
<s:HGroup gap="0" paddingLeft="0" verticalAlign="middle" id="hgMkImg">
<s:Label text="サイズ"/>
<s:NumericStepper id="nsImgW" width="55"
value="500" minimum="100" maximum="3000"
snapInterval="1" stepSize="10" toolTip="作成イメージのサイズ・幅"
/>
<s:Label text="X"/>
<s:NumericStepper id="nsImgH" width="55"
value="500" minimum="100" maximum="3000"
snapInterval="1" stepSize="10" toolTip="作成イメージのサイズ・高さ" />
<s:Button label="Save" click="onImgSave()"
toolTip="ローカルにイメージファイルを保存する" width="50"/>
<s:ComboBox id="cmbImgFormat" requireSelection="true"
width="55" toolTip="ファイル種類" >
<s:dataProvider>
<s:ArrayList>
<fx:Array>
<fx:Object label="PNG" />
<fx:Object label="JPG" />
</fx:Array>
</s:ArrayList>
</s:dataProvider>
</s:ComboBox>
</s:HGroup>
<!-- 描画領域 -->
<mx:HRule width="100%" /> <!-- 区切り線 -->
<!-- 描画領域が大きくなた時のためのスクロールバー -->
<s:Scroller width="100%" height="100%" >
<s:Group width="100%" height="100%" >
<s:Rect width="100%" height="100%">
<s:fill>
<s:SolidColor color="0xbbbbbb"/>
</s:fill>
</s:Rect>
<!-- 描画領域 -->
<s:Group width="500" height="500" id="grpPreview">
<!-- 描画領域の初期背景色 -->
<s:Rect height="100%" width="100%">
<s:fill>
<s:SolidColor color="0xffffff"/>
</s:fill>
</s:Rect>
<!-- 実際の描画領域 -->
<mx:UIComponent id="uiGrf" height="500" width="500"/>
</s:Group>
</s:Group>
</s:Scroller>
</s:VGroup>
</s:HGroup>
</s:VGroup>
</s:Scroller>
</s:Group>
</s:Application>