Cálculo de líneas rectas que se cruzan con planos espaciales y su código fuente

Propósito: Al escribir proyectos gráficos, a menudo nos encontramos con la intersección de planos tridimensionales. También es la base de los gráficos.

El plano del espacio es lo mismo que la línea recta, y hay dos formas principales de expresión.
1) Expresión algebraica general: ax + by + cz + d = 0 ax+by+cz+d=0una x+por _+cz _+d=0
2) Expresión geométrica (ambos son vectores columna):( P , N ) (P,N)( P ,N ) , donde es un punto en el plano,NNN es el vector normal del plano. Su expresión algebraica es( P − O ) T ∗ N = 0 (PO)^T*N=0( PAGO )Tnorte=0 (Necesita transponerse a un vector fila)
En los cálculos posteriores, cuando se escriben códigos C++, generalmente se prefieren las expresiones geométricas. Porque es más intuitivo, pero también propicio para los cálculos posteriores. A continuación, presentaré el algoritmo de la intersección de dos planos basado en la expresión geométrica y finalmente daré el código C++.

Método 1:
suponga que los dos planos son:

( PAGS 1 , norte 1 ) = > ( X − PAGS 1 ) T ∗ norte 1 = 0 ( 1 ) (P_1,N_1)=>(X-P_1)^T*N_1=0 \space \space \space(1 )( PAG1,norte1)=>( XPAG1)Tnorte1=0 ( 1 )   

( PAGS 2 , norte 2 ) = > ( X − PAGS 2 ) T ∗ norte 2 = 0 ( 2 ) (P_2,N_2)=>(X-P_2)^T*N_2=0 \space \space \space(2 )( PAG2,norte2)=>( XPAG2)Tnorte2=0 ( 2 )   

Hay tres situaciones donde dos planos espaciales se cruzan
: 1: La intersección es una línea recta.
2: Si los planos son paralelos, no hay intersección.
3: En el caso de coplanaridad, se cortan pero no son planos.

Lo siguiente introduce la situación de que los planos se cortan como una línea recta:
inserte la descripción de la imagen aquí
la expresión de la línea recta que se corta de dos planos: O 3 O_3O3(vértice inicial); N 3 N_3norte3(dirección).
1) Primero calcule la dirección de la intersección N 3 N_3norte3, porque se encuentra que la dirección de la línea de intersección es perpendicular a los vectores normales del plano1 y el plano2. Producto vectorial N 1 × N 2 N_1\veces N_2norte1×norte2, obtenga lo siguiente:
N 3 = N 1 × N 2 ( 3 ) N_3 = N_1\times N_2 \space \space (3)norte3=norte1×norte2  ( 3 )

inserte la descripción de la imagen aquíEl rojo es el vector normal de la línea de intersección del plano obtenido. (en la imagen)

2) Necesita encontrar un vértice en una línea recta. Puede ser cualquier vértice, el mejor es P 1 P_1PAG1, P 2 P_2PAG2Proyecte el vértice sobre la recta P 1 ′ , P 2 ′ P_1',P_2'PAG1′′,PAG2′′punto medio de . Para la comodidad de contar, este blog solo usa P 1 P_1PAG1El punto PP proyectado sobre la rectaP , como se muestra en la siguiente figura

inserte la descripción de la imagen aquí

Es el avión ( P 1 , N 3 ) (P_1,N_3)( PAG1,norte3) y el punto de intersección de la recta. P 1 , N3 P_1, N_3PAG1,norte3Escrito en el siguiente formato:

( PAGS 1 , norte 3 ) = > ( X − PAGS 1 ) T ∗ norte 3 = 0 ( 4 ) (P_1,N_3)=>(X-P_1)^T*N_3=0 \space \space \space(4 )( PAG1,norte3)=>( XPAG1)Tnorte3=0 ( 4 )   

Entonces, usar (1)(2)(4) puede formar un sistema de ecuaciones lineales como:

formar un nuevo plano. Luego usa la intersección de los tres planos para obtener el vértice. Como se muestra en la siguiente figura:
el tercer vector normal se puede expresar como:
( X − P 1 ) T ∗ N 1 = 0 ( X − P 2 ) T ∗ N 2 = 0 ( X − P 1 ) T ∗ N 3 = 0 \ begin{reunidos} (X-P_1)^T*N_1=0 \\ (X-P_2)^T*N_2=0\\ (X-P_1)^T*N_3=0 \\end{reunidos}( XPAG1)Tnorte1=0( XPAG2)Tnorte2=0( XPAG1)Tnorte3=0

La fórmula se puede descomponer de la siguiente manera:
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{reunidos} 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{reunidos}XTnorte1=PAG1Tnorte1XTnorte2=PAG2Tnorte2XTnorte3=PAG1Tnorte3

donde XXX es un número desconocido, es un vector y el vértice X ∗ X^*en la línea se puede obtener a través de la fórmula anteriorX , su valor esP = X ∗ P=X^*PAG=X .
Esta parte del código se agregará más adelante. También es muy simple de la siguiente manera:

#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;
}

El resultado de la operación es el siguiente:
inserte la descripción de la imagen aquí

Método 2:
si la expresión de la función es ax + by + cz + d = 0 ax+by+cz+d=0una x+por _+cz _+d=0 _ Las expresiones de los dos planos son
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 \espacio \espacio \espacio (6)a2X+b2y+C2z+d2=0 ( 6 )   

Se puede escribir en forma vectorial como:

norte 1 T × X = − re 1 ( 7 ) N_1^T \times X=-d_1 \space \space \space (7)norte1T×X=- re1   ( 7 )

norte 2 T × X = − re 2 ( 8 ) N_2^T \times X=-d_2 \espacio \espacio \espacio (8)norte2T×X=- re2   ( 8 )

1: Calcule la dirección de la línea recta: utilice el mismo método, puede obtener N 3 = N 1 × N 2 N_3=N_1 \times N_2norte3=norte1×norte2,
2: Encuentra un vértice en una línea recta: dado que ambos planos son vértices, no se considerará encontrar el mejor vértice. Usamos un video en youtube que se describe a continuación:

inserte la descripción de la imagen aquí
Supongamos que uno de los ejes es 0 ( z = 0 z=0z=0 ). Luego invente la fórmula a continuación.
a 1 x + b 1 y + d 1 = 0 a 2 x + b 2 y + d 2 = 0 \begin{reunidos} a_1x+b_1y+d_1=0 \\ a_2x+b_2y+d_2=0 \end{reunidos}a1X+b1y+d1=0a2X+b2y+d2=0
Los vértices así obtenidos son P = ( 0 , ys , zs ) P=(0,y_s,z_s)PAG=( 0 ,ys,zs)
pero en el código real,0 00 debe ser considerado. Sabemos que para un eje, si no aporta casi nada, pueden surgir problemas. Solo si en la ecuacióna 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 )    , sic 1 = 10000 , a 1 = 0.0001 , b 1 = 100 c_1=10000, a_1=0.0001, b_1=100C1=1 0 0 0 0 , un1=0 _ 0 0 0 1 ,b1=1 0 0 , entonces se puede encontrar que elxxx será muy grande. Tal línea de intersección está enxxEl coeficiente en el eje x es muy pequeño, lo que indica que sigue axxEl eje x es paralelo. Por lo tanto, cuando calculamos la línea de intersección, necesitamos calcular el eje principal de la línea de intersección del plano. Tiene vector normalN 3 N_3norte3expresar.
si N 3 N_3norte3medio xxEl coeficiente x es el más grande. Suponemos que la línea de intersección esP = ( 0 , y , z ) P=(0,y,z)PAG=( 0 ,y ,z ) , y luego poner en la ecuación como:

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

si N 3 N_3norte3 y y El coeficiente y es el más grande. Suponemos que la línea de intersección esP = ( x , 0 , z ) P=(x,0,z)PAG=( X ,0 ,z )
a 1 x + c 1 z + d 1 = 0 a 2 x + c 2 z + d 2 = 0 \begin{reunidos} a_1x+c_1z+d_1=0 \\ a_2x+c_2z+d_2=0 \end{ reunido}a1X+C1z+d1=0a2X+C2z+d2=0

si N 3 N_3norte3medio zzEl factor z es el más grande. Suponemos que la línea de intersección esP = ( 0 , y , z ) P=(0,y,z)PAG=( 0 ,y ,z )
a 1 y + b 1 z + d 1 = 0 a 2 y + b 2 z + d 2 = 0 \begin{reunidos} a_1y+b_1z+d_1=0 \\ a_2y+b_2z+d_2=0 \end{ reunido}a1y+b1z+d1=0a2y+b2z+d2=0

El código de implementación específico es el siguiente:

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); Esto es para encontrar el eje más largo.

Si los planos en los casos 2 y 3 anteriores son paralelos o coplanares:
primero tome un punto en el plano y luego calcule la distancia desde el vértice hasta el plano. Entonces es como sigue:
SamplePnt3dFromPlaneFnc(sor_fun, sm_pnt); Esto es para ir arbitrariamente a un punto en el plano.Pnt3d2PlaneDist
(tgt_fn, sm_pnt); Calcula la distancia desde el punto hasta el plano. Se utiliza para determinar si dos caras son coplanares.

También hay un mejor método de intersección de planos, pero no lo he entendido completamente por el momento. El enlace es el siguiente:
http://tbirdal.blogspot.com/2016/10/a-better-approach -to-plane-intersection.html

Supongo que te gusta

Origin blog.csdn.net/weixin_43851636/article/details/125311930
Recomendado
Clasificación