package ae {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
class Circle extends Sprite
{
//width
public var w:Number;
//height
public var h:Number;
//radius
public var r:Number;
//radius / 2
public var r2:Number;
//color
public var c:int;
// interpolation factor
private var t:Number = 0;
// time step
private var step:Number = 0.06;
public var node:CircleNode;
public static var cs:CircleSplit;
public function Circle(_w:Number, _h:Number, _cs:CircleSplit = null)
{
super();
w = _w;
h = _h;
r = w/2;
r2 = r/2;
if (_cs != null)
Circle.cs = _cs;
}
public function setColor() : void
{
if (Circle.cs.pic == null)
{
//generate a random color that's not too dark
var red:int = int(Math.random() * 224) + 32;
var g:int = int(Math.random() * 224) + 32;
var b:int = int(Math.random() * 224) + 32;
c = (red << 16) + (g << 8) + b;
return;
}
//sample the pic
var xm:int = x+r;
var ym:int = y+r;
var c1:int = Circle.cs.pic.getPixel32(int(xm-r2), int(ym-r2));
var c2:int = Circle.cs.pic.getPixel32(int(xm+r2), int(ym-r2));
var c3:int = Circle.cs.pic.getPixel32(int(xm-r2), int(ym+r2));
var c4:int = Circle.cs.pic.getPixel32(int(xm+r2), int(ym+r2));
var cm:int = Circle.cs.pic.getPixel32(int(xm), int(ym));
c = averageColor(new Array(c1, c2, c3, c4, cm, cm) );
}
private function averageColor(a:Array):int
{
var rt:int = 0;
var gt:int = 0;
var bt:int = 0;
for each(var cc:int in a)
{
rt += (cc >> 16) & 0xFF;
gt += (cc >> 8) & 0xFF;
bt += (cc >> 0) & 0xFF;
}
return ((rt/a.length) << 16) + ((gt/a.length) << 8) + (bt/a.length);
}
private function handleFrame(e:Event)
{
if (t >= 1)
{
// we're done animating
removeEventListener(Event.ENTER_FRAME, handleFrame);
split();
}
else
{
t += step;
draw();
}
}
// draw 4 circles (while animating)
// animate by interpolating the x,y coords and radius
public function draw():void
{
this.graphics.clear();
// blank the bg behind the original circle
// this happens after the first step to avoid a flicker
if (t == step)
(this.parent as CircleSplit).drawSquare(this);
this.graphics.beginFill(c);
this.graphics.drawCircle(lerp(r, r-r2, t) , lerp(r, r-r2, t), lerp(r, r2, t));
this.graphics.endFill();
this.graphics.beginFill(c);
this.graphics.drawCircle(lerp(r, r-r2, t) , lerp(r, r+r2, t), lerp(r, r2, t));
this.graphics.endFill();
this.graphics.beginFill(c);
this.graphics.drawCircle(lerp(r, r+r2, t) , lerp(r, r-r2, t), lerp(r, r2, t));
this.graphics.endFill();
this.graphics.beginFill(c);
this.graphics.drawCircle(lerp(r, r+r2, t) , lerp(r, r+r2, t), lerp(r, r2, t));
this.graphics.endFill();
}
public function handleMouseOver(e:MouseEvent)
{
// dont split if the mouse button is down
if(e.buttonDown) return;
// if we're already animating, don't do anything
if(t > 0) return;
// still have to do a hitTest
if ( !hitTest(e) ) return;
// start recieveving frame events to animate
addEventListener(Event.ENTER_FRAME, handleFrame);
this.graphics.clear();
}
// check to see if the mouse is actually inside the circle;
private function hitTest(e:MouseEvent) : Boolean
{
var dx:Number = Math.abs(x+r - e.stageX);
var dy:Number = Math.abs(y+r - e.stageY);
var dist = Math.sqrt(dx*dx +dy*dy);
return dist <= r;
}
// split into 4 sub-circles/nodes
public function split():void
{
//create the 4 child Circles
var c1:Circle = new Circle(r, r);
var c2:Circle = new Circle(r, r);
var c3:Circle = new Circle(r, r);
var c4:Circle = new Circle(r, r);
// the global midlines of the circle
var ymid:Number = y+r;
var xmid:Number = x+r;
// set up their coords
c1.x = x; c1.y = y;
c2.x = xmid; c2.y = y;
c3.x = x; c3.y = ymid;
c4.x = xmid; c4.y = ymid;
c1.setColor(); c2.setColor(); c3.setColor(); c4.setColor();
// create the assicated tree nodes
var cn1:CircleNode = new CircleNode(c1);
var cn2:CircleNode = new CircleNode(c2);
var cn3:CircleNode = new CircleNode(c3);
var cn4:CircleNode = new CircleNode(c4);
// set the thresholds on the nodes
cn1.xThresh = xmid - r2;
cn1.yThresh = ymid - r2;
cn2.xThresh = xmid + r2;
cn2.yThresh = ymid - r2;
cn3.xThresh = xmid - r2;
cn3.yThresh = ymid + r2;
cn4.xThresh = xmid + r2;
cn4.yThresh = ymid + r2;
// set up the tree
node.addChildren(cn1, cn2, cn3, cn4);
// draw the new circles
(this.parent as CircleSplit).addCircles(new Array(c1, c2, c3, c4));
// this circle is no longer needed, remove all references to it
node.parentCircle = null;
node = null;
this.parent.removeChild(this);
}
// standard linear interpolation function
private function lerp(a:Number, b:Number, t:Number) : Number
{
return a * (1-t) + b * t;
}
}
}