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: forked from: Sprite Link Test

Sprite の Link と接点の修飾を行うテストコード 2010/08/20

今後 DisplayObject の Link に対する ArrowShape クラスなりを用意して
Tail / Head の描画を柔軟に切り替えられれば実用度も高まりそう?

グラフの各要素に対する制御は Flash だと意識しなくても DisplayObject を
ベースにすれば事足りそう。他の言語使うより、こりゃ楽だわw
この手の有向グラフに対する線の描画補助って、需要あったりするのだろうか?

今の crossPoint チェックは使える方法をとりあえず書いているが、やや冗長だろうか?
事前の距離から、矩形に近い2辺は解るから、わざわざ4辺すべてをチェックする必要はないか・・・

回転された図形や、表面がデコボコの図形に対しては、接点を簡単に求める方法が
あるだろうか?ブレゼンハムで線分の hitTest を行うのが一つの方法?

接点の修飾に関しては、同じ接続の場合、線の集約も考える必要が有るだろうか?
集約すると表現としてマズい場合もあるだろうから、可変できる必要もあるだろう。
いろいろ考えるとムツカシイ ^^;
Get Adobe Flash player
by zier 19 Aug 2010
/**
 * Copyright zier ( http://wonderfl.net/user/zier )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/7Qch
 */

// forked from zier's forked from: Sprite Link Test
// forked from zier's Sprite Link Test
package {
/* Sprite の Link と接点の修飾を行うテストコード 2010/08/20
 * 
 * 今後 DisplayObject の Link に対する ArrowShape クラスなりを用意して
 * Tail / Head の描画を柔軟に切り替えられれば実用度も高まりそう?
 * 
 * グラフの各要素に対する制御は Flash だと意識しなくても DisplayObject を
 * ベースにすれば事足りそう。他の言語使うより、こりゃ楽だわw
 * この手の有向グラフに対する線の描画補助って、需要あったりするのだろうか?
 *
 * 今の crossPoint チェックは使える方法をとりあえず書いているが、やや冗長だろうか?
 * 事前の距離から、矩形に近い2辺は解るから、わざわざ4辺すべてをチェックする必要はないか・・・
 *
 * 回転された図形や、表面がデコボコの図形に対しては、接点を簡単に求める方法が
 * あるだろうか?ブレゼンハムで線分の hitTest を行うのが一つの方法?
 *
 * 接点の修飾に関しては、同じ接続の場合、線の集約も考える必要が有るだろうか?
 * 集約すると表現としてマズい場合もあるだろうから、可変できる必要もあるだろう。
 * いろいろ考えるとムツカシイ ^^;
 */

    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    
    [SWF(width = 400, height = 400, frameRate = 30)]
    public class FlashTest extends Sprite {
        private function createRectangle(c: uint, x: Number, y: Number, w: Number, h: Number): Sprite {
            var result: Sprite = new DraggableSprite();
            with (result.graphics) {
                beginFill(c)
                drawRect(- w / 2, - h / 2, w, h)
                endFill()
            }
            
            result.x = x
            result.y = y
            return result
        }
        
        public function FlashTest() {
            var rect1: Sprite = createRectangle(0x00A0FF, 100, 150, 50, 50)
            var rect2: Sprite = createRectangle(0xA0FF00, 300, 200, 100, 20)
            var rect3: Sprite = createRectangle(0xFFA000, 100, 250, 70, 40)
            
            addChild(rect1)
            addChild(rect2)
            addChild(rect3)
            
            rect1.rotation += 45
            rect2.rotation += 30
            rect3.rotation += 20
            
            addChild(new LinkTest(rect1, rect2))
            addChild(new LinkTest(rect3, rect2))
        }
    }
}

import flash.display.Graphics;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;

class Utils {
    
    public static function drawRectangle(g: Graphics, b: int , c: uint, r: Rectangle): void {
        g.lineStyle(b, c)
        g.drawRect(r.left, r.top, r.right - r.left, r.bottom - r.top)
    }

    // 2つの矩形の中心点を通る線分の交点を求める 式は http://hakuhin.jp/as/collision.html 参照
    public static function crossPoint(tail: DisplayObject, head: DisplayObject): Point {
        var p: Point = new Point(tail.x, tail.y)
        var dx: Number = head.x - tail.x
        var dy: Number = head.y - tail.y
        
        function t(ax: Number, ay: Number, bx: Number, by: Number): Number {
            var abx: Number = bx - ax;
            var aby: Number = by - ay;
            var nx: Number = -aby;
            var ny: Number =  abx;
            
            var length: Number = Math.sqrt((nx * nx) + (ny * ny));
            if (length > 0) length = 1 / length;
            nx *= length;
            ny *= length;
            
            var d: Number = -(ax * nx + ay * ny);
            return -(nx * p.x + ny * p.y + d) / (nx * dx + ny * dy);
        }
        
        var d2: Point = new Point(head.width / 2, head.height / 2);
        
        var t1: Number = t(head.x - d2.x, head.y - d2.y, head.x - d2.x, head.y + d2.y)
        var t2: Number = t(head.x - d2.x, head.y - d2.y, head.x + d2.x, head.y - d2.y)
        var t3: Number = t(head.x + d2.x, head.y + d2.y, head.x - d2.x, head.y + d2.y)
        var t4: Number = t(head.x + d2.x, head.y + d2.y, head.x + d2.x, head.y - d2.y)
        
        var _t: Number = 0
        if (_t < t1 && t1 <= 1) _t = t1
        if (_t < t2 && t2 <= 1) _t = t2
        if (_t < t3 && t3 <= 1) _t = t3
        if (_t < t4 && t4 <= 1) _t = t4
        
        return new Point(p.x + dx * _t, p.y + dy * _t)
    }
}

// 掴める Sprite
class DraggableSprite extends Sprite {
    public static const DRAGGING: String = "dragging"
    public static const COMPLETE: String = "complete"
    public static const REFRESH: String = "refresh"
    
    function DraggableSprite() {
        this.addEventListener(MouseEvent.MOUSE_DOWN, function(): void {
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove)
            stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp)
        });
    }
    
    private function onMouseMove(e: MouseEvent): void {
        this.x = e.stageX
        this.y = e.stageY
        dispatchEvent(new Event(DRAGGING));
        dispatchEvent(new Event(REFRESH));
    }
    
    private function onMouseUp(e: MouseEvent): void {
        this.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove)
        this.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp)
        dispatchEvent(new Event(COMPLETE));
        dispatchEvent(new Event(REFRESH));
    }
}


class LinkTest extends Sprite {
    private var tail: Sprite = null;
    private var head: Sprite = null;
    
    function LinkTest(aTail: Sprite, aHead: Sprite) {
        link(aTail, aHead)
        onRefresh()
    }
    
    public function link(aTail: Sprite, aHead: Sprite): void {
        unlink()
        tail = aTail
        head = aHead
        if (null != tail) tail.addEventListener(DraggableSprite.REFRESH, onRefresh)
        if (null != head) head.addEventListener(DraggableSprite.REFRESH, onRefresh)
    }

    public function unlink(): void {
        if (null != tail) tail.removeEventListener(DraggableSprite.REFRESH, onRefresh)
        if (null != head) head.removeEventListener(DraggableSprite.REFRESH, onRefresh)
        tail = null
        head = null
    }
    
    public function onRefresh(e: Event = null): void {
        graphics.clear()
        graphics.lineStyle(1, 0)
        // graphics.moveTo(tail.x, tail.y)
        // graphics.lineTo(head.x, head.y)
        
        // draw head cross point
        var hp: Point = Utils.crossPoint(tail, head)
        // graphics.drawCircle(hp.x, hp.y, 2)

        function drawHeadTest(p: Point, base: DisplayObject): Point {
            // 接点P と矢印の元となる座標から向きを求め単位を整える
            var dp: Point = hp.subtract(new Point(base.x, base.y))
            dp.normalize(1)
            
            // 描画をごにょごにょ            
            var radius: int = 5
            var ec: Point = new Point(p.x - dp.x * radius, p.y - dp.y * radius)
            graphics.drawEllipse(ec.x - radius, ec.y - radius, radius * 2, radius * 2)
            
            var top: Point = new Point(p.x - dp.x * radius * 2, p.y - dp.y * radius * 2)
            var support: Point = new Point(top.x - dp.x * 20, top.y - dp.y * 20)
            var root: Point = new Point(top.x - dp.x * 15, top.y - dp.y * 15)
            
            graphics.moveTo(top.x, top.y)
            graphics.lineTo(support.x + dp.y * 6, support.y - dp.x * 6)
            graphics.lineTo(root.x, root. y)
            graphics.lineTo(support.x - dp.y * 6, support.y + dp.x * 6)
            graphics.lineTo(top.x, top.y)
            
            // 矢印の終端点を返す
            return root
        }
        var ep: Point = drawHeadTest(hp, tail)
        
        
        // draw tail cross point
        var tp: Point = Utils.crossPoint(head, tail)
        // graphics.drawCircle(tp.x, tp.y, 3)
        
        function drawTailTest(p: Point, base: DisplayObject): Point {
            var dp: Point = hp.subtract(new Point(base.x, base.y))
            dp.normalize(1)
            
            var cp: Point = new Point(p.x - dp.x * 10, p.y - dp.y * 10)
            var root: Point = new Point(p.x - dp.x * 20, p.y - dp.y * 20)
            
            graphics.moveTo(p.x, p.y)
            graphics.lineTo(cp.x + dp.y * 5, cp.y - dp.x * 5)
            graphics.lineTo(root.x, root.y)
            graphics.lineTo(cp.x - dp.y * 5, cp.y + dp.x * 5)
            graphics.lineTo(p.x, p.y)
            
            return root
        }
        var sp: Point = drawTailTest(tp, head)
        
        // tail と head を結ぶ shaft の描画 この方法だと曲線でも使えそう?
        graphics.moveTo(sp.x, sp.y)
        graphics.lineTo(ep.x, ep.y)
        
        // frame
        Utils.drawRectangle(graphics, 1, 0xFF0000, tail.getRect(this))
        Utils.drawRectangle(graphics, 1, 0xFF0000, head.getRect(this))
    }
}