平面と線分の交差判定
平面と線分ABから交点Xを求めるには...
はじめに、内積を使って平面と線分の交差判定を行います。
平面の平面方程式から平面上の点Pと法線Nが分かるので、
この状態において、PAベクトル、PBベクトルをそれぞれNと内積して、片方がプラス、片方がマイナスなら交差していると判断できます。
内積が0になることもありますが、それは線端が平面上にある場合です。
( PAとNの内積 >= 0 ) かつ ( PBとNの内積 <= 0 ) なら交差する
または
( PAとNの内積 <= 0 ) かつ ( PBとNの内積 >= 0 ) なら交差する
平面と線分の交点
前述の内積の結果は、AXとXBの距離の比率を表しているので、
ベクトルABをその比率で分割すれば交点Xが求まります。
AXの長さ : XBの長さ = PAとNの内積 : PBとNの内積
※内積はマイナス値になる場合があるので、絶対値を使ってください。
交点X = A + ベクトルAB * ( PAとNの内積 / (PAとNの内積 + PBとNの内積) )
#include <math.h>
//平面の定義
class Plane { //ax+by+cz+d=0
public:
double a,b,c,d;
Plane(){}
Plane(double a,double b,double c,double d){ this->a = a; this->b = b; this->c = c; this->d = d; }
};
//ベクトルの定義
class Vector3D{
public:
double x,y,z;
Vector3D(){}
Vector3D( double x, double y, double z) {this->x = x; this->y = y; this->z = z; }
};
//頂点の定義(ベクトルと同じ)
#define Vertex3D Vector3D
//線分ABと平面の交点を計算する
bool IntersectPlaneAndLine(
Vertex3D* out, //戻り値 交点が見つかれば格納される
Vertex3D A, //線分始点
Vertex3D B, //線分終点
Plane PL ) //平面
{
//平面上の点P
Vertex3D P = Vertex3D( PL.a * PL.d, PL.b * PL.d, PL.c * PL.d );
//PA PBベクトル
Vector3D PA = Vertex3D( P.x - A.x, P.y - A.y, P.z - A.z );
Vector3D PB = Vertex3D( P.x - B.x, P.y - B.y, P.z - B.z );
//PA PBそれぞれを平面法線と内積
double dot_PA = PA.x * PL.a + PA.y * PL.b + PA.z * PL.c;
double dot_PB = PB.x * PL.a + PB.y * PL.b + PB.z * PL.c;
//これは線端が平面上にあった時の計算の誤差を吸収しています。調整して使ってください。
if ( abs(dot_PA) < 0.000001 ) { dot_PA = 0.0; }
if ( abs(dot_PB) < 0.000001 ) { dot_PB = 0.0; }
//交差判定
if( dot_PA == 0.0 && dot_PB == 0.0 ) {
//両端が平面上にあり、交点を計算できない。
return false;
} else
if ( ( dot_PA >= 0.0 && dot_PB <= 0.0 ) ||
( dot_PA <= 0.0 && dot_PB >= 0.0 ) ) {
//内積の片方がプラスで片方がマイナスなので、交差している
} else {
//交差していない
return false;
}
//以下、交点を求める
Vector3D AB = Vector3D( B.x - A.x, B.y - A.y, B.z - A.z );
//交点とAの距離 : 交点とBの距離 = dot_PA : dot_PB
double hiritu = abs(dot_PA) / ( abs(dot_PA) + abs(dot_PB) );
out->x = A.x + ( AB.x * hiritu );
out->y = A.y + ( AB.y * hiritu );
out->z = A.z + ( AB.z * hiritu );
return true;
}