Calculation of straight lines intersecting space planes and its source code

Purpose: In writing graphics projects, we often encounter the intersection of three-dimensional planes. It is also the basis of graphics

The space plane is the same as the straight line, and there are two main ways of expression.
1) General algebraic expression: ax + by + cz + d = 0 ax+by+cz+d=0ax+by+cz+d=0
2) Geometric expression (both are column vectors):( P , N ) (P,N)(P,N ) , where is a point on the plane,NNN is the normal vector of the plane. Its algebraic expression is( P − O ) T ∗ N = 0 (PO)^T*N=0(PO)TN=0 (Need to be transposed into a row vector)
In subsequent calculations, when writing C++ codes, geometric expressions are generally preferred. Because it is more intuitive, but also conducive to subsequent calculations. Next, I will introduce the algorithm of the intersection of two planes based on the geometric expression, and finally give the C++ code.

Method 1:
Assume that the two planes are:

( P 1 , N 1 ) = > ( X − P 1 ) T ∗ N 1 = 0     ( 1 ) (P_1,N_1)=>(X-P_1)^T*N_1=0 \space \space \space(1) (P1,N1)=>(XP1)TN1=0   (1)

( P 2 , N 2 ) = > ( X − P 2 ) T ∗ N 2 = 0     ( 2 ) (P_2,N_2)=>(X-P_2)^T*N_2=0 \space \space \space(2) (P2,N2)=>(XP2)TN2=0   (2)

There are three situations where two space planes intersect
: 1: The intersection is a straight line.
2: If the planes are parallel, there is no intersection.
3: In the case of coplanarity, they intersect but are not planes.

The following introduces the situation that planes intersect as a straight line:
insert image description here
the expression of the intersecting straight line of two planes: O 3 O_3O3(starting vertex); N 3 N_3N3(direction).
1) First calculate the direction of intersection N 3 N_3N3, because the direction of the intersection line is found to be perpendicular to the normal vectors of plane1 and plane2. Cross product N 1 × N 2 N_1\times N_2N1×N2, get as follows:
N 3 = N 1 × N 2 ( 3 ) N_3 = N_1\times N_2 \space \space (3)N3=N1×N2  (3)

insert image description hereRed is the normal vector of the obtained plane intersection line. (in the image)

2) Need to find a vertex on a straight line. It can be any vertex, the best is P 1 P_1P1, P 2 P_2 P2Project the vertex onto the straight line P 1 ′ , P 2 ′ P_1',P_2'P1,P2midpoint of . For the convenience of telling, this blog only uses P 1 P_1P1The point PP projected onto the lineP , as shown in the figure below

insert image description here

It is the plane ( P 1 , N 3 ) (P_1,N_3)(P1,N3) and the intersection point of the line. P 1 , N3 P_1,N_3P1,N3Written in the following format:

( P 1 , N 3 ) = > ( X − P 1 ) T ∗ N 3 = 0     ( 4 ) (P_1,N_3)=>(X-P_1)^T*N_3=0 \space \space \space(4) (P1,N3)=>(XP1)TN3=0   (4)

So using (1)(2)(4) can form a linear equation system as:

form a new plane. Then use the intersection of the three planes to get the vertex. As shown in the figure below:
the third normal vector can be expressed as:
( X − P 1 ) T ∗ N 1 = 0 ( X − P 2 ) T ∗ N 2 = 0 ( X − P 1 ) T ∗ N 3 = 0 \ begin{gathered} (X-P_1)^T*N_1=0 \\ (X-P_2)^T*N_2=0\\ (X-P_1)^T*N_3=0 \\end{gathered}(XP1)TN1=0(XP2)TN2=0(XP1)TN3=0

The formula can be disassembled as follows:
XT ∗ N 1 = P 1 T ∗ N 1 XT ∗ N 2 = P 2 T ∗ N 2 XT ∗ N 3 = P 1 T ∗ N 3 \begin{gathered} X^T*N_1 =P_1^T*N_1 \\ X^T*N_2=P_2^T*N_2\\ X^T*N_3=P_1^T*N_3 \end{gathered}XTN1=P1TN1XTN2=P2TN2XTN3=P1TN3

where XXX is an unknown number, it is a vector, and the vertex X ∗ X^*on the line can be obtained through the above formulaX , its value isP = X ∗ P=X^*P=X .
This part of the code will be added later. It is also very simple as follows:

#include<Eigen/Eigen>
#include<iostream>
#include<vector>

/*
m=[n1,
   n2,
   n3]
*/
Eigen::Matrix3f ConstructMatrix3fFromVectors(Eigen::Vector3f& n1, Eigen::Vector3f& n2, Eigen::Vector3f& n3)
{
    
    
    Eigen::Matrix3f m;
    m.block<1, 3>(0, 0) = n1;
    m.block<1, 3>(1, 0) = n2;
    m.block<1, 3>(2, 0) = n3;
    return m;
}

float Pnt3d2PlaneDist(Eigen::Vector3f& ppnt, Eigen::Vector3f& pdir, Eigen::Vector3f& pnt)
{
    
    
	float sd = pdir.norm();
	if (sd < 1e-8)
		return std::numeric_limits<float>::max();
	float sb = std::abs(pdir.dot(ppnt - pnt));
	float d = sb / sd;
	return d;
}

int ComputeLineFromTwoPlanes(Eigen::Vector3f& src_pnt, Eigen::Vector3f& src_dir, 
Eigen::Vector3f& tgt_pnt, Eigen::Vector3f& tgt_dir, Eigen::Vector3f& lpnt, Eigen::Vector3f& ldir)
{
    
    
    ldir = src_dir.cross(tgt_dir);
    //判断两个平面是否共面,或者平行
    if ((std::abs(ldir[0]) + std::abs(ldir[1]) + std::abs(ldir[2])) < 1e-6)	//判断两个平面是否平行
	{
    
    
	    float dist = Pnt3d2PlaneDist(tgt_pnt, tgt_dir, src_pnt);
	    if (dist < 1e-4)
		    return 0;	//共面
	    else
		    return 1;	//平行面
    }
    //计算投影到直线的顶点
    float pn1 = src_pnt.dot(src_dir);
    float pn2 = tgt_pnt.dot(tgt_dir);
    float pn3 = src_pnt.dot(ldir);
    Eigen::Vector3f b = Eigen::Vector3f(pn1, pn2, pn3);
    Eigen::Matrix3f A = ConstructMatrix3fFromVectors(src_dir, tgt_dir, ldir);
    lpnt = A.inverse()*b;
    return 2;
}

//test adjugate matrix

int main(int argc, char** argv)
{
    
    
    Eigen::Vector3f sor_c_pnt = Eigen::Vector3f(3.84935, 0.742589, 1.38037);
    Eigen::Vector3f sor_c_dir = Eigen::Vector3f(-0.999087, -0.0426946, -0.00180283);
    Eigen::Vector3f tgt_c_pnt = Eigen::Vector3f(2.73047, 0.188734, 1.95757);
    Eigen::Vector3f tgt_c_dir = Eigen::Vector3f(0.0486091, -0.99881, 0.00407396);
    
    Eigen::Vector3f lpnt, ldir;
    ComputeLineFromTwoPlanes(sor_c_pnt, sor_c_dir, tgt_c_pnt, tgt_c_dir, lpnt, ldir);
    std::cerr <<"lpnt, dir: " << lpnt.transpose() <<", " << ldir.transpose() << std::endl;    
    return 0;
}

The result of the operation is as follows:
insert image description here

Method 2:
If the expression of the function is ax + by + cz + d = 0 ax+by+cz+d=0ax+by+cz+d=0 . The expressions of the two planes are
a 1 x + b 1 y + c 1 z + d 1 = 0 ( 5 ) a_1x+b_1y+c_1z+d_1=0 \space \space \space (5)a1x+b1y+c1z+d1=0   (5)

a 2 x + b 2 y + c 2 z + d 2 = 0     ( 6 ) a_2x+b_2y+c_2z+d_2=0 \space \space \space (6) a2x+b2y+c2z+d2=0   (6)

It can be written in vector form as:

N 1 T × X = − d 1     ( 7 ) N_1^T \times X=-d_1 \space \space \space (7) N1T×X=d1   (7)

N 2 T × X = − d 2     ( 8 ) N_2^T \times X=-d_2 \space \space \space (8) N2T×X=d2   (8)

1: Calculate the straight line direction: use the same method, you can get N 3 = N 1 × N 2 N_3=N_1 \times N_2N3=N1×N2,
2: Find a vertex on a straight line: since both planes are vertices, finding the best vertex will not be considered. We use a video on youtube which is described as follows:

insert image description here
Suppose one of the axes is 0 ( z = 0 z=0z=0 ). Then make up the formula below.
a 1 x + b 1 y + d 1 = 0 a 2 x + b 2 y + d 2 = 0 \begin{gathered} a_1x+b_1y+d_1=0 \\ a_2x+b_2y+d_2=0 \end{gathered}a1x+b1y+d1=0a2x+b2y+d2=0
The vertices obtained in this way are P = ( 0 , ys , zs ) P=(0,y_s,z_s)P=(0,ys,zs)
but in the actual code,0 00 needs to be considered. We know that for an axis, if it contributes almost nothing, problems can arise. Just if in the equationa 1 x + b 1 y + c 1 z + d 1 = 0 ( 5 ) a_1x+b_1y+c_1z+d_1=0 \space \space \space (5)a1x+b1y+c1z+d1=0 ( 5 )    , ifc 1 = 10000 , a 1 = 0.0001 , b 1 = 100 c_1=10000, a_1=0.0001, b_1=100c1=10000a1=0.0001,b1=1 0 0 , then it may be found that the computedxxx will be very large. Such an intersection line is atxxThe coefficient on the x- axis is very small, indicating that it followsxxThe x- axis is parallel. Therefore, when actually calculating the intersection line, we need to calculate the main axis of the plane intersection line. It has normal vectorN 3 N_3N3express.
if N 3 N_3N3middle xxThe x coefficient is the largest. We assume that the intersection line isP = ( 0 , y , z ) P=(0,y,z)P=(0,y,z ) , and then put into the equation as:

b 1 y + c 1 z + d 1 = 0 b 2 y + c 2 z + d 2 = 0 \begin{gathered} b_1y+c_1z+d_1=0 \\ b_2y+c_2z+d_2=0 \end{gathered} b1y+c1z+d1=0b2y+c2z+d2=0

if N 3 N_3N3yyThe y coefficient is the largest. We assume that the intersection line isP = ( x , 0 , z ) P=(x,0,z)P=(x,0,z)
a 1 x + c 1 z + d 1 = 0 a 2 x + c 2 z + d 2 = 0 \begin{gathered} a_1x+c_1z+d_1=0 \\ a_2x+c_2z+d_2=0 \end{gathered} a1x+c1z+d1=0a2x+c2z+d2=0

if N 3 N_3N3middle zzThe z -factor is the largest. We assume that the intersection line isP = ( 0 , y , z ) P=(0,y,z)P=(0,y,z)
a 1 y + b 1 z + d 1 = 0 a 2 y + b 2 z + d 2 = 0 \begin{gathered} a_1y+b_1z+d_1=0 \\ a_2y+b_2z+d_2=0 \end{gathered} a1y+b1z+d1=0a2y+b2z+d2=0

The specific implementation code is as follows:

int GetIntersectionLineFromTwoPlanesFunction(Eigen::Vector4f& sor_fun, Eigen::Vector4f& tgt_fn, 
		Eigen::Vector3f& lpnt3d, Eigen::Vector3f& ldir3d)
	{
    
    
		Eigen::Vector3f sorn = Eigen::Vector3f(sor_fun[0], sor_fun[1], sor_fun[2]);
		Eigen::Vector3f tgtn = Eigen::Vector3f(tgt_fn[0], tgt_fn[1], tgt_fn[2]);
		Eigen::Vector3f ln = sorn.cross(tgtn);
		ldir3d = ln;
		//判断三根轴,找到最大的一根轴
		if ((std::abs(ln[0]) + std::abs(ln[1]) + std::abs(ln[2])) < 1e-6)	//判断两个平面是否平行
		{
    
    
			Eigen::Vector3f sm_pnt;
			SamplePnt3dFromPlaneFnc(sor_fun, sm_pnt);
			float dist = Pnt3d2PlaneDist(tgt_fn, sm_pnt);
			if (dist < 1e-4)
				return 0;	//共面
			else
				return 1;	//平行面
		}
		int max_cn = FindMaxCoordFromVec3D(ln);
		float d1, d2;
		d1 = sor_fun[3];
		d2 = tgt_fn[3];
		if (max_cn == 0)
		{
    
    
			lpnt3d[0] = 0.0f;
			lpnt3d[1] = (d2*sorn[2] - d1*tgtn[2]) / ln[0];	//ln[0]为b_1,c_1和b_2,c_2的矩阵det|A|
			lpnt3d[2] = (d1*tgtn[1] - d2*sorn[1]) / ln[0];
			return 2;
		}
		else if (max_cn == 1)
		{
    
    
			lpnt3d[0] = (d1*tgtn[2] - d2*sorn[2]) / ln[1]; //ln[1]为a_1,c_1和a_2,c_2的矩阵det|A|
			lpnt3d[1] = 0.0f;
			lpnt3d[2] = (d2*sorn[0] - d1*tgtn[0]) / ln[1];
			return 3;
		}
		else
		{
    
    
			lpnt3d[0] = (d2*sorn[1] - d1*tgtn[1]) / ln[2]; //ln[2]为a_1,b_1和a_2,b_2的矩阵det|A|
			lpnt3d[1] = (d1*tgtn[0] - d2*sorn[0]) / ln[2];
			lpnt3d[2] = 0.0f;
			return 4;
		}
	}

FindMaxCoordFromVec3D(ln); This is to find the longest axis.

If the planes in the above 2 and 3 cases are parallel or coplanar:
first take a point on the plane, and then calculate the distance from the vertex to the plane. So it is as follows:
SamplePnt3dFromPlaneFnc(sor_fun, sm_pnt); This is to arbitrarily go to a point on the plane.
Pnt3d2PlaneDist(tgt_fn, sm_pnt); Calculate the distance from the point to the plane. It is used to determine whether two faces are coplanar.

There is also a better method of plane intersection, but I haven't fully understood it for the time being. The link to it is as follows:
http://tbirdal.blogspot.com/2016/10/a-better-approach-to-plane- intersection.html

Guess you like

Origin blog.csdn.net/weixin_43851636/article/details/125311930