package {
import com.bit101.components.CheckBox;
import flash.display.Sprite;
import flash.events.Event;
import flash.utils.getTimer;
/**
* Explicit metaballs experiment.
*/
[SWF(backgroundColor="#FFFFFF")]
public class CassiniTest extends Sprite {
public var cb:CheckBox;
public var c1:Cassini = new Cassini;
public var c2:CassiniMod = new CassiniMod;
public function CassiniTest () {
cb = new CheckBox (this, 10, 10, "MODIFIED");
addEventListener (Event.ENTER_FRAME, loop);
}
public function loop (e:Event):void {
var a:Number = 1 + Math.sin (2e-3 * getTimer ());
var c:Cassini = cb.selected ? c2 : c1;
var ranges:Vector.<Range> = c.ranges (a);
graphics.clear ();
graphics.lineStyle (2);
var t:int, X:Number, Y:Number;
for each (var range:Range in ranges) {
// positive
X = range.x (0);
graphics.moveTo (232 + 75 * X, 232);
for (t = 1; t < 101; t++) {
X = range.x (t / 100);
Y = c.y (X, a);
graphics.lineTo (232 + 75 * X, 232 - 75 * Y);
}
// negative
X = range.x (0);
graphics.moveTo (232 + 75 * X, 232);
for (t = 1; t < 101; t++) {
X = range.x (t / 100);
Y = c.y (X, a);
graphics.lineTo (232 + 75 * X, 232 + 75 * Y);
}
}
}
}
}
class Range {
public var a:Number;
public var b:Number;
public function Range (from:Number, to:Number) {
a = from; b = to;
}
public function x (t:Number):Number {
return a + (b - a) * t;
}
}
/**
* Cassini oval, a=0..2, b=1.
* @see http://paulbourke.net/geometry/egg/
*/
class Cassini {
public function y (x:Number, a:Number, b:Number = 1):Number {
var a2:Number = a * a, x2:Number = x * x;
var D:Number = Math.max (0, 4 * a2 * x2 + b * b);
var D2:Number = Math.max (0, Math.sqrt (D) - a2 - x2);
return Math.sqrt (D2);
}
/**
* Assumes b=1.
*/
public function ranges (a:Number):Vector.<Range> {
var a2:Number = a * a;
var D:Number = a2 - 1, D2:Number = a2 + 1;
if (D > 0) {
return new <Range> [
new Range ( -Math.sqrt (D2), -Math.sqrt (D)),
new Range ( +Math.sqrt (D), +Math.sqrt (D2))
];
}
return new <Range> [
new Range ( -Math.sqrt (D2), +Math.sqrt (D2))
];
}
}
/**
* Modified Cassini oval.
*/
class CassiniMod extends Cassini {
override public function y (x:Number, a:Number, ignore:Number = 1):Number {
return super.y (x, a, 1 + (a * a + a) / 4);
}
override public function ranges (a:Number):Vector.<Range> {
var a2:Number = a * a;
var D:Number = 3 * a2 - a - 4, D2:Number = 5 * a2 + a + 4;
if (D > 0) {
return new <Range> [
new Range ( -0.5 * Math.sqrt (D2), -0.5 * Math.sqrt (D)),
new Range ( +0.5 * Math.sqrt (D), +0.5 * Math.sqrt (D2))
];
}
return new <Range> [
new Range ( -0.5 * Math.sqrt (D2), +0.5 * Math.sqrt (D2))
];
}
}