两架飞机之间的交叉线

AMH*_*AMH 16 language-agnostic math plane

如何找到两个平面之间的交线?

我知道数学思想,并且我在平面法向量之间做了交叉乘积

但是如何以编程方式从结果向量中获取该行

R. *_*des 19

平面的方程是ax + by + cz + d = 0,其中(a,b,c)是平面的法线,d是到原点的距离.这意味着满足该等式的每个点(x,y,z)都是平面的一个成员.

鉴于两架飞机:

P1: a1x + b1y + c1z + d1 = 0
P2: a2x + b2y + c2z + d2 = 0
Run Code Online (Sandbox Code Playgroud)

两者之间的交集是验证两个方程的点集.要沿此线找到点,您只需选择x的值,任何值,然后求解y和z的方程.

y = (-c1z -a1x -d1) / b1
z = ((b2/b1)*(a1x+d1) -a2x -d2)/(c2 - c1*b2/b1)
Run Code Online (Sandbox Code Playgroud)

如果你做x=0,这变得更简单:

y = (-c1z -d1) / b1
z = ((b2/b1)*d1 -d2)/(c2 - c1*b2/b1)
Run Code Online (Sandbox Code Playgroud)

  • x = 0可能并不总是有效.例如,如果结果线与yz平面平行. (3认同)

bob*_*obo 12

在线找到一个点

要获得2个平面的交集,您需要一条线和该线的方向.

找到该线的方向非常简单,只需穿过相交的2个平面的2个法线即可.

lineDir = n1 × n2
Run Code Online (Sandbox Code Playgroud)

但是那条线穿过原点,而沿着你的平面交叉点的线可能不会.因此,Martinho的回答为在交叉线上找到一个点提供了一个很好的开始(基本上是两个平面上的任何点).

如果你想看看如何解决这个问题的推导,这里有它背后的数学:

首先让x = 0.现在我们在2个方程中有2个未知数而不是2个方程中的3个未知数(我们任意选择了一个未知数).

然后平面方程是(由于我们选择x = 0,因此消除了一个项):

B 1 y + C 1 z + D 1 = 0

B 2 y + C 2 z + D 2 = 0

我们想要y和z使得那些方程式对于给定的B 1,C 1都正确地求解(= 0).

所以,只需将顶部eq乘以(-B 2/B 1)即可得到

-B 2 y +( - B 2/B 1)*C 1 z +( - B 2/B 1)*D 1 = 0

B 2 y + C 2 z + D 2 = 0

添加eqs来获取

z =(( - B 2/B 1)*D 1 - D 2)/(C 2*B 2/B 1)*C 1)

现在把你找到的z扔到第一个等式中,找到y为

y =( - D 1 - C 1 z)/ B 1

注意,使0变为0 的最佳变量是具有最低系数的变量,因为它无论如何都不携带任何信息.因此,如果C 1和C 2均为0,则选择z = 0(而不是x = 0)将是更好的选择.

如果B 1 = 0 ,上述解决方案仍然会搞砸(这不太可能).您可以添加一些if语句来检查B 1是否为0,如果是,则确保解决其中一个其他变量.

解决方案使用3个平面的交叉点

根据用户的回答,3个平面交叉的封闭形式解决方案实际上是在图形宝石1中.公式为:

P_intersection =((point_on1•n1)(n2×n3)+(point_on2•n2)(n3×n1)+(point_on3•n3)(n1×n2))/ det(n1,n2,n3)

实际上是point_on1•n1 = -d1(假设你写的平面Ax + By + Cz + D = 0,而不是= -D).所以,你可以把它重写为:

P_intersection =(( - d1)(n2×n3)+( - d2)(n3×n1)+( - d3)(n1×n2))/ det(n1,n2,n3)

与3个平面相交的函数:

// Intersection of 3 planes, Graphics Gems 1 pg 305
static Vector3f getIntersection( const Plane& plane1, const Plane& plane2, const Plane& plane3 )
{
  float det = Matrix3f::det( plane1.normal, plane2.normal, plane3.normal ) ;

  // If the determinant is 0, that means parallel planes, no intn.
  if( det == 0.f ) return 0 ; //could return inf or whatever

  return ( plane2.normal.cross( plane3.normal )*-plane1.d +
           plane3.normal.cross( plane1.normal )*-plane2.d + 
           plane1.normal.cross( plane2.normal )*-plane3.d ) / det ;            
}
Run Code Online (Sandbox Code Playgroud)

证明它有效(黄点是这里的rgb平面的交点)

在此输入图像描述

获得这条线

一旦你有一个与两个平面共同的交叉点,就行了

P + t*d

其中P是交点,t可以从(-inf,inf)开始,d是方向向量,它是两个原始平面法线的叉积.

红色和蓝色平面之间的交叉线看起来像这样

在此输入图像描述

效率和稳定性

"强健"(第二种方式)按照我的计数需要48个基本操作,而第一种方式(x,y的隔离)使用的36个基本操作.在这两种方式之间的稳定性和#computing之间存在折衷.

在B 1为0并且你没有检查的情况下,从第一路的呼叫中获得(0,inf,inf)是非常灾难性的.因此,添加if语句并确保不将0除以第一种方式可能会以代码膨胀和增加的分支(可能非常昂贵)为代价来提供稳定性.3平面交叉法几乎是无分支的,不会给你无穷大.


ide*_*n42 12

添加此答案是为了完整性,因为在撰写本文时,这里的答案都没有包含直接解决问题的工作代码示例.

虽然这里的其他答案已经涵盖了原则.


可以使用3平面交叉算法的简化版本来计算在两个平面之间找到​​线.

来自bobobobo答案的2',"更强大的方法" 引用了3平面交叉点.

虽然这适用于2架飞机 (其中第3个平面可以使用前两个平面的叉积计算),但对于2平面版本,问题可以进一步减少.

  • 无需使用3x3矩阵行列式,
    而是可以使用第一和第二平面(即第3平面的方向)之间的叉积的平方长度.
  • 无需包括第3架飞机距离,
    (计算最终位置).
  • 无需否定距离.
    通过交换交叉产品订单来节省一些cpu周期.

包括这个代码示例,因为它可能不会立即显而易见.

// Intersection of 2-planes: a variation based on the 3-plane version.
// see: Graphics Gems 1 pg 305
//
// Note that the 'normal' components of the planes need not be unit length
bool isect_plane_plane_to_normal_ray(
        const Plane& p1, const Plane& p2,
        // output args
        Vector3f& r_point, Vector3f& r_normal)
{
    // logically the 3rd plane, but we only use the normal component.
    const Vector3f p3_normal = p1.normal.cross(p2.normal);
    const float det = p3_normal.length_squared();

    // If the determinant is 0, that means parallel planes, no intersection.
    // note: you may want to check against an epsilon value here.
    if (det != 0.0) {
        // calculate the final (point, normal)
        r_point = ((p3_normal.cross(p2.normal) * p1.d) +
                   (p1.normal.cross(p3_normal) * p2.d)) / det;
        r_normal = p3_normal;
        return true;
    }
    else {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)


use*_*499 6

只要两个平面不平行,该方法就可以避免除零.

如果这些是飞机:

A1*x + B1*y + C1*z + D1 = 0
A2*x + B2*y + C2*z + D2 = 0
Run Code Online (Sandbox Code Playgroud)

1)找到平行于交线的矢量.这也是与其他两个平面垂直的第3平面的法线:

(A3,B3,C3) = (A1,B1,C1) cross (A2,B2,C2)
Run Code Online (Sandbox Code Playgroud)

2)形成3个方程的系统.这些描述了3个在一点交叉的平面:

A1*x1 + B1*y1 + C1*z1 + D1 = 0
A2*x1 + B2*y1 + C2*z1 + D2 = 0
A3*x1 + B3*y1 + C3*z1 = 0
Run Code Online (Sandbox Code Playgroud)

3)解决它们找到x1,y1,z1.这是交叉线上的一个点.

4)交线的参数方程为:

x = x1 + A3 * t
y = y1 + B3 * t
z = z1 + C3 * t
Run Code Online (Sandbox Code Playgroud)