In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Delaunay三角分割

Delaunay三角分割サンプル

@author termat(http://termat.sakura.ne.jp/)
/**
 * Copyright termat ( http://wonderfl.net/user/termat )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/vuDK
 */

package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    /**
	 *	Delaunay三角分割サンプル
	 *
     * @author termat(http://termat.sakura.ne.jp/)
     */
	[SWF(framerate="30",width="480",height="480",backgroundColor="0x000000")]
	public class Practice05 extends Sprite
	{
		private var list:Vector.<Circle>;
		private var del:Del
		
		public function Practice05():void {
			graphics.lineStyle(2,0xaaaaaa);
			graphics.drawRect(0,0,480,480);
			list = new Vector.<Circle>();
			del = new Del(list);
			addChild(del);
			stage.addEventListener(MouseEvent.CLICK, onClick);
			stage.addEventListener(Event.EXIT_FRAME,update);
		}
		
		private function onClick(e:MouseEvent):void {
			addNode(e.stageX,e.stageY);
		}
		
		private function addNode(x:Number,y:Number):void{
			var vx:Number = Math.random() * 12 - 6;
			if (Math.abs(vx) < 1e-2) vx=1.0;
			var vy:Number = Math.random() * 12 - 6;
			if (Math.abs(vy) < 1e-2) vy=1.0;
			var velo:Number = vx * vx + vy * vy;
			var c:int = Math.floor(Math.random() * 0xffffff);
			var p:Circle = new Circle(x,y,2,c,vx,vy);
			addChild(p);
			list.push(p);
		}	
		private function update(e:Event):void {
			if(this.numChildren<80){
				var xx:Number=Math.random()*480;
				var yy:Number=Math.random()*480;
				addNode(xx,yy);
			}
			for each(var c:Circle in list ) {
				c.update();
			}
			del.update();
		}
	}

}

import flash.display.MovieClip;
import flash.display.Shape;
import flash.display.Sprite;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.display.GradientType;

class Circle extends MovieClip {
	private var vx:Number;
	private var vy:Number;
	private var color:uint;
	
	public function Circle(x:int, y:int, r:int, c:uint, vx:int, vy:int) {
		this.vx = vx;
		this.vy = vy;
		this.x = x;
		this.y = y;
		color = c;
		graphics.lineStyle(2, color) ;
		graphics.beginFill(c);
		graphics.drawCircle(0, 0, r);
		graphics.endFill();
		this.alpha = 0.5;
	}
	
	public function getLineColor():uint {
		return color;
	}
	
	public function update():void {
		var div:Number;
		if (x + vx < 0) {
			div = Math.abs((x + vx)/vx);
			vx *= -1;
			x = x + vx * div;
		}else if (x + vx > 480) {
			div= Math.abs((x + vx - 480) / vx);
			vx *= -1;
			x = x + vx * div;
		}else {
			x += vx;
		}
		if (y + vy < 0) {
			div = Math.abs((y + vy)/vy);
			vy *= -1;
			y = y + vy * div;
		}else if (y + vy > 480) {
			div= Math.abs((y + vy-480)/vy);
			vy *= -1;
			y = y + vy * div;
		}else {
			y += vy;
		}
	}
}

class Del extends Sprite {
	private var list:Vector.<Circle>;
	private var del:Delaunay;
	private var matrix:Matrix=new Matrix();
	
	public function Del(l:Vector.<Circle>):void {
		list = l;
		del = new Delaunay(0, 0, 480, 480);
	}
	
	public function update():void {
		while(this.numChildren > 0) removeChildAt(this.numChildren - 1);
		del.clear();
		for each(var c:Circle in list) {
			var p:Point = new Point(c.x, c.y);
			del.insert(p);
		}
		var n:Vector.<Point> = del.getNode();
		var e:Vector.<Array> = del.getElem();
		for each(var ee:Array in e) {
			addChild(
				getLines(n[ee[0]], n[ee[1]], n[ee[2]],
					list[ee[0]].getLineColor(),list[ee[1]].getLineColor(),list[ee[2]].getLineColor()));
		}
	}
	
	private function getLines(p0:Point, p1:Point, p2:Point, c0:uint, c1:uint, c2:uint):Shape {
		var ret:Shape = new Shape();
		ret.graphics.lineStyle(1, 0x444444);
		ret.graphics.moveTo(p0.x, p0.y);
		var tp:Number = Math.min(20 / dist(p0, p1), 1.0);
		ret.graphics.lineGradientStyle(GradientType.LINEAR, [c0,c1], [tp,tp], [0, 255], updateMatrix(p0,p1)); 
		ret.graphics.lineTo(p1.x, p1.y);
		tp = Math.min(20 / dist(p1, p2), 1.0);
		ret.graphics.lineGradientStyle(GradientType.LINEAR, [c1,c2], [tp,tp], [0, 255], updateMatrix(p1,p2)); 
		ret.graphics.lineTo(p2.x, p2.y);
		tp = Math.min(20 / dist(p2, p0), 1.0);
		ret.graphics.lineGradientStyle(GradientType.LINEAR, [c2, c0], [tp, tp], [0, 255], updateMatrix(p2,p0)); 
		ret.graphics.lineTo(p0.x, p0.y);
		return ret;
	}
	
	private function dist(p0:Point,p1:Point):Number {
		var xx:Number = p0.x - p1.x;
		var yy:Number = p0.y - p1.y;
		return Math.sqrt(xx*xx+yy*yy);
	}
	
	private function updateMatrix(p0:Point, p1:Point):Matrix {
		matrix.createGradientBox(p1.x - p0.x, p1.y - p0.y, 0, p0.x, p0.y);
		return matrix;
	}
}
import flash.geom.Point;
import flash.geom.Rectangle;
	
class Delaunay
{
	private var EPS:Number = 1e-16;
	private var rect:Rectangle;
	private var min:Number;
	private var max:Number;
	private var data:Vector.<Point>;
	private var node:Vector.<Point>;
	private var elem:Array;
	private var map:Array;
	private var stack:Array;
	private var boundary:Array;
	private var boundaryID:Array;
	private var ids:int;
	private var bs:int;
		
	public function Delaunay(x:Number, y:Number, w:Number, h:Number ):void {
		rect= new Rectangle(x, y, w, h);
		min = Math.min(x,y,x+w,y+h);
		max = Math.max(x,y,x+w,y+h);
		data=new Vector.<Point>();
		node=new Vector.<Point>();
		elem=new Array();
		map=new Array();
		stack=new Array();
		boundary=new Array();
		boundaryID=new Array();
		node.push(new Point(-1.23,-0.5));
		node.push(new Point(2.23,-0.5));
		node.push(new Point(0.5,2.5));
		elem.push(new Array(0,1,2));
		map.push(new Array(-1,-1,-1));
		ids=0;
		bs=1;
	}
		
	public function clear():void {
		data=new Vector.<Point>();
		node=new Vector.<Point>();
		elem=new Array();
		map=new Array();
		stack=new Array();
		boundary=new Array();
		boundaryID=new Array();
		node.push(new Point(-1.23,-0.5));
		node.push(new Point(2.23,-0.5));
		node.push(new Point(0.5,2.5));
		elem.push(new Array(0,1,2));
		map.push(new Array( -1, -1, -1));
		ids=0;
		bs=1;
	}
		
	private function getTriangleById():Array {
		var et:Array=new Array();
		var id:int=0;
		for(var i:int=0;i<elem.length;i++){
			if(!checkBounds(i)){
				et.push(-1);
			}else if(!checkBoundaryState(i)){
				et.push(-1);
			}else{
				et.push(id++);
			}
		}
		var ee:Array=new Array();
		for(i=0;i<et.length;i++){
			var e:Array=this.elem[i];
			if(et[i]!=-1){
				ee.push(new Array(e[0]-3,e[1]-3,e[2]-3));
			}
		}
		return ee;
	}
	private function getTriangleMapById():Array {
		var et:Array=new Array();
		var id:int=0;
		for(var i:int=0;i<elem.length;i++){
			if(!checkBounds(i)){
				et.push(-1);
			}else if(!this.checkBoundaryState(i)){
				et.push(-1);
			}else{
				et.push(id++);
			}
		}
		var ee:Array=new Array();
		var tp:Array=new Array();
		for(i=0;i<et.length;i++){
			var m:Array=map[i];
			if(et[i]!=-1){
				for(var j:int=0;j<m.length;j++){
					if(m[j]==-1){
						tp[j]=-1;
					}else{
						tp[j]=et[m[j]];
					}
				}
				ee.push(new Array(tp[0],tp[1],tp[2]));
			}
		}
		return ee;
	}
	
	private function isLeft(a:Point,b:Point,p:Point):Number{
		var v0:Number=(a.y-p.y)*(b.x-p.x);
		var v1:Number=(a.x-p.x)*(b.y-p.y);
		if(Math.abs(v1-v0)<this.EPS){
			return 0;
		}else{
			return (v1-v0);
		}
	}

	public function getLocation(id:int, p:Point):int {
		var e:Array=elem[id];
		for(var i:int=0;i<e.length;i++){
			var a:Point=node[e[i]];
			var b:Point=node[e[(i+1)%3]];
			if(isLeft(a,b,p)<0){
				var n:int=map[id][i];
				if(n==-1){
					return -1;
				}
				return getLocation(n,p);
			}
		}
		return id;
	}
	
	private function checkBoundaryState(id:int):Boolean {
		if(bs>1){
			if(!checkBounds(id))return false;
		}
		var e:Array=elem[id];
		for (var i:int = 0; i < e.length; i++) {
			if(typeof boundaryID[e[i]]=="undefined")continue;
			var b0:int = boundaryID[e[i]];
			if(typeof boundaryID[e[(i + 1) % 3]]=="undefined")continue;
			var b1:int = boundaryID[e[(i + 1) % 3]];
			if (b0 - b1 == 0) {
				if(typeof boundary[e[(i + 1) % 3]]=="undefined")continue;
				var v0:int = boundary[e[(i + 1) % 3]];
				if(v0==e[i]){
					return false;
				}
			}
		}
		return true;
	}
	
	private function edge(elemId:int, targetId:int, mp:Array ):int {
		var j:Array=mp[elemId];
		for(var i:int=0;i<j.length;i++){
			if(j[i]==targetId)return i;
		}
		return -1;
	}

	private function isSwap(aId:int , bId:int, cId:int, pId:int):Boolean {
		var x13:Number=node[aId].x-node[cId].x;
		var y13:Number=node[aId].y-node[cId].y;
		var x23:Number=node[bId].x-node[cId].x;
		var y23:Number=node[bId].y-node[cId].y;
		var x1p:Number=node[aId].x-node[pId].x;
		var y1p:Number=node[aId].y-node[pId].y;
		var x2p:Number=node[bId].x-node[pId].x;
		var y2p:Number=node[bId].y-node[pId].y;
		var cosa:Number=x13*x23+y13*y23;
		var cosb:Number=x2p*x1p+y1p*y2p;
		if(cosa>=0&&cosb>=0){
			return false;
		}else if(cosa<0&&cosb<0){
			return true;
		}else{
			var sina:Number=x13*y23-x23*y13;
			var sinb:Number=x2p*y1p-x1p*y2p;
			if((sina*cosb+sinb*cosa)<0){
				return true;
			}else{
				return false;
			}
		}
	}

	public function getNode():Vector.<Point> {
		return data;
	}
	
	public function getElem():Vector.<Array> {
		var ret:Vector.<Array> = new Vector.<Array>();
		for each(var e:Array in elem) {
			if(e[0]<3||e[1]<3||e[2]<3){
				continue;
			}else{
				ret.push(new Array(e[0]-3, e[1]-3, e[2]-3));
			}
		}
		return ret;
	}

	private function normalize(x:Number, y:Number):Point {
		var xx:Number = (x - min) / (max - min);
		var yy:Number = (y - min) / (max - min);
		return new Point(xx,yy);
	}

	private function checkBounds(id:int):Boolean {
		var e:Array=elem[id];
		if(e[0]<3||e[1]<3||e[2]<3){
			return false;
		}else{
			return true;
		}
	}

	public function insert(pos:Point):Boolean {
		if (!rect.containsPoint(pos)) return false;
		var p:Point=normalize(pos.x,pos.y);
		ids = getLocation(ids, p);
		if(ids==-1){
			ids=0;
			return false;
		}else {
			if (checkBoundaryState(ids)) {
				data.push(pos);
				node.push(p);
				process(ids, node.length - 1);
				return true;
			}else {
				return false;
			}
		}
	}

	public function addBoundary(arg:Array,isClose:Boolean):void {
		var sz:int= node.length;
		for(var i:int=0;i<arg.length;i++){
			var p:Point=normalize(arg[i].x,arg[i].y);
			ids=getLocation(ids,p);
			if(ids==-1){
				ids=0;
				continue;
			}
			if(checkBoundaryState(ids)){
				data.push(arg[i]);
				node.push(p);
				if(i>0){
					boundary[sz+i-1]=sz+i;
					boundaryID[sz+i-1]=bs;
				}
				process(ids,node.length-1);
			}
		}
		if(isClose){
			boundary[node.length-1]=sz;
			boundaryID[node.length-1]=bs;
		}
		bs++;
	}
	
	private function isBoundary(nodeId0:int , nodeId1:int):Boolean {
		var p:int=boundary[nodeId0];
		if(!(typeof boundary[nodeId0]=="undefined")&&p==nodeId1)return true;
		p=boundary[nodeId1];
		if(!(typeof boundary[nodeId1]=="undefined")&&p==nodeId0){
			return true;
		}else{
			return false;
		}	
	}

	private function process(elemId:int, nodeId:int):void {
		var nn:int=elem.length;
		var em:Array=elem[elemId];
		var te:Array=new Array(em[0],em[1],em[2]);
		var e0:Array=new Array(nodeId,em[0],em[1]);
		var e1:Array=new Array(nodeId,em[1],em[2]);
		var e2:Array=new Array(nodeId,em[2],em[0]);
		em[0]=e0[0];em[1]=e0[1];em[2]=e0[2];
		elem.push(e1);
		elem.push(e2);
		var jm:Array=map[elemId];
		var tmp:Array=new Array(jm[0],jm[1],jm[2]);
		var j0:Array=new Array(nn+1,jm[0],nn);
		var j1:Array=new Array(elemId,jm[1],nn+1);
		var j2:Array=new Array(nn,jm[2],elemId);
		jm[0]=j0[0];jm[1]=j0[1];jm[2]=j0[2];
		map.push(j1);
		map.push(j2);
		if(tmp[0]!=-1){
			if(!isBoundary(te[0],te[1]))stack.push(elemId);
		}
		if(tmp[1]!=-1){
			var ix:int=edge(tmp[1],elemId,map);
			map[tmp[1]][ix]=nn;
			if(!isBoundary(te[1],te[2]))stack.push(nn);
		}
		if(tmp[2]!=-1){
			ix=edge(tmp[2],elemId,map);
			map[tmp[2]][ix]=nn+1;
			if(!isBoundary(te[2],te[0]))stack.push(nn+1);
		}
		while (stack.length > 0) {
			var il:int=stack.pop();
			var ir:int=map[il][1];
			var ierl:int=edge(ir,il,map);
			var iera:int=(ierl+1)%3;
			var ierb:int=(iera+1)%3;
			var iv1:int=elem[ir][ierl];
			var iv2:int=elem[ir][iera];
			var iv3:int=elem[ir][ierb];
			if(isSwap(iv1,iv2,iv3,nodeId)){
				var ja:int=map[ir][iera];
				var jb:int=map[ir][ierb];
				var jc:int=map[il][2];
				elem[il][2]=iv3;
				map[il][1]=ja;
				map[il][2]=ir;
				var picElem:Array=elem[ir];
				picElem[0]=nodeId;picElem[1]=iv3;picElem[2]=iv1;
				picElem=map[ir];
				picElem[0]=il;picElem[1]=jb;picElem[2]=jc;
				if(ja!=-1){
					ix=edge(ja,ir,map);
					map[ja][ix]=il;
					if(!isBoundary(iv2,iv3))stack.push(il);
				}
				if(jb!=-1){
					if(!isBoundary(iv3,iv1))stack.push(ir);
				}
				if(jc!=-1){
					ix=edge(jc,il,this.map);
					map[jc][ix]=ir;
				}
			}
		}
	}
}