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: Illustrotor風ペンツール ver.6(未完成)

ver.3:3次ベジェ曲線を再現
ver.4:始点-終点を結ぶと閉じる
ver.5:閉じたあとにアンカーとハンドルが操作可能
今回はさらにアンカーポイントを追加できるようにする
Get Adobe Flash player
by taka_milk 26 Nov 2009
    Embed
/**
 * Copyright taka_milk ( http://wonderfl.net/user/taka_milk )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/aHvD
 */

// forked from KoheiTAKAMIYA's Illustrotor風ペンツール ver.6(未完成)
// forked from KoheiTAKAMIYA's Illustrotor風ペンツール ver.5
// forked from KoheiTAKAMIYA's Illustrotor風ペンツール ver.4
// forked from KoheiTAKAMIYA's Illustrotor風ペンツール ver.3
// forked from KoheiTAKAMIYA's Illustrotor風ペンツール ver.2
// forked from KoheiTAKAMIYA's Illustrotor風ペンツール ver.1

//ver.3:3次ベジェ曲線を再現
//ver.4:始点-終点を結ぶと閉じる
//ver.5:閉じたあとにアンカーとハンドルが操作可能
//今回はさらにアンカーポイントを追加できるようにする

package{
    import flash.display.Sprite;
    import flash.geom.Point;
    import flash.events.MouseEvent;
    import flash.text.TextField;
    
    public class PenTool extends Sprite{
        private var bezierPointStage:Sprite = new Sprite();
        private var bezierCurve:BezierCurveDrawer = new BezierCurveDrawer();
        private var txt:TextField = new TextField();
        private var targetIndex:uint;
        private var targetType:String;
        
        public function PenTool(){
            addChild(bezierCurve);
            addChild(bezierPointStage);
            addChild(txt);
            txt.width = 400;
            txt.height = 20;
            stage.addEventListener(MouseEvent.MOUSE_DOWN, addBezierPoint);
        }
        
        private function addBezierPoint(event:MouseEvent):void{
            switch(event.type){
                case MouseEvent.MOUSE_DOWN:
                    if(bezierCurve.finalize){
                        targetIndex = 0;
                        txt.text = "ベジェ曲線を閉じました。";
                        stage.removeEventListener(MouseEvent.MOUSE_DOWN, addBezierPoint);
                        bezierCurve.push(bezierCurve.getIndexAt(0));
                        bezierCurve.getIndexAt(0).anchor.removeEventListener(MouseEvent.ROLL_OVER, finalizeBezier);
                        bezierCurve.getIndexAt(0).anchor.removeEventListener(MouseEvent.ROLL_OUT, finalizeBezier);
                    }
                    else {
                        targetIndex = bezierCurve.length; 
                        var bezierPoint:BezierPoint = new BezierPoint(new Point(mouseX, mouseY));
                        bezierCurve.push(bezierPoint);
                        if(!targetIndex) {
                            bezierPoint.anchor.addEventListener(MouseEvent.ROLL_OVER, finalizeBezier);
                            bezierPoint.anchor.addEventListener(MouseEvent.ROLL_OUT, finalizeBezier);
                        }
                        bezierPointStage.addChild(bezierPoint);
                    }

                    stage.addEventListener(MouseEvent.MOUSE_MOVE, moveBezierPoint);
                    stage.addEventListener(MouseEvent.MOUSE_UP,
                        function defineBezierPoint():void{
                            if(bezierCurve.finalize) {
                                bezierCurve.addBezierCurveEvent(MouseEvent.ROLL_OVER, addBezierPoint);
                                bezierCurve.addBezierCurveEvent(MouseEvent.ROLL_OUT, addBezierPoint);
                                bezierCurve.addBezierCurveEvent(MouseEvent.CLICK, addBezierPoint);
                                bezierCurve.addBezierPointEvent(MouseEvent.ROLL_OVER, moveBezierPoint);
                                bezierCurve.addBezierPointEvent(MouseEvent.ROLL_OUT, moveBezierPoint);
                                bezierCurve.addBezierPointEvent(MouseEvent.MOUSE_DOWN, moveBezierPoint);
                            }
                            txt.text = "";
                            stage.removeEventListener(MouseEvent.MOUSE_MOVE, moveBezierPoint);
                        }
                    );
                break;
                case MouseEvent.CLICK:
                    txt.text = "アンカーポイント追加しました。";
                break;
                case MouseEvent.ROLL_OVER:
                    txt.text = "アンカーポイント追加します。";
                break;
                case MouseEvent.ROLL_OUT:
                    txt.text = "";
                break;
            }
        }
        
        private function moveBezierPoint(event:MouseEvent):void{
            var targetPoint:BezierPoint = bezierCurve.getIndexAt(targetIndex);
            switch(event.type){
                case MouseEvent.MOUSE_MOVE:
                    var f:Number = -targetPoint.f(targetType);
                    //if(inFinite(f))) f = -1;
                    txt.text = String(f);
                    //if(KeyboardEvent.altKey) txt.text = "alt";
                    switch(targetType){
                        case "anchor":
                            bezierCurve.setIndexAt(new Point(mouseX, mouseY), null, null, targetIndex);
                        break;
                        case "handleA":
                            //bezierCurve.setIndexAt(null, new Point(mouseX, mouseY), null, targetIndex);), targetIndex);
                            if(isFinite(f)) bezierCurve.setIndexAt(null,  new Point(mouseX, mouseY), Point.interpolate(targetPoint.handleAPoint, targetPoint.anchorPoint, f), targetIndex);
                        break;
                        case "handleB":
                            //bezierCurve.setIndexAt(null, null, new Point(mouseX, mouseY), targetIndex);
                            if(isFinite(f)) bezierCurve.setIndexAt(null, Point.interpolate(targetPoint.handleBPoint, targetPoint.anchorPoint, f), new Point(mouseX, mouseY), targetIndex);
                        break;
                        
                        default:
                            bezierCurve.setIndexAt(null,new Point(mouseX, mouseY),Point.interpolate(targetPoint.handleAPoint, targetPoint.anchorPoint, -1), targetIndex);
                        break;
                    }
                    
                break;
                case MouseEvent.MOUSE_DOWN:
                    stage.addEventListener(MouseEvent.MOUSE_MOVE, moveBezierPoint);
                    stage.addEventListener(MouseEvent.MOUSE_UP,
                        function removeEvent():void{
                            event.target.removeEventListener(MouseEvent.MOUSE_MOVE, moveBezierPoint);
                        }
                    );
                break;
                case MouseEvent.ROLL_OVER:
                    txt.text = event.target.type;
                    targetType = event.target.type;
                    targetIndex = bezierCurve.indexOf(event.target.parent as BezierPoint);
                break;
                case MouseEvent.ROLL_OUT:
                    txt.text = "";
                break;
                
            }
            event.updateAfterEvent();
        }
        private function finalizeBezier(event:MouseEvent):void{
            if(targetIndex) {
                switch(event.type){
                    case MouseEvent.ROLL_OVER:
                        txt.text = "ベジェ曲線を閉じます。";
                        bezierCurve.finalize = true;
                    break;
                    case MouseEvent.ROLL_OUT:
                        txt.text = "";
                        bezierCurve.finalize = false;
                    break;
                }
            }
        }
    }  
}


import flash.geom.Point;
import flash.display.Sprite;

//---------
//3次ベジェ曲線を繋げてグラフィックを描くクラス
class BezierCurveDrawer extends Sprite{
    private var _pointArray:Array = new Array(); //BezierPointを格納する変数
    private var _curveArray:Array = new Array(); //BezierCurveを格納する変数
    public var finalize:Boolean = false;         //BezierCurveの開閉を監視
    
    public function BezierCurveDrawer(){
    }
    public function indexOf(bezierPoint:BezierPoint):int{
        return _pointArray.indexOf(bezierPoint);
    }
     public function indexOfCurve(bezierCurve:BezierCurve):int{
        return _curveArray.indexOf(bezierCurve);
    }
    public function getIndexAt(_index:uint):BezierPoint{
        return _pointArray[_index];
    }
    public function setIndexAt(_anchor:Point, _handleA:Point, _handleB:Point, _index:uint):void{
        if(_index < length){
            if(_anchor)  _pointArray[_index].anchorPoint  = _anchor;
            if(_handleA) _pointArray[_index].handleAPoint = _handleA;
            if(_handleB) _pointArray[_index].handleBPoint = _handleB;
        
            var prev:int = _index > 0 ? _index-1 : finalize ? length-1 : -1;
            var next:int = !finalize ? -1 : _index < length ? _index : 0;
            if(_curveArray[prev]) {
                _curveArray[prev].setPoint(null, null, _pointArray[_index].handleBPoint, _pointArray[_index].anchorPoint);
                _curveArray[prev].draw();
            }
            if(_curveArray[next]){
                _curveArray[next].setPoint(_pointArray[_index].anchorPoint, _pointArray[_index].handleAPoint, null, null);
                _curveArray[next].draw();
            }
        }
    }
    
    //イベント
    public function addBezierPointEvent(type:String, listener:Function):void{
        for each(var bezierPoint:BezierPoint in _pointArray){
            bezierPoint.anchor.addEventListener(type,listener);
            bezierPoint.handleA.addEventListener(type,listener);
            bezierPoint.handleB.addEventListener(type,listener);
        }
    }
    public function removeBezierPointEvent(type:String, listener:Function):void{
        for each(var bezierPoint:BezierPoint in _pointArray){
            bezierPoint.anchor.removeEventListener(type,listener);
            bezierPoint.handleA.removeEventListener(type,listener);
            bezierPoint.handleB.removeEventListener(type,listener);
        }
    }
    public function addBezierCurveEvent(type:String, listener:Function):void{
        for each(var bezierCurve:BezierCurve in _curveArray){
            bezierCurve.addEventListener(type,listener);
        }
    }
    
    
    public function push(bezierPoint:BezierPoint):void{
        if(length) {
            var bezierCurve:BezierCurve = new BezierCurve(_pointArray[length-1].anchorPoint, _pointArray[length-1].handleAPoint,
                                                          bezierPoint.handleBPoint, bezierPoint.anchorPoint);
            addChild(bezierCurve);
            _curveArray.push(bezierCurve);
        }
        if(!finalize) _pointArray.push(bezierPoint);
    }
    public function get length():uint{
        return _pointArray.length;
    }
}

//---------
//4点で3次ベジェ曲線の計算・描画クラス
class BezierCurve extends Sprite{ 
    public var a:Point; //anchorA 
    public var b:Point; //handleA 
    public var c:Point; //handleB 
    public var d:Point; //anchorB 
     
    public function BezierCurve(a:Point, b:Point, c:Point, d:Point){ 
        this.a = a; 
        this.b = b; 
        this.c = c; 
        this.d = d;
        draw();
    }
    public function setPoint(a:Point, b:Point, c:Point, d:Point):void{
        if(a) this.a = a; 
        if(b) this.b = b; 
        if(c) this.c = c; 
        if(d) this.d = d;
    }
     
    public function draw():void{ 
        graphics.clear(); 
        graphics.lineStyle(3,0x666666); 
        graphics.moveTo(a.x, a.y); 
        for each(var bezierPoint:Point in BezierCurve.bezierValues(a,b,c,d,20)){ 
            graphics.lineTo(bezierPoint.x,bezierPoint.y); 
        } 
    } 
      
    public static function bezierValue(a:Point, b:Point, c:Point, d:Point,t:Number):Point{ 
        if(t < 0 || t > 1) return null; 
        var _p4:Point = Point.interpolate(b, a, t); 
        var _p5:Point = Point.interpolate(c, b, t); 
        var _p6:Point = Point.interpolate(d, c, t); 
        var _p7:Point = Point.interpolate(_p5, _p4, t); 
        var _p8:Point = Point.interpolate(_p6, _p5, t); 
        return Point.interpolate(_p8, _p7, t); 
    } 
     
    public static function bezierValues(a:Point, b:Point, c:Point, d:Point,_quality:uint = 10):Array{ 
        if(a.equals(d)) return [a]; 
         
        var valueArray:Array = new Array();  
        for(var i:uint = 0; i <= _quality; i++){  
            valueArray.push(bezierValue(a,b,c,d,i/_quality));  
        }  
        return valueArray; 
    }   
}

//---------
//アンカー,ハンドルA,ハンドルBを格納したクラス
class BezierPoint extends Sprite{
    private var _anchor:PointSprite;
    private var _handleA:PointSprite;
    private var _handleB:PointSprite;
    
    public function BezierPoint(_anchor:Point){
        anchorPoint = _anchor;
    }
    
    private function drawLine():void{
        graphics.clear();
        graphics.lineStyle(1,0x00ffff);
        if(_handleA){
            graphics.moveTo(anchor.x, anchor.y);
            graphics.lineTo(handleA.x, handleA.y);
        }
        if(_handleB){
            graphics.moveTo(anchor.x, anchor.y);
            graphics.lineTo(handleB.x, handleB.y);
        }
    }
    public function f(_handle:String):Number{
        if(_handle == "handleA") {
            //if(anchorPoint.equals(handleAPoint)) return -1;//Point.distance(anchorPoint, handleBPoint);
            return Point.distance(anchorPoint, handleBPoint)/Point.distance(anchorPoint, handleAPoint);
        }else if(_handle == "handleB") {
            //if(anchorPoint.equals(handleBPoint)) return Point.distance(anchorPoint, handleAPoint);
            return Point.distance(anchorPoint, handleAPoint)/Point.distance(anchorPoint, handleBPoint);
        }else return 0;
    }
    
    //プロパティ
    //anchor
    public function set anchorPoint(_point:Point):void{
        if(!_anchor){
            _anchor = new PointSprite(_point, "anchor");
            addChild(_anchor);
        }
        else{
            var subPoint:Point = _point.subtract(_anchor.point);
            _anchor.drawPoint(_point);
            if(_handleA) _handleA.drawPoint(_handleA.point.add(subPoint));
            if(_handleB) _handleB.drawPoint(_handleB.point.add(subPoint));
            drawLine();
        }
    }
    public function get anchorPoint():Point{
        return _anchor.point;
    }
    public function get anchor():Sprite{
        return _anchor as Sprite;
    }
    
    //handleA
    public function set handleAPoint(_point:Point):void{
        if(!_handleA) {
            _handleA = new PointSprite(_point, "handleA");
            addChild(_handleA);
        }
        else {
            _handleA.drawPoint(_point);
        }
        drawLine();
    }
    public function get handleAPoint():Point{
        if(_handleA) return _handleA.point;
        return _anchor.point;
    }
    public function get handleA():Sprite{
        if(_handleA) return _handleA;
        return _anchor;
    }
    
    //handleB
    public function set handleBPoint(_point:Point):void{
        if(!_handleB) {
            _handleB = new PointSprite(_point, "handleB");
            addChild(_handleB)
        }
        else {
            _handleB.drawPoint(_point);
        }
        drawLine();
    }
    public function get handleBPoint():Point{
        if(_handleB) return _handleB.point;
        return _anchor.point;
    }
    public function get handleB():Sprite{
        if(_handleA) return _handleB;
        return _anchor;
    }
}

//---------
//アンカー,ハンドルの描画用クラス
class PointSprite extends Sprite{
    public var point:Point;
    public var alt:Boolean = false;
    
    private var _type:String;
    private var _color:uint;
    private var _thick:uint;
    private var _shape:String;
    
    public function PointSprite(_point:Point, _type:String){
        type = _type; //"anchor" or "handle"
        drawPoint(_point);
    }
    
    public function drawPoint(_point:Point = null):void{
        if(_point) point = _point.clone();
        graphics.clear();
        graphics.lineStyle(_thick,_color);
        graphics.beginFill(0xffffff);
        if(_shape == "rect") graphics.drawRect(point.x-2, point.y-2, 4, 4);
        else graphics.drawCircle(point.x, point.y, 2);
        graphics.endFill();
    }
    
    public function set type(_type:String):void{
        this._type = _type;
        switch(_type){
            case "anchor":
                _color = 0x00ffff;
                _thick = 1;
                _shape = "rect";
            break;
            case "handleA":
            case "handleB":
                _color = 0x00ffff;
                _thick = 1;
                _shape = "circle";
            break;
        }
    }
    public function get type():String{
        return _type;
    }
    
    public override function get x():Number{
        return point.x;
    }
    public override function get y():Number{
        return point.y;
    }
}