この記事のURL

http://www.dango-itimi.com/blog/archives/2006/000858.html


FLASH tips 円と線分の交差判定

こちらのサイトによると円と線分の交差判定方法は、

線分の始点から終点へのベクトルを v、 線分の始点から球の中心へのベクトルを c とします。 
v・c<0 の時、球の中心が線分の始点よりも線分から遠くにあるので、
c の長さが球の半径よりも小さければ交差と判定します。 
v・c≧0 の時、v・c と v2 の長さを比べます (v 方向での c の長さと v の比較)。 
v・c の方が大きければ、球の中心が線分の終点よりも線分から遠くにあるので、 
線分の終点と球の中心の距離の 2 乗を求めて、 球の半径の 2 乗よりも小さければ交差と判定します。 
v2 の方が大きければ、球の中心から線分に降ろした足が線分上に 存在するはずです。
c2-(v・c/v2)*v・c でその長さの 2 乗が分かり、 球の半径の 2 乗よりも小さければ交差と判定します。 

とのことで、詳しくは理解していませんがActionScriptに移植しました。

class Equation{

	//========================================================================//
	//
	// 円と線分の交差判定を行う
	// 交差していない場合は null を返却する
	//
	// crcl : { x:円中心点X座標, y:円中心点Y座標, r:半径 } 
	// line : { pt1:{ x:X座標, y:Y座標 }, pt2:{ x:X座標, y:Y座標 } }
	//
	// ※ : line.pt1を始点 line.pt2を終点 とする
	//
	// return : 交差している/true or 交差していない/false
	//
	//========================================================================//
	public static function checkCrclCls( crcl:Object, line:Object ):Boolean{

		//V : 線分始点から終点へのベクトル
		//C : 線分始点から円中心へのベクトル
		var V:Object = { x:line.pt2.x-line.pt1.x, y:line.pt2.y-line.pt1.y };
		var C:Object = { x:crcl.x-line.pt1.x, y:crcl.y-line.pt1.y };

		//二つのベクトルの内積を求める
		var n1:Number = Equation.dotProduct( V, C );

		if( n1 < 0 ){

			//Cの長さが円の半径より小さい場合 : 交差している
			return (Equation.distance(line.pt1, crcl) < crcl.r) ? true : false;
		}

		var n2:Number = Equation.dotProduct( V, V );

		if( n1 > n2 ){

			//線分の終点と円の中心の距離の二乗を求める
			var len:Number = Math.pow( Equation.distance(line.pt2, crcl), 2 );

			//円の半径の二乗よりも小さい場合 : 交差している
			return ( len < Math.pow( crcl.r, 2 ) ) ? true : false;

		}else{

			var n3:Number = Equation.dotProduct( C, C );
			return ( n3-(n1/n2)*n1 < Math.pow( crcl.r, 2 ) ) ? true : false;
		}
	}

	//========================================================================//
	//
	// ベクトルとベクトルの内積を求める
	//
	// vec1 : { x, y }
	// vec2 : { x, y }
	//
	// retrun : 内積
	//
	//========================================================================//
	public static function dotProduct( vec1:Object, vec2:Object ):Number{

		return ( vec1.x * vec2.x ) + ( vec1.y * vec2.y );
	}

	//========================================================================//
	//
	// 二点の成す線分の移動量を求める
	//
	// pt1   : { x:点1X座標, y:点1Y座標 }
	// pt2   : { x:点2X座標, y:点2Y座標 }
	//
	// retrun : 移動量
	//
	//========================================================================//
	public static function distance( pt1:Object, pt2:Object ):Number{

		return Math.sqrt(Math.pow(pt1.x-pt2.x, 2) + Math.pow(pt1.y-pt2.y, 2));
	}
}

【 使用例 】

//_rootに点を示すムービークリップ mc1, mc2, mc3が存在する
var CRCL_R:Number = 60; //円の半径
var pt1 :Object = { x:_root.mc1._x, y:_root.mc1._y };
var pt2 :Object = { x:_root.mc2._x, y:_root.mc2._y };
var crcl:Object = { x:_root.mc3._x, y:_root.mc3._y, r:CRCL_R };
var line:Object = { pt1:pt1, pt2:pt2 };	

//円と線分の交差判定を行う
trace( Equation.checkCrclCls( crcl, line ) );

【 サンプル1 】円と線分との交差判定

線分の始点と終点が両方とも円内部にある場合もEquation.checkCrclClsメソッドは交差していると判定しています。円周と線分との交差判定でないことにご注意ください。
円周と線分の交差判定を行いたい場合は、あらかじめ線分の始点と終点が円内部にあるかどうかを調査し、始点と終点の両方がが円内部にある場合、円と線分の交差判定を行わないようにすればよいと思われます。

点と円の衝突判定には以下のメソッドを利用します。

class Equation{

	//========================================================================//
	//
	// 点と円の衝突判定
	//
	// 点と円の中心の距離の二乗を求め
	// その長さが円の半径の二乗以下なら衝突している
	//
	// pt   : { x:点X座標, y:点Y座標 }
	// crcl : { x:円中心点X座標, y:円中心点Y座標, r:半径 } 
	//
	// return : true/衝突している or false/衝突していない
	//
	//========================================================================//
	public static function checkPntCrclCrs( pt:Object, crcl:Object ):Boolean{

		var dis:Number = Math.pow( (pt.x - crcl.x), 2 ) + 
						 Math.pow( (pt.y - crcl.y), 2 );
		return ( dis <= Math.pow( crcl.r, 2 ) ) ? true : false;
	}
}

【 サンプル2 】円周と線分との交差判定

円周と線分とが交差している場合のみ、円周上に交点が表示されます。

[ FLASH ] [ tips ] 投稿者 siratama : 2006年02月23日 03:14

トラックバック

http://www.dango-itimi.com/blog/mt-tb.cgi/818




[EDIT]