【計算幾何】求三角面和直線交點


需求:

對於給定的三角形面片3個頂點,和一條直線的2個點,求三角面和直線的交點,若無交點,輸出-1。

思路:

利用海倫公式,可以得到三角形的面積,然后用3個點的2個向量,進行叉乘,得到面的法向量。ax+by+cz=d可以表示面,求出常數d,聯力面的方程和直線方程,求解交點。

代碼:

class CVector
{
public:
	union
	{
		float vec[3];
		struct { float x, y, z; };
	};
};

class CrossPoint
{
public:
	CrossPoint();
	virtual ~CrossPoint();
public:
	static bool ValidPoint(CVector &LinePoint, CVector &LineV,
		CVector &TrianglePoint1, CVector &TrianglePoint2, CVector &TrianglePoint3, CVector &result);
	static float Area(float a, float b, float c);
	static float Distance(CVector &p1, CVector &p2);
};

///////////////////////////////

CrossPoint::CrossPoint()
{

}

CrossPoint::~CrossPoint()
{

}
//計算p1到p2的距離的平方
float CrossPoint::Distance(CVector &p1, CVector &p2)
{
	float dist;
	dist = ((p2.x - p1.x)*(p2.x - p1.x)
		+ (p2.y - p1.y)*(p2.y - p1.y)
		+ (p2.z - p1.z)*(p2.z - p1.z));
	return (float)sqrt(dist);
}
//利用海倫公式求變成為a,b,c的三角形的面積
float CrossPoint::Area(float a, float b, float c)
{
	float s = (a + b + c) / 2;
	return (float)sqrt(s*(s - a)*(s - b)*(s - c));
}


bool CrossPoint::ValidPoint(CVector &LinePoint1, CVector &LinePoint2, CVector &TrianglePoint1, CVector

	&TrianglePoint2, CVector &TrianglePoint3, CVector &result)
{
	//三角形所在平面的法向量
	CVector TriangleV;
	//三角形的邊方向向量
	CVector VP12, VP13;
	//直線與平面的交點
	CVector CrossPoint;
	//平面方程常數項
	float TriD;
	//CVector LineV = LinePoint2 - LinePoint1;
	CVector LineV;
	LineV.x = 0, LineV.y = 0, LineV.z = 100;
	/*-------計算平面的法向量及常數項-------*/
	//point1->point2
	VP12.x = TrianglePoint2.x - TrianglePoint1.x;
	VP12.y = TrianglePoint2.y - TrianglePoint1.y;
	VP12.z = TrianglePoint2.z - TrianglePoint1.z;
	//point1->point3
	VP13.x = TrianglePoint3.x - TrianglePoint1.x;
	VP13.y = TrianglePoint3.y - TrianglePoint1.y;
	VP13.z = TrianglePoint3.z - TrianglePoint1.z;
	//VP12xVP13
	TriangleV.x = VP12.y*VP13.z - VP12.z*VP13.y;
	TriangleV.y = -(VP12.x*VP13.z - VP12.z*VP13.x);
	TriangleV.z = VP12.x*VP13.y - VP12.y*VP13.x;
	//計算常數項
	TriD = -(TriangleV.x*TrianglePoint1.x
		+ TriangleV.y*TrianglePoint1.y
		+ TriangleV.z*TrianglePoint1.z);
	/*-------求解直線與平面的交點坐標---------*/
	/* 思路:
	* 首先將直線方程轉換為參數方程形式,然后代入平面方程,求得參數t,
	* 將t代入直線的參數方程即可求出交點坐標
	*/
	float tempU, tempD; //臨時變量
	tempU = TriangleV.x*LinePoint1.x + TriangleV.y*LinePoint1.y
		+ TriangleV.z*LinePoint1.z + TriD;
	tempD = TriangleV.x*LineV.x + TriangleV.y*LineV.y + TriangleV.z*LineV.z;
	//直線與平面平行或在平面上
	if (tempD == 0.0)
	{
		//printf("The line is parallel with the plane.\n");
		return false;
	}
	//計算參數t
	float t = -tempU / tempD;
	//計算交點坐標
	CrossPoint.x = LineV.x*t + LinePoint1.x;
	CrossPoint.y = LineV.y*t + LinePoint1.y;
	CrossPoint.z = LineV.z*t + LinePoint1.z;
	/*----------判斷交點是否在三角形內部---*/

	//計算三角形三條邊的長度
	float d12 = Distance(TrianglePoint1, TrianglePoint2);
	float d13 = Distance(TrianglePoint1, TrianglePoint3);
	float d23 = Distance(TrianglePoint2, TrianglePoint3);
	//計算交點到三個頂點的長度
	float c1 = Distance(CrossPoint, TrianglePoint1);
	float c2 = Distance(CrossPoint, TrianglePoint2);
	float c3 = Distance(CrossPoint, TrianglePoint3);
	//求三角形及子三角形的面積
	float areaD = Area(d12, d13, d23); //三角形面積
	float area1 = Area(c1, c2, d12); //子三角形1
	float area2 = Area(c1, c3, d13); //子三角形2
	float area3 = Area(c2, c3, d23); //子三角形3
									 //根據面積判斷點是否在三角形內部
	if (fabs(area1 + area2 + area3 - areaD) > 0.001)
	{
		return false;
	}

	result = CrossPoint;
	return true;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM