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

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

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

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_SEGMENT);
		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;
	}
}