forked from: 直線や線分の交点を計算する

by alumican_net forked from 直線や線分の交点を計算する (diff: 2)
♥0 | Line 120 | Modified 2013-07-26 12:44:46 | MIT License
play

ActionScript3 source code

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

// forked from obanetty's 直線や線分の交点を計算する
package {
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    import flash.display.Graphics;
    public class LineTest extends Sprite {

    //マウスドラッグの始点と終点
    private var s_p:Point;
    private var e_p:Point;
    
    //描画領域
    private var canvas:Sprite;
    //四角形の四辺を格納する配列
    private var lineArray:Array;
    
    function LineTest():void{
        
        //四角形の四隅のポイント
        var leftTop:Point = new Point(stage.stageWidth / 2 - 100, stage.stageHeight / 2 - 100);
        var rightTop:Point = new Point(stage.stageWidth / 2 + 100, stage.stageHeight / 2 - 100);
        var rightBottom:Point = new Point(stage.stageWidth / 2 + 100, stage.stageHeight / 2 + 100);
        var leftBottom:Point = new Point(stage.stageWidth / 2 - 100, stage.stageHeight / 2 + 100);

        //四角形の描画
        var base:Sprite = new Sprite();
        var g:Graphics = base.graphics;
        base.x = base.y = 0;
        stage.addChild(base);    
        g.lineStyle(3, 0x000000);
        g.drawRect(leftTop.x, leftTop.y, 200, 200);
        
        //四角形の4つの辺をLineインスタンスとして作成し、配列に格納
        var line1:Line = new Line(leftTop, rightTop, Line.TYPE_SEGMENT);
        var line2:Line = new Line(rightTop, rightBottom, Line.TYPE_SEGMENT);
        var line3:Line = new Line(rightBottom, leftBottom, Line.TYPE_SEGMENT);
        var line4:Line = new Line(leftBottom, leftTop, Line.TYPE_SEGMENT);
        lineArray = [line1, line2, line3, line4];
        
        //赤線の描画領域を作成
        canvas = new Sprite();
        canvas.x = 0;
        canvas.y = 0;
        stage.addChild(canvas);
        
        stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
    }
    
    private function onMouseDown(event:MouseEvent):void{
        stage.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
        stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
        stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
        
        //ドラッグ開始点の保存(線分の始点)
        s_p = new Point(mouseX, mouseY);
    }
    
    private function onMouseMove(event:MouseEvent):void{
        //ドラッグ終了点の保存(線分の終点)
        e_p = new Point(mouseX, mouseY);
        
        //マウスドラッグによりできた線分の描画
        var g:Graphics = canvas.graphics;
        g.clear();
        g.lineStyle(3, 0xff0000);
        g.moveTo(s_p.x, s_p.y);
        g.lineTo(e_p.x, e_p.y);
        
        //描画された線分と四角形の四辺それぞれの交点を計算
        var line:Line = new Line(s_p, e_p, Line.TYPE_STRAIGHT);
        lineArray.forEach(function(item:*, index:int, array:Array):void{
            var p:Point = item.getIntersectionPoint(line);
            if(p != null){
                //交点があれば円を描画
                g.beginFill(0xff0000);
                g.drawCircle(p.x, p.y, 10);
            }
        });
    }
    
    private function onMouseUp(event:MouseEvent):void{
        stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
        stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
        stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
    }
    }
}

import flash.geom.Point;
import flash.display.Graphics;
    
class Line
{
    /* 2点を通る直線(終端はない) */
    public static const TYPE_STRAIGHT:String = "straight";
    /* p1からp2の方向に延びる半直線 */
    public static const TYPE_HALF:String = "half";
    /* p1, p2間の線分 */
    public static const TYPE_SEGMENT:String = "segment";
    
    public var p1:Point;
    public var p2:Point;
    public var type:String;
    
    public function Line(p1:Point, p2:Point, type:String=TYPE_STRAIGHT)
    {
        this.p1 = p1;
        this.p2 = p2;
        this.type = type;
    }
    
    /**
     * 2つのLineインスタンスの交点を表わすPointインスタンスを取得する
     * 交点がない場合はnullを返す
     * @param line
     * @return 
     * 
     */
    public function getIntersectionPoint(line:Line):Point{
        var vector1:Point = this.getVector();
        var vector2:Point = line.getVector();
        
        if(cross(vector1, vector2) == 0.0){
            //2直線が並行の場合はnullを返す
            return null;
        }
        
        // 交点を this.p1 + s * vector1 としたとき
        var s:Number = cross(vector2, line.p1.subtract(this.p1)) / cross(vector2, vector1);
        // 交点を line.p1 + t * vector2 としたとき
        var t:Number = cross(vector1, this.p1.subtract(line.p1)) / cross(vector1, vector2);
        
        if(this.validateIntersect(s) && line.validateIntersect(t)){
            vector1.x *= s;
            vector1.y *= s;
            return this.p1.add(vector1);
        }else{
            return null;
        }
    }
    
    public function getVector():Point{
        return p2.subtract(p1);
    }
    
    /**
     * 交点までのベクトルを p1 + n * (p2 - p1) であらわしたとき、
     * nが適切な値の範囲内かどうかを判定する。
     * 
     * 直線の場合:nはどの値でもよい
     * 半直線の場合:nは0以上である必要がある
     * 線分の場合:nは0以上1以下である必要がある
     * @param n
     * @return 
     * 
     */
    private function validateIntersect(n:Number):Boolean{
        if(this.type === TYPE_HALF){
            return (0 <= n);
        }else if(this.type === TYPE_SEGMENT){
            return ((0 <= n) && (n <= 1));
        }else{
            return true;
        }
    }
    
    /**
     * 2つの2次元ベクトルの外積を返す
     * @param vector1 2次ベクトルを表わすPointインスタンス
     * @param vector2 2次ベクトルを表わすPointインスタンス
     * @return 
     * 
     */
    private function cross(vector1:Point, vector2:Point):Number{
        return (vector1.x * vector2.y - vector1.y * vector2.x);
    }

    public function toString():String{
        var str:String = "";
        if(type === TYPE_STRAIGHT){
            str += "---> ";
        }
        str += "(" + p1.x + ", " + p1.y + ") ---> (" + p2.x + ", " + p2.y + ")";
        if(type === TYPE_STRAIGHT || type === TYPE_HALF){
            str += " --->";
        }
        
        return str;
    }
}