直線や線分の交点を計算する
/**
* 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;
}
}