Bezier - Closed Loop - Animated
// forked from PESakaTFM's Bezier - Closed Loop
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.Event;
import flash.filters.ColorMatrixFilter;
import flash.geom.Point;
[SWF (backgroundColor = "0x0", frameRate = "30", width = "465", height = "465")]
public class Bezier extends Sprite
{
public const NUM_POINTS:int = 4;
public var pts:Vector.<Point> = new Vector.<Point>();
public var vel:Vector.<Point> = new Vector.<Point>();
public var val:Number = .9;
public var fade:ColorMatrixFilter = new ColorMatrixFilter([val,0,0,0,0,
0,val,0,0,0,
0,0,val,0,0,
0,0,0,1,0]);
public var bmd:BitmapData = new BitmapData(465, 465, false, 0x0);
public var bmp:Bitmap = new Bitmap(bmd);
public var mc:Sprite = new Sprite();
public function Bezier()
{
addChild(bmp);
for(var i:int=0; i<NUM_POINTS; i++)
{
pts[i] = new Point(465*Math.random() >> 0, 465*Math.random() >> 0);
vel[i] = new Point(Math.random()*8-4, Math.random()*8-4);
}
draw();
stage.addEventListener(Event.ENTER_FRAME, onEnter);
}
public function onEnter(event:Event):void
{
for(var i:int=0; i<NUM_POINTS; i++)
{
pts[i].x += vel[i].x;
if(pts[i].x > 465)
{
pts[i].x -= pts[i].x-465;
vel[i].x *= -1;
}
else if(pts[i].x < 0)
{
pts[i].x *= -1;
vel[i].x *= -1;
}
pts[i].y += vel[i].y;
if(pts[i].y > 465)
{
pts[i].y -= pts[i].y-465;
vel[i].y *= -1;
}
else if(pts[i].y < 0)
{
pts[i].y *= -1;
vel[i].y *= -1;
}
}
draw();
}
public function drawClosedLoop(pnts:Vector.<Point>, accuracy:int=20):void
{
var p:Vector.<Point> = new Vector.<Point>(3,true);
for(var i:int=0; i<pnts.length-2; i++)
{
p[0] = Point.interpolate(pnts[i], pnts[i+1], .5);
p[1] = pnts[i+1];
p[2] = Point.interpolate(pnts[i+1], pnts[i+2], .5);
drawCurve(p, accuracy);
}
p[0] = Point.interpolate(pnts[i], pnts[i+1], .5);
p[1] = pnts[i+1];
p[2] = Point.interpolate(pnts[i+1], pnts[0], .5);
drawCurve(p, accuracy);
i++;
p[0] = Point.interpolate(pnts[i], pnts[0], .5);
p[1] = pnts[0];
p[2] = Point.interpolate(pnts[0], pnts[1], .5);
drawCurve(p, accuracy);
}
public function drawCurve(pnts:Vector.<Point>, accuracy:int=20):void
{
var g:Graphics = mc.graphics;
var a:int;
var p:Point;
g.moveTo(pnts[0].x, pnts[0].y);
for(a=0; a <= accuracy; a++)
{
p = getPointAt(pnts, a/accuracy);
g.lineTo(p.x, p.y);
}
}
protected function getPointAt(pnts:Vector.<Point>, t:Number):Point
{
var n:int = pnts.length-1;
var m:Number = Math.pow((1-t), n);
var p:Point = new Point(pnts[0].x * m, pnts[0].y * m);
for(var i:int=1; i<=n; i++)
{
m = Math.pow((1-t), n-i)*bc(n, i)*Math.pow(t, i);
p = p.add(new Point(pnts[i].x * m, pnts[i].y * m));
}
return p;
}
protected function bc(n:int, k:int):int // Binomial Coefficient
{
return (f(n)/(f(k)*f(n-k)));
}
protected function f(value:int):int // Factorial
{
var i:int = value;
var result:int = 1;
for(; i>0; i--)
{
result *= i;
}
return result;
}
protected function draw():void
{
mc.graphics.clear();
mc.graphics.lineStyle(1,0xFF0000);
drawClosedLoop(pts);
mc.graphics.endFill();
bmd.applyFilter(bmd, bmd.rect, new Point(), fade);
bmd.draw(mc);
}
}
}