forked from: DotLight [Red]

by zier forked from DotLight [Red] (diff: 302)
Sprite と線の接点を調べるためのテストプログラムです。
* 手っ取り早くブレゼンハムアルゴリズムを使いたかったので
* fork させてもらいました。 2010/08/20 Zier
♥0 | Line 83 | Modified 2010-08-20 11:14:43 | MIT License
play

ActionScript3 source code

/**
 * Copyright zier ( http://wonderfl.net/user/zier )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/y9t0
 */

// forked from ProjectNya's DotLight [Red]

/*
 * Sprite と線の接点を調べるためのテストプログラムです。
 * 手っ取り早くブレゼンハムアルゴリズムを使いたかったので
 * fork させてもらいました。 2010/08/20 Zier
 */
package {
    import flash.events.MouseEvent
    import flash.display.Sprite;
    import flash.geom.Point;
    
    [SWF(backgroundColor="#000000", width="465", height="465", frameRate="30")]
    public class Main extends Sprite {

        private var block: Sprite;
        private var testLayer: Sprite;
        
        public function Main() {
            block = new Sprite();
            block.graphics.beginFill(0x808080)
            block.graphics.drawRect(-50, -20, 100, 40)
            block.graphics.endFill()
            block.x = 230
            block.y = 230
            block.rotation = 30
            addChild(block)
            
            testLayer = new Sprite();
            addChild(testLayer);
            
            stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown)
        }
        
        private function onMouseDown(e: MouseEvent): void {
            var x0: int = e.stageX
            var y0: int = e.stageY
            var x1: int = block.x
            var y1: int = block.y
            
            var p: Point = null
            Bresenham.line(x0, y0, x1, y1, function(x: int, y: int, a: Boolean): Boolean {
                if (a == block.hitTestPoint(x, y, true)) {
                    p = new Point(x, y)
                    return true;
                }
                return false;
            });
            
            testLayer.graphics.clear()
            testLayer.graphics.lineStyle(2, 0xff0000);
            testLayer.graphics.moveTo(x0, y0);
            testLayer.graphics.lineTo(p.x, p.y);
            testLayer.graphics.drawEllipse(p.x - 5, p.y - 5, 10, 10);
        }
    }
}

class Bresenham {
    // 各処理では f() に引き渡した関数を呼ぶ形
    public static function line(x0:int, y0:int, x1:int, y1:int, f: Function):void {
        var steep:Boolean = Math.abs(y1 - y0) > Math.abs(x1 - x0);
        var t:int;
        if (steep) {
            t = x0;
            x0 = y0;
            y0 = t;
            t = x1;
            x1 = y1;
            y1 = t;
        }
        // 途中で走査を中断するためのフラグを追加
        var aboutFlag: Boolean = true;
        if (x0 > x1) {
            t = x0;
            x0 = x1;
            x1 = t;
            t = y0;
            y0 = y1;
            y1 = t;
            // 指定した二点の位置関係によっては走査を逆転し最適化を行っているのですね
            // なので、開始と終了を意識しない場合の走査自体は効率的。
            // ただ、開始から終了を明確に意識する処理が行いたい場合にはロジック外で考慮が必要となる。
            // 今回、aboutFlag を反転して f() に引き渡して対応したが、方向を意識する処理ならば
            // 素直に開始から終了を走査するコードを書いた方が良いか?
            aboutFlag = false;
        }
        var dx:int = x1 - x0;
        var dy:int = Math.abs(y1 - y0);
        var e:int = dx*0.5;
        var ys:int = (y0 < y1) ? 1 : -1;
        var y:int = y0;
        for (var x:int = x0; x <= x1; x++) {
            if (steep) {
                if (f(y, x, aboutFlag)) return;
            } else {
                if (f(x, y, aboutFlag)) return;
            }
            e = e - dy;
            if (e < 0) {
                y = y + ys;
                e = e + dx;
            }
        }
    }
}