Algorithm 沿两个平面的交点查找直线

Algorithm 沿两个平面的交点查找直线,algorithm,math,3d,three.js,linear-algebra,Algorithm,Math,3d,Three.js,Linear Algebra,我试图在3D中画出两个平面相交形成的线,但是我在理解数学方面遇到了困难,这已经被解释和解释了 我试着自己去弄清楚,但我得到的最接近于一个解的是一个向量,它指向与相交线相同的方向,通过使用平面法线的叉积。我不知道如何在相交线上找到一个点,任何点都可以。我认为这种方法是一条死胡同。以下是此尝试的屏幕截图: 我试着使用问题中提到的解决方案,但它与最初的解释有一个死链接,并且这个方程对我不起作用(它有不平衡的括号,我在下面试图更正) 输出: THREE.Vector3 {x: -1, y: NaN,

我试图在3D中画出两个平面相交形成的线,但是我在理解数学方面遇到了困难,这已经被解释和解释了

我试着自己去弄清楚,但我得到的最接近于一个解的是一个向量,它指向与相交线相同的方向,通过使用平面法线的叉积。我不知道如何在相交线上找到一个点,任何点都可以。我认为这种方法是一条死胡同。以下是此尝试的屏幕截图:

我试着使用问题中提到的解决方案,但它与最初的解释有一个死链接,并且这个方程对我不起作用(它有不平衡的括号,我在下面试图更正)

输出:

THREE.Vector3 {x: -1, y: NaN, z: NaN, …}
THREE.Vector3 {x: 1, y: Infinity, z: -Infinity, …}
预期产出:

  • 沿x=0的交点的点,以及
  • 同一直线上的另一点,其中x=1

如果有人能给我一个很好的解释,或者一个平面相交算法的例子,我将不胜感激。

当我遇到这样的问题时,我通常会让一个符号代数包(在本例中是Mathematica)来处理。打字后

In[1]:= n1={x1,y1,z1};n2={x2,y2,z2};p={x,y,z};

In[2]:= Solve[n1.p==d1&&n2.p==d2,p]    
简化并替换x=0和x=1,我得到

                d2 z1 - d1 z2        d2 y1 - d1 y2
Out[5]= {{{y -> -------------, z -> ----------------}}, 
                y2 z1 - y1 z2       -(y2 z1) + y1 z2

            d2 z1 - x2 z1 - d1 z2 + x1 z2
>    {{y -> -----------------------------, 
                    y2 z1 - y1 z2

            d2 y1 - x2 y1 + (-d1 + x1) y2
>      z -> -----------------------------}}}
                  -(y2 z1) + y1 z2
先决条件
回想一下,为了表示一条线,我们需要一个向量来描述它的方向和这条线经过的点。这称为参数化形式:

line_point(t) = t * (point_2 - point_1) + point_1
其中,
point_1
point_2
是线经过的任意点,
t
是一个标量,它参数化了我们的线。现在,如果我们把任意的
t
放入上面的等式中,我们可以找到线上的任意点
line\u点(t)

注意:术语
(点2-点1)
什么都不是,只是一个描述直线方向的向量,术语
点1
什么都不是,但是直线经过的点(当然
点2
)也可以使用

算法
  • 通过以下步骤找到相交线的方向
    方向
    
    平面法线的叉积,即
    方向=叉(法线_1,
    正常(2)

  • 以任何平面为例,例如第一个平面,并找到任何两个不同的点 在此平面上:
    点1
    点2
    。如果我们假设平面方程 其形式为
    a1*x+b1*y+c1*z+d1=0
    ,然后查找2 我们可以做以下几点:

    y1 = 1
    z1 = 0
    x1 = -(b1 + d1) / a1
    
    y2 = 0
    z2 = 1
    x2 = -(c1 + d1) / a1
    
    其中
    点_1=(x1,y1,z1)
    点_2=(x2,y2,z2)

  • 现在我们有了2个点,我们可以构造参数化 位于第一个平面上的线的表示:
    直线点(t)=t*(点2-点1)+点1
    ,其中
    直线点(t)
    描述此行上的任何点,
    t
    只是一个输入标量 (通常称为参数

  • 找到直线的交点
    交点
    line_点(t)
    第二个平面
    a2*x+b2*y+c2*z+d2=0
    标准(注意 代数形式部分,因为这是实现线平面所需的全部内容 交叉口,如果您尚未这样做)

  • 我们的交叉线现在已经找到,可以在 参数化形式与往常一样:
    交点线点)=s*
    方向+交点
    ,其中
    交点(多个点)
    描述此相交线上的任何点,
    s
    参数

  • 注意:我没有在任何地方读过这个算法,我只是根据我对线性代数的知识,从头开始设计它。这并不意味着它不起作用,但该算法可能会进一步优化

    条件作用

    当两个法向量
    normal_1
    normal_2
    几乎共线时,这个问题变得非常严重。几何上,这意味着两个平面几乎相互平行,在有限精度算法中,确定具有可接受精度的相交线变得不可能。在这种情况下,有限精度算法是浮点算法three.js为您解决此问题

    如果你用矩阵表示法来表达你的问题

    m * x = v
    
    那么x的解是

    x = inverse( m ) * v
    
    我们将对m使用4x4矩阵,因为three.js对
    Matrix4
    类有一个
    inverse()
    方法

    var x1 = 0,
        y1 = 0,
        z1 = 1,
        d1 = 100;
    
    var x2 = 1,
        y2 = 1,
        z2 = 1,
        d2 = -100;
    
    var c = 0; // the desired value for the x-coordinate
    
    var v = new THREE.Vector4( d1, d2, c, 1 );
    
    var m = new THREE.Matrix4( x1, y1, z1, 0, 
                               x2, y2, z2, 0,
                               1,  0,  0,  0,
                               0,  0,  0,  1
                             );
    
    var minv = new THREE.Matrix4().getInverse( m );
    
    v.applyMatrix4( minv );
    
    console.log( v );
    
    根据需要,v的x分量将等于c,y分量和z分量将包含您要查找的值。w分量是不相关的

    现在,对下一个值c重复此操作,c=1


    three.js r.58

    这里是一个平面交点解决方案的实现,如中所述。基本上,首先使用平面法线的叉积来查找两个平面中直线的方向。其次,在平面的隐式方程(P.n+d=0,其中P是平面上的某个点,n是法线,d是平面常数)上使用一些代数来求解平面交点上的点,以及x=0、y=0或z=0平面上的点。然后,解是由点和向量描述的线。我使用的是three.js79版

    /*
    
    Algorithm taken from http://geomalgorithms.com/a05-_intersect-1.html. See the
    section 'Intersection of 2 Planes' and specifically the subsection
    (A) Direct Linear Equation
    
    */
    function intersectPlanes(p1, p2) {
    
      // the cross product gives us the direction of the line at the intersection
      // of the two planes, and gives us an easy way to check if the two planes
      // are parallel - the cross product will have zero magnitude
      var direction = new THREE.Vector3().crossVectors(p1.normal, p2.normal)
      var magnitude = direction.distanceTo(new THREE.Vector3(0, 0, 0))
      if (magnitude === 0) {
        return null
      }
    
      // now find a point on the intersection. We use the 'Direct Linear Equation'
      // method described in the linked page, and we choose which coordinate
      // to set as zero by seeing which has the largest absolute value in the
      // directional vector
    
      var X = Math.abs(direction.x)
      var Y = Math.abs(direction.y)
      var Z = Math.abs(direction.z)
    
      var point
    
      if (Z >= X && Z >= Y) {
        point = solveIntersectingPoint('z', 'x', 'y', p1, p2)
      } else if (Y >= Z && Y >= X){
        point = solveIntersectingPoint('y', 'z', 'x', p1, p2)
      } else {
        point = solveIntersectingPoint('x', 'y', 'z', p1, p2)
      }
    
      return [point, direction]
    }
    
    
    /*
    
    This method helps finding a point on the intersection between two planes.
    Depending on the orientation of the planes, the problem could solve for the
    zero point on either the x, y or z axis
    
    */
    function solveIntersectingPoint(zeroCoord, A, B, p1, p2){
        var a1 = p1.normal[A]
        var b1 = p1.normal[B]
        var d1 = p1.constant
    
        var a2 = p2.normal[A]
        var b2 = p2.normal[B]
        var d2 = p2.constant
    
        var A0 = ((b2 * d1) - (b1 * d2)) / ((a1 * b2 - a2 * b1))
        var B0 = ((a1 * d2) - (a2 * d1)) / ((a1 * b2 - a2 * b1))
    
        var point = new THREE.Vector3()
        point[zeroCoord] = 0
        point[A] = A0
        point[B] = B0
    
        return point
    }
    
    
    var planeA = new THREE.Plane((new THREE.Vector3(0, 0, 1)).normalize(), 100)
    var planeB = new THREE.Plane((new THREE.Vector3(1, 1, 1)).normalize(), -100)
    
    var [point, direction] = intersectPlanes(planeA, planeB)
    

    这听起来是解决此类问题的一个很好的工具,但我不熟悉符号代数软件包。说实话,当你为我做输出时,我甚至很难理解输出:p我检查了倍频程,并决定学习该工具所需的时间与研究解决我的问题所需的时间一样多
    /*
    
    Algorithm taken from http://geomalgorithms.com/a05-_intersect-1.html. See the
    section 'Intersection of 2 Planes' and specifically the subsection
    (A) Direct Linear Equation
    
    */
    function intersectPlanes(p1, p2) {
    
      // the cross product gives us the direction of the line at the intersection
      // of the two planes, and gives us an easy way to check if the two planes
      // are parallel - the cross product will have zero magnitude
      var direction = new THREE.Vector3().crossVectors(p1.normal, p2.normal)
      var magnitude = direction.distanceTo(new THREE.Vector3(0, 0, 0))
      if (magnitude === 0) {
        return null
      }
    
      // now find a point on the intersection. We use the 'Direct Linear Equation'
      // method described in the linked page, and we choose which coordinate
      // to set as zero by seeing which has the largest absolute value in the
      // directional vector
    
      var X = Math.abs(direction.x)
      var Y = Math.abs(direction.y)
      var Z = Math.abs(direction.z)
    
      var point
    
      if (Z >= X && Z >= Y) {
        point = solveIntersectingPoint('z', 'x', 'y', p1, p2)
      } else if (Y >= Z && Y >= X){
        point = solveIntersectingPoint('y', 'z', 'x', p1, p2)
      } else {
        point = solveIntersectingPoint('x', 'y', 'z', p1, p2)
      }
    
      return [point, direction]
    }
    
    
    /*
    
    This method helps finding a point on the intersection between two planes.
    Depending on the orientation of the planes, the problem could solve for the
    zero point on either the x, y or z axis
    
    */
    function solveIntersectingPoint(zeroCoord, A, B, p1, p2){
        var a1 = p1.normal[A]
        var b1 = p1.normal[B]
        var d1 = p1.constant
    
        var a2 = p2.normal[A]
        var b2 = p2.normal[B]
        var d2 = p2.constant
    
        var A0 = ((b2 * d1) - (b1 * d2)) / ((a1 * b2 - a2 * b1))
        var B0 = ((a1 * d2) - (a2 * d1)) / ((a1 * b2 - a2 * b1))
    
        var point = new THREE.Vector3()
        point[zeroCoord] = 0
        point[A] = A0
        point[B] = B0
    
        return point
    }
    
    
    var planeA = new THREE.Plane((new THREE.Vector3(0, 0, 1)).normalize(), 100)
    var planeB = new THREE.Plane((new THREE.Vector3(1, 1, 1)).normalize(), -100)
    
    var [point, direction] = intersectPlanes(planeA, planeB)