flash on 2012-1-19
/**
* Copyright numeric ( http://wonderfl.net/user/numeric )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/2dSq
*/
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextFormat;
import flash.text.TextField;
import flash.display.Shape;
import flash.ui.Keyboard;
public class CubicBezier extends Sprite {
private var _p0:ControlPoint;
private var _p1:ControlPoint;
private var _p2:ControlPoint;
private var _p3:ControlPoint;
private var _t:Number = 0.0;
private var _bezierDrawn:Boolean = false;
private var _layer:Sprite;
private var _curve:Shape;
private var _top:Sprite;
private var _out:TextField;
private var _step:Number = 0.01;
public function CubicBezier() {
Key.initialize(stage);
_p0 = new ControlPoint(0xff0000);
_p1 = new ControlPoint(0x00ff00);
_p2 = new ControlPoint(0x0000ff);
_p3 = new ControlPoint(0xffff00);
_p0.x = 20;
_p0.y = 200;
_p1.x = 40;
_p1.y = 20;
_p2.x = 80;
_p2.y = 200 - 20;
_p3.x = 800 - 20;
_p3.y = _p0.y;
_top = new Sprite();
_top.addChild(_p0);
_top.addChild(_p1);
_top.addChild(_p2);
_top.addChild(_p3);
_curve = new Shape();
addChild(_curve);
_layer = new Sprite();
addChild(_layer);
addChild(_top);
_out = new TextField();
_out.width = stage.stageWidth;
_out.height = 70;
_out.y = stage.stageHeight - _out.height;
var format:TextFormat = new TextFormat();
format.size = 30;
_out.defaultTextFormat = format;
addChild(_out);
addEventListener(Event.ENTER_FRAME, onEachFrame);
}
private var _depth:uint = 5;
private function onEachFrame(e:Event):void {
if (!_bezierDrawn) {
if (Key.isDown(Keyboard.UP)) {
_step += 0.001;
_out.text = String(_step);
} else if (Key.isDown(Keyboard.DOWN)) {
_step -= 0.001;
_out.text = String(_step);
} else if (Key.isDown(Keyboard.SPACE)) {
_out.text = String(_step);
drawCubicBezier();
} else if (Key.isDown(Keyboard.ENTER)) {
trace("start drawing subdivision");
_out.text = String(_depth);
drawSubdivision(_p0.asPair(), _p1.asPair()
, _p2.asPair(), _p3.asPair(), _depth);
_bezierDrawn = true;
_depth += 1;
if (_depth > 12) {
_depth = 3;
}
trace("end drawing subdivision");
}
} else if (Key.isDown(Keyboard.BACKSPACE)) {
eraseAll();
}
drawCurve();
}
private function cut(p0:Pair, p1:Pair
, ratio:Number = 0.5):Pair {
return new Pair(p0.x + (p1.x - p0.x)*ratio
, p0.y + (p1.y - p0.y)*ratio);
}
private function drawCurve():void {
var p0:Pair = new Pair(_p0.x, _p0.y);
var p1:Pair = new Pair(_p1.x, _p1.y);
var p2:Pair = new Pair(_p2.x, _p2.y);
var p3:Pair = new Pair(_p3.x, _p3.y);
var p01:Pair = cut(p0, p1);
var p12:Pair = cut(p1, p2);
var p23:Pair = cut(p2, p3);
var p0112:Pair = cut(p01, p12);
var p1223:Pair = cut(p12, p23);
var c0:Pair = cut(p0, p1, 3/8.0);
var c1:Pair = cut(p0112, p1223, 1/8.0);
var c2:Pair = cut(p0112, p1223, 7/8.0);
var c3:Pair = cut(p3, p2, 3/8.0);
var a:Pair = p0;
var b:Pair = cut(c0, c1);
var c:Pair = cut(c1, c2);
var d:Pair = cut(c2, c3);
var e:Pair = p3;
_curve.graphics.clear();
_curve.graphics.lineStyle(30, 0xdddddd);
_curve.graphics.moveTo(a.x, a.y);
_curve.graphics.curveTo(c0.x, c0.y, b.x, b.y);
_curve.graphics.moveTo(b.x, b.y);
_curve.graphics.curveTo(c1.x, c1.y, c.x, c.y);
_curve.graphics.moveTo(c.x, c.y);
_curve.graphics.curveTo(c2.x, c2.y, d.x, d.y);
_curve.graphics.moveTo(d.x, d.y);
_curve.graphics.curveTo(c3.x, c3.y, e.x, e.y);
}
private function eraseAll():void {
trace('deleting all');
_t = 0.0;
_bezierDrawn = false;
removeChild(_layer);
_layer = new Sprite();
addChild(_layer);
}
private function drawBernsteinDot():void {
var x_bernstein:Number = bernstein("x", _t);
var y_bernstein:Number = bernstein("y", _t);
var dot_bernstein:Point =
new Point(x_bernstein, y_bernstein, 5, 0x001234);
_layer.addChild(dot_bernstein);
}
private function drawDeCasteljauDot():void {
var x_de:Number = deCasteljau("x", _t);
var y_de:Number = deCasteljau("y", _t);
var dot_de:Point = new Point(x_de, y_de, 3, 0xaa00ee, 0.5);
_layer.addChild(dot_de);
}
private function drawSubdivision(p0:Pair, p1:Pair
, p2:Pair, p3:Pair, depth:uint = 7):void {
if (depth == 0) {
_layer.addChild(new Point(p0.x, p0.y,1));
return;
}
var p01:Pair = cut(p0, p1);
var p12:Pair = cut(p1, p2);
var p23:Pair = cut(p2, p3);
var p012:Pair = cut(p01, p12);
var p123:Pair = cut(p12, p23);
var p0123:Pair = cut(p012, p123);
drawSubdivision(p0, p01, p012, p0123, depth - 1);
drawSubdivision(p0123, p123, p23, p3, depth - 1);
}
private function drawCubicBezier():void {
if (_t > 1) {
_t = 0.0;
_bezierDrawn = true;
}
drawBernsteinDot();
drawDeCasteljauDot();
_t += _step;
}
private function deCasteljau(what:String, t:Number):Number {
var t_:Number = 1 - t;
var p00:Number = t_*_p0[what] + t*_p1[what];
var p01:Number = t_*_p1[what] + t*_p2[what];
var p02:Number = t_*_p2[what] + t*_p3[what];
var p10:Number = t_*p00 + t*p01;
var p11:Number = t_*p01 + t*p02;
return t_*p10 + t*p11;
}
private function factorial(n:uint):uint {
var result:uint = 1;
while (n>0) {
result *= n;
n--;
}
return result;
}
private function comb(n:uint, i:uint):uint {
return factorial(n)/(factorial(i)*factorial(n - i));
}
private function bernstein_(what:String, t:Number):Number {
var t_:Number = 1 - t;
var result:Number = _p0[what]*Math.pow(t_, 3);
result += _p1[what]*3*t*Math.pow(t_, 2);
result += _p2[what]*3*Math.pow(t, 2)*t_;
result += _p3[what]*Math.pow(t, 3);
return result;
}
private function bernstein(what:String, t:Number):Number {
var tt:Number = t * t;
var ttt:Number = tt * t;
var t_:Number = 1 - t;
var tt_:Number = t_ * t_;
var ttt_:Number = tt_ * t_;
if (what != "x" && what != "y") {
what = "x";
}
return (_p0[what]*ttt_
+ _p1[what]*3*t*tt_
+ _p2[what]*3*tt*t_
+ _p3[what]*ttt);
}
}
}
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.Stage;
import flash.events.KeyboardEvent;
import flash.events.Event;
internal class ControlPoint extends Sprite {
private var _color:uint;
private var _radius:Number = 5;
private var _dragged:Boolean = false;
public function ControlPoint(color:uint = 0xff0000) {
_color = color;
var button:Shape = new Shape();
button.graphics.beginFill(_color);
button.graphics.lineStyle(2);
button.graphics.drawCircle(0, 0, _radius);
addChild(button);
addEventListener(MouseEvent.MOUSE_DOWN, beginDrag);
addEventListener(MouseEvent.MOUSE_UP, endDrag);
}
private function beginDrag(e:MouseEvent):void {
trace('start dragging');
_dragged = true;
startDrag();
}
private function endDrag(e:MouseEvent):void {
trace('drag stopped');
_dragged = false;
stopDrag();
}
public function asPair():Pair {
return new Pair(x, y);
}
}
internal class Point extends Shape {
private var _radius:Number;
private var _color:uint;
private var _alpha:Number;
public function Point(xCor:Number, yCor:Number
, radius:Number = 3, color:uint = 0x000000
, alpha:Number = 1.0) {
_radius = radius;
_color = color;
_alpha = alpha;
graphics.beginFill(_color);
graphics.lineStyle(1,_color, _alpha);
graphics.drawCircle(xCor, yCor, radius);
}
}
internal class Pair {
public var x:Number;
public var y:Number;
public function Pair(a:Number, b:Number) {
x = a;
y = b;
}
}
internal class Key {
private static var _initialized:Boolean = false;
private static var _keysDown:Object = new Object();
public static function initialize(stage:Stage):void {
if (!_initialized) {
stage.addEventListener(KeyboardEvent.KEY_DOWN
, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP
, keyReleased);
stage.addEventListener(Event.DEACTIVATE, clearKeys);
_initialized = true;
}
}
public static function isDown(keyCode:uint):Boolean {
if (!_initialized) {
throw new Error("Key.initialize() not called yet");
}
return Boolean(keyCode in _keysDown);
}
public static function isDownUnique(keyCode:uint
, ...keyCodes):Boolean {
if (!_initialized) {
throw new Error("Key.initialize() not called yet");
}
var result:Boolean = (keyCode in _keysDown);
for (var i:uint = 0; i < keyCodes.length; i++) {
var curr:uint = keyCodes[i];
if (curr != keyCode && (curr in _keysDown)) {
return false;
}
}
return result;
}
private static function keyPressed(event:KeyboardEvent):void {
_keysDown[event.keyCode] = true;
}
private static function keyReleased(event:KeyboardEvent):void {
if (event.keyCode in _keysDown) {
delete _keysDown[event.keyCode];
}
}
private static function clearKeys(event:Event):void {
_keysDown = new Object();
}
}