forked from: jump floodingアルゴリズムを用いたボロノイ図の生成
jump floodingアルゴリズムを用いたボロノイ図の生成
制御点をドラッグで移動
http://www.comp.nus.edu.sg/~tants/jfa/rong-guodong-phd-thesis.pdf
点の数が増えても処理負荷が変わらず、GPU実装が容易なアルゴリズム
ソフトシャドウにも応用可能
x方向の移動距離とy方向の移動距離を別々に保存しておき、距離はテーブルで算出するようにした。
/**
* Copyright h_sakurai ( http://wonderfl.net/user/h_sakurai )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/2bDK
*/
// forked from Nao_u's jump floodingアルゴリズムを用いたボロノイ図の生成
// forked from Nao_u's jump floodingアルゴリズムを用いたボロノイ図の生成
//
// jump floodingアルゴリズムを用いたボロノイ図の生成
//
// 制御点をドラッグで移動
//
// http://www.comp.nus.edu.sg/~tants/jfa/rong-guodong-phd-thesis.pdf
// 点の数が増えても処理負荷が変わらず、GPU実装が容易なアルゴリズム
// ソフトシャドウにも応用可能
//
// x方向の移動距離とy方向の移動距離を別々に保存しておき、距離はテーブルで算出するようにした。
//
package {
import flash.accessibility.Accessibility;
import flash.display.Sprite;
import flash.events.*;
[SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="15")]
public class FlashTest extends Sprite {
public function FlashTest() {
Main = this;
initialize();
stage.addEventListener(Event.ENTER_FRAME,update);
}
}
}
import flash.display.Sprite;
import flash.events.*
import flash.text.TextField;
import flash.geom.*;
import flash.utils.getTimer;
var Main:Sprite;
var SCREEN_W:Number = 465;
var SCREEN_H:Number = 465;
var Text:TextField
var Text2:TextField
var Tex:ProcTex;
var BITMAP_W:int = 128;
var BITMAP_H:int = 128;
var Pnt:Vector.<ControlPoint> = new Vector.<ControlPoint>;
// 初期化
function initialize():void{
Tex = new ProcTex( BITMAP_W, BITMAP_H );
Tex.Bmp.x = 0;
Tex.Bmp.y = 0;
Text = new TextField();
Text.text = "生成中...";
Text.autoSize = "left";
Text.textColor=0xff0000;
Main.addChild(Text);
Text2 = new TextField();
Text2.text = "";
Text2.autoSize = "left";
Text2.y = 16;
Main.addChild(Text2);
// 制御点の設置
Pnt[0] = new ControlPoint(new Point(10, 10));
Pnt[1] = new ControlPoint(new Point(10+58*4, 10));
for (var i:int=2; i < 20; i++) {
Pnt[i] = new ControlPoint( new Point(SCREEN_W*Math.random(), SCREEN_H*Math.random()) );
}
}
// 更新
function update(e :Event):void{
var time:int = getTimer();
Tex.draw();
var endTime:int = getTimer() - time;
Text.text = " 生成時間:" + endTime + "[ms]"+dstr;
dstr = "";
}
var dstr:String = "";
var dbg:Boolean = false;
function db(str:String):void{
if(dbg)dstr += str;
}
import flash.display.Bitmap;
import flash.display.BitmapData;
// テクスチャ生成クラス
class ProcTex{
public var BmpData:BitmapData;
public var TmpBmpData:BitmapData;
public var Bmp:Bitmap;
public var Width:int;
public var Height:int;
private var distTable:Vector.<uint> = new Vector.<uint>(0x10000);
private function dist(v:int):int {
if((v & 0x80)>0)v = 0xffffff00|v;
return v;
}
public function ProcTex( w:int, h:int ){
for(var i:int=0;i<0x10000;i++){
var d:int = 0;
var x1:int = dist((i >> 8)& 0xff);
var y1:int = dist(i&0xff);
distTable[i]=x1*x1+y1*y1;
}
Width = w;
Height = h;
BmpData = new BitmapData(Width, Height, false, 0xffffff);
TmpBmpData = new BitmapData(Width, Height, false, 0xffffff);
Bmp = new Bitmap(BmpData);
Bmp.x = 0.0;
Bmp.y = 0.0;
Bmp.scaleX = 7.25*0.5;
Bmp.scaleY = 7.25*0.5;
Main.addChild(Bmp);
}
public function draw():void{
drawBmpData( BmpData );
}
public function drawBmpData( bmpData:BitmapData ):void{
var col:int;
bmpData.lock();
bmpData.fillRect(bmpData.rect, 0x8080);
var c:int = 0x12344321;
// 基準点を描画
for (var i:int = 0; i < Pnt.length; i++) {
Pnt[i].Sp.x = (Pnt[i].Sp.x + Pnt[i].vx+SCREEN_W)% SCREEN_W;
Pnt[i].Sp.y = (Pnt[i].Sp.y + Pnt[i].vy+SCREEN_H)% SCREEN_H;
bmpData.setPixel( Pnt[i].Sp.x/7.2*2, Pnt[i].Sp.y/7.2*2, 0xff0000 & c);
c = c * 4321431+4314313;
}
bmpData.unlock();
// jumpFlood処理を大きいほうから順番に行う
// 7回移動する
jumpFlood( bmpData, 1 );
//dbg=true;
jumpFlood( bmpData, 64 );
jumpFlood( bmpData, 32 );
jumpFlood( bmpData, 16 );
jumpFlood( bmpData, 8 );
jumpFlood( bmpData, 4 );
jumpFlood( bmpData, 2 );
// jumpFlood( bmpData, 1 );
// jumpFlood( bmpData, 1 );
}
public function jumpFlood( bmpData:BitmapData, w:int ):void{
TmpBmpData = bmpData.clone();
var distTable:Vector.<uint> = this.distTable;
var p0:int, p1:int, p2:int, p3:int, p4:int, p5:int, p6:int, p7:int, p8:int;
var base:int, col:int,col2:int, baseDist:uint, d:int;
var w2:int = w << 8;
bmpData.lock();
var b:int = 0;
for( var x:int=0; x<Width; x++ ){
var x1:int = (x-w)&0x7f;
var x2:int = (x+w)&0x7f;
for( var y:int=0; y<Height; y++ ){
var y1:int =(y-w)&0x7f;
var y2:int =(y+w)&0x7f;
col = base = TmpBmpData.getPixel( x, y );
// 周囲8方向の指定された距離だけ離れたピクセルを拾ってくる
p0 = TmpBmpData.getPixel( x1, y1 );
p1 = TmpBmpData.getPixel( x , y1 );
p2 = TmpBmpData.getPixel( x2, y1 );
p3 = TmpBmpData.getPixel( x1, y );
p5 = TmpBmpData.getPixel( x2, y );
p6 = TmpBmpData.getPixel( x1, y2 );
p7 = TmpBmpData.getPixel( x , y2 );
p8 = TmpBmpData.getPixel( x2, y2 );
col2 = base & 0xffff;
var d0:uint = ((p0-w2)&0xff00)+((-w+p0)&0xff);
var d1:uint = ((p1 )&0xff00)+((-w+p1)&0xff);
var d2:uint = ((p2+w2)&0xff00)+((-w+p2)&0xff);
var d3:uint = ((p3-w2)&0xff00)+(( p3)&0xff);
var d5:uint = ((p5+w2)&0xff00)+(( p5)&0xff);
var d6:uint = ((p6-w2)&0xff00)+(( w+p6)&0xff);
var d7:uint = ((p7 )&0xff00)+(( w+p7)&0xff);
var d8:uint = ((p8+w2)&0xff00)+(( w+p8)&0xff);
baseDist = distTable[col2];
var pp0:uint = distTable[d0];
var pp1:uint = distTable[d1];
var pp2:uint = distTable[d2];
var pp3:uint = distTable[d3];
var pp5:uint = distTable[d5];
var pp6:uint = distTable[d6];
var pp7:uint = distTable[d7];
var pp8:uint = distTable[d8];
// 拾った中でもっとも基準点からの距離が小さいピクセルを自分のピクセルにコピー
if(pp0 < baseDist ) { col=p0; col2 = d0; baseDist = pp0;}
if(pp1 < baseDist ) { col=p1; col2 = d1; baseDist = pp1;}
if(pp2 < baseDist ) { col=p2; col2 = d2; baseDist = pp2;}
if(pp3 < baseDist ) { col=p3; col2 = d3; baseDist = pp3;}
if(pp5 < baseDist ) { col=p5; col2 = d5; baseDist = pp5;}
if(pp6 < baseDist ) { col=p6; col2 = d6; baseDist = pp6;}
if(pp7 < baseDist ) { col=p7; col2 = d7; baseDist = pp7;}
if(pp8 < baseDist ) { col=p8; col2 = d8; baseDist = pp8;}
// 距離を更新
if(col != 0x8080) {
bmpData.setPixel(x, y, (col&0xff0000)+col2);
}
}
}
}
}
// 制御点マーカークラス
class ControlPoint{
public var Sp:Sprite;
public var isEnable:Boolean = false;
public var Pos:Point;
public var vx:Number;
public var vy:Number;
public function ControlPoint( p:Point ){
Sp=new Sprite();
Pos = p;
Sp.x = Pos.x;
Sp.y = Pos.y;
vx = Math.random()*8.0-4;
vy = Math.random()*8.0-4;
// setEnable( true );
Main.stage.addChild(Sp);
Sp.addEventListener(MouseEvent.MOUSE_UP, function (event:MouseEvent):void{ Sp.stopDrag(); });
Sp.addEventListener(MouseEvent.MOUSE_DOWN, function (event:MouseEvent):void{ if( isEnable ) Sp.startDrag(); });
}
public function setEnable( flg:Boolean ):void{
if( flg == true && isEnable == false ){
Sp.graphics.clear();
Sp.graphics.lineStyle(1.4,0x000000);
Sp.graphics.beginFill(0x00000,0);
Sp.graphics.drawCircle(0,0,2.0);
Sp.graphics.endFill();
}else if( flg == false && isEnable == true ){
Sp.graphics.clear();
}
isEnable = flg;
}
}