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

forked from: forked from: flash on 2012-8-10

Get Adobe Flash player
by makc3d 10 Aug 2012
    Embed
// forked from makc3d's forked from: flash on 2012-8-10
// forked from makc3d's flash on 2012-8-10
package  
{
	import flash.display.*;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;

	public class Main3 extends Sprite
	{
		public var bd:BitmapData;
		public var bezier:Vector.<Bezier>;
		public var i:int;
		public function Main3 () 
		{
			click ();
			stage.addEventListener (MouseEvent.CLICK, click);
			stage.addEventListener (Event.ENTER_FRAME, loop);
		}
		
		private function click (...whatever):void {
			i = -1;
			
			bezier = new Vector.<Bezier>;
			for (var k:int = 0; k < 10; k++) bezier [k] = new Bezier (
				465 * (0.1 + 0.8 * Math.random ()),
				465 * (0.1 + 0.8 * Math.random ()),
				465 * (0.1 + 0.8 * Math.random ()),
				465 * (0.1 + 0.8 * Math.random ()),
				465 * (0.1 + 0.8 * Math.random ()),
				465 * (0.1 + 0.8 * Math.random ())
			);
			
			graphics.beginBitmapFill (bd = new BitmapData (465, 465, false, 0));
			graphics.drawRect (0, 0, 465, 465);
			graphics.endFill ();
			
			graphics.lineStyle (1, 0xFFFFFF);
			for (k = 0; k < 10; k++) {
				graphics.moveTo (bezier[k].getPos (0).x, bezier[k].getPos (0).y);
				graphics.curveTo (bezier[k].getCtrl ().x, bezier[k].getCtrl ().y, bezier[k].getPos (1).x, bezier[k].getPos (1).y);
			}
		}
		
		private function loop(e:Event):void 
		{
			bd.lock();
			var j:int = i + 234;
			while (i++ < 465 * 465) {
				var X:Number = int (i / 465);
				var Y:Number = i % 465;
				var D:Number = Number.MAX_VALUE;
				for (var k:int = 0; k < 10; k++) {
					var O:Object = bezier[k].findNearestPoint (X, Y);
					if (D > O.dist) {
						D = O.dist;
						var P:Point = O.pos;
						var R:int = 255 * (k + O.t) / 10;
						var G:int = 255 * (0.5 + 0.5 * (P.x - X) / 465);
						var B:int = 255 * (0.5 + 0.5 * (P.y - Y) / 465);
					}
				}
				bd.setPixel (X, Y, R * 65536 + G * 256 + B);
				if (i > j) break;
			}
			bd.unlock();
		}
		
	}

}

/**
* Bezier class for collision detection
* @author Olivier Besson (http://www.gludion.com)
* @version 0.2
*/

import flash.geom.Point;


class Bezier
{
	// a value we consider "small enough" to equal it to zero:
	// (this is used for double solutions in 2nd or 3d degree equation)
	public static var zeroMax:Number = 0.0000001;
	
	private var p0:Point;			// handle 0 of curve
	private var p1:Point;			// handle 1 of curve
	private var p2:Point;			// handle 2 of curve
	
	// bounds data
	private var xMin:Number;
	private var xMax:Number;
	private var yMin:Number;
	private var yMax:Number;
	
	// data for position+tangent
	private var pos:Point;			// generic position on curve
	private var tan:Point;			// tangent
	private var nor:Point;			// normal
	
	// PERSONAL note: for conversion quadratic=>cubic, put 2 handles at 2/3 of p0p1 and p2p1

	
	// data for nearest:
	private var A:Point;				// an util vector (= p1-p0)
	private var B:Point;				// an util vector (= p2-p1-A)
	private var solution:Object;		// solution of 3d degree equation
	private var nearest:Object;			// data about nearest point
	private var posMin:Point;			// nearest position on curve
	
	
	// defines a Quadratic Bezier Curve with p0 = (x0, y0), p1 = (x1, y1), p2 = (x2, y2)
	// p0 and p2 are anchor points.
	// p1 is control point.
	public function Bezier(x0:Number,y0:Number,x1:Number,y1:Number,x2:Number,y2:Number)
	{
		p0 = new Point();
		p1 = new Point();
		p2 = new Point();
	
		pos = new Point();
		tan = new Point();
		nor = new Point();
		
		A = new Point();
		B = new Point();
		solution = new Object();
		nearest = new Object();
		posMin = new Point();
		
		update(x0, y0, x1, y1, x2, y2);
	}
	
	// should be called after any anchor or control point is moved.
	public function update(x0:Number,y0:Number,x1:Number,y1:Number,x2:Number,y2:Number):void
	{
		p0.x = x0;
		p0.y = y0;
		p1.x = x1;
		p1.y = y1;
		p2.x = x2;
		p2.y = y2;
		
		// precompute A and B, which will be very useful next.
		A.x = p1.x - p0.x;
		A.y = p1.y - p0.y;
		B.x = p0.x - 2 * p1.x + p2.x;
		B.y = p0.y - 2 * p1.y + p2.y;
		
		// rough evaluation of bounds:
		xMin = Math.min(x0, Math.min(x1, x2));
		xMax = Math.max(x0, Math.max(x1, x2));
		yMin = Math.min(y0, Math.min(y1, y2));
		yMax = Math.max(y0, Math.max(y1, y2));
		
		// more accurate evaluation:
		// see Andree Michelle for a faster but less readable method 
		var u:Number;
		if (xMin == x1 || xMax == x1) 
		{
			u = -A.x / B.x; // u where getTan(u).x == 0
			u = (1 - u) * (1 - u) * p0.x + 2 * u * (1 - u) * p1.x + u * u * p2.x;
			if (xMin == x1) xMin = u;
			else xMax = u;
		}
		if (yMin == y1 || yMax == y1) 
		{
			u = -A.y / B.y; // u where getTan(u).y == 0
			u = (1 - u) * (1 - u) * p0.y + 2 * u * (1 - u) * p1.y + u * u * p2.y;
			if (yMin == y1) yMin = u;
			else yMax = u;
		}
	}
	
	public function hitTest(pBounds:Object):Boolean
	{
		if (pBounds.xMax < xMin || pBounds.xMin > xMax) return false;
		if (pBounds.yMax < yMin || pBounds.yMin > yMax) return false;
		return true;
	}
	
	// returns { t:Number, pos:Point, dist:Number, nor:Point }
	// (costs about 80 multiplications+additions)
	public function findNearestPoint(x:Number, y:Number):Object
	{
		// a temporary util vect = p0 - (x,y)
		pos.x = p0.x - x;
		pos.y = p0.y - y;
		// search points P of bezier curve with PM.(dP / dt) = 0
		// a calculus leads to a 3d degree equation :
		var a:Number = B.x * B.x + B.y * B.y;
		var b:Number = 3 * (A.x * B.x + A.y * B.y);
		var c:Number = 2 * (A.x * A.x + A.y * A.y) + pos.x * B.x + pos.y * B.y;
		var d:Number = pos.x * A.x + pos.y * A.y;
		var sol:Object = thirdDegreeEquation(a, b, c, d);
		
		var t:Number;
		var dist:Number;
		var tMin:Number;
		var distMin:Number = Number.MAX_VALUE;
		var d0:Number = getDist(x, y, p0.x, p0.y);
		var d2:Number = getDist(x, y, p2.x, p2.y);
		var orientedDist:Number;
		
		if (sol != null)
		{
			// find the closest point:
			for (var i:int = 1; i <= sol.count; i++)
			{
				t = sol["s" + i];
				if (t >= 0 && t <= 1)
				{
					pos = getPos(t);
					dist = getDist(x, y, pos.x, pos.y);
					if (dist < distMin)
					{
						// minimum found!
						tMin = t;
						distMin = dist;
						posMin.x = pos.x;
						posMin.y = pos.y;
					}
				}
			}
			if (!isNaN(tMin) && distMin < d0 && distMin < d2) 
			{
				// the closest point is on the curve
				nor.x = A.y + tMin * B.y;
				nor.y = -(A.x + tMin * B.x);
				nor.normalize(1);
				orientedDist = distMin;
				if ((x - posMin.x) * nor.x + (y - posMin.y) * nor.y < 0) 
				{
					nor.x *= -1;
					nor.y *= -1;
					orientedDist *= -1;
				}
				
				nearest.t = tMin;
				nearest.pos = posMin;
				nearest.nor = nor;
				nearest.dist = distMin;
				nearest.orientedDist = orientedDist;
				nearest.onCurve = true;
				return nearest;
			}
			
		} 
		// the closest point is one of the 2 end points
		if (d0 < d2) 
		{
			distMin = d0;
			tMin = 0;
			posMin.x = p0.x;
			posMin.y = p0.y;	
		} else 
		{
			distMin = d2;
			tMin = 1;
			posMin.x = p2.x;
			posMin.y = p2.y;
		}
		nor.x = x - posMin.x;
		nor.y = y - posMin.y;
		nor.normalize(1);
		
		nearest.t = tMin;
		nearest.pos = posMin;
		nearest.nor = nor;
		nearest.orientedDist = nearest.dist = distMin;
		nearest.onCurve = false;
		return nearest;
	}
	
	
	
	public function getPos(t:Number):Point
	{
		var a:Number = (1 - t) * (1 - t);
		var b:Number = 2 * t * (1 - t);
		var c:Number = t * t;
		pos.x = a * p0.x + b * p1.x + c * p2.x;
		pos.y = a * p0.y + b * p1.y + c * p2.y;
		return pos;
	}
	
	public function getCtrl():Point
	{
		return p1.clone();
	}
	
	// (dP/dt)(t) = 2*(A + t*B)
	public function getSpeed(t:Number):Number
	{
		tan.x = A.x + t * B.x;
		tan.y = A.y + t * B.y;
		return 2 * Math.sqrt(tan.x * tan.x + tan.y * tan.y);
		//return 2*tan.getNorm();
	}
	
	public function getNor(t:Number):Point
	{
		nor.x = A.y + t * B.y;
		nor.y = -(A.x + t * B.x);
		// normalize:
		var lNorm:Number = Math.sqrt(nor.x * nor.x + nor.y * nor.y);
		if (lNorm > 0)
		{
			nor.x /= lNorm;
			nor.y /= lNorm;
		}
		return nor;
	}
	
	// a local duplicate & optimized version of com.gludion.utils.MathUtils.thirdDegreeEquation(a,b,c,d):Object
	//WARNING: s2, s3 may be non - null if count = 1.
	// use only result["s"+i] where i <= count
	private function thirdDegreeEquation(
								a:Number,
								b:Number,
								c:Number,
								d:Number
								):Object	// returns a {count:Number, s1:Number, s2:Number, s3:Number} object
	{
		if (Math.abs(a) > zeroMax)
		{
			// let's adopt form: x3 + ax2 + bx + d = 0
			var z:Number = a; // multi-purpose util variable
			a = b / z;
			b = c / z;
			c = d / z;
			// we solve using Cardan formula: http://fr.wikipedia.org/wiki/M%C3%A9thode_de_Cardan
			var p:Number = b - a * a / 3;
			var q:Number = a * (2 * a * a - 9 * b) / 27 + c;
			var p3:Number = p * p * p;
			var D:Number = q * q + 4 * p3 / 27;
			var offset:Number = -a / 3;
			if (D > zeroMax)
			{
				// D positive
				z = Math.sqrt(D)
				var u:Number = ( -q + z) / 2;
				var v:Number = ( -q - z) / 2;
				u = (u >= 0)? Math.pow(u, 1 / 3) : -Math.pow( -u, 1 / 3);
				v = (v >= 0)? Math.pow(v, 1 / 3) : -Math.pow( -v, 1 / 3);
				solution.s1 = u + v + offset;
				solution.count = 1;
				return solution;
			} else if (D < -zeroMax)
			{
				// D negative
				u = 2 * Math.sqrt( -p / 3);
				v = Math.acos( -Math.sqrt( -27 / p3) * q / 2) / 3;
				solution.s1 = u * Math.cos(v) + offset;
				solution.s2 = u * Math.cos(v + 2 * Math.PI / 3) + offset;
				solution.s3 = u * Math.cos(v + 4 * Math.PI / 3) + offset;
				solution.count = 3;
				return solution;
			} else
			{
				// D zero
				if (q < 0) u = Math.pow( -q / 2, 1 / 3);
				else u = -Math.pow( q / 2, 1 / 3);
				solution.s1 = 2*u + offset;
				solution.s2 = -u + offset;
				solution.count = 2;
				return solution;
			}
		} else
		{
			// a = 0, then actually a 2nd degree equation:
			// form : ax2 + bx + c = 0;
			a = b;
			b = c;
			c = d;
			if (Math.abs(a) <= zeroMax)
			{
				if (Math.abs(b) <= zeroMax) return null;
				else 
				{
					solution.s1 = -c / b;
					solution.count = 1;
					return solution;
				}
			}
			D = b*b - 4*a*c;
			if (D <= - zeroMax) return null;
			if (D > zeroMax)
			{
				// D positive
				D = Math.sqrt(D);
				solution.s1 = ( -b - D) / (2 * a);
				solution.s2 = ( -b + D) / (2 * a);
				solution.count = 2;
				return solution;
			} else if (D < - zeroMax)
			{
				// D negative
				return null;
			} else 
			{
				// D zero
				solution.s1 = -b / (2 * a);
				solution.count = 1
				return solution;
			}
		}
	}
	
	private function getDist(x1:Number, y1:Number, x2:Number, y2:Number):Number
	{
		return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
	}
}