9

我正在尝试绘制由 3D 中两个平面的交点形成的线,但我无法理解数学,这已在此处此处进行了解释。

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

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

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 x1 = planeA.normal.x,
    y1 = planeA.normal.y,
    z1 = planeA.normal.z,
    d1 = planeA.constant;

var x2 = planeB.normal.x,
    y2 = planeB.normal.y,
    z2 = planeB.normal.z,
    d2 = planeB.constant;

var point1 = new THREE.Vector3();
point1.x = 0;
point1.z = (y2 / y1) * (d1 - d2) / (z2 - z1 * y2 / y1);
point1.y = (-z1 * point1.z - d1) / y1;

var point2 = new THREE.Vector3();
point2.x = 1;
point2.z = (y2 / y1) * (x1 * point2.x + d1) - (x2 * point2.x - d2) / (z2 - z1 * y2 / y1);
point2.y = (-z1 * point2.z - x1 * point2.x - d1) / y1;

console.log(point1, point2);

输出:

THREE.Vector3 {x: -1, y: NaN, z: NaN, …}
THREE.Vector3 {x: 1, y: Infinity, z: -Infinity, …}

预期输出:

  • 沿交叉点 x = 0 的点,以及
  • 同一行上的另一个点 x = 1

如果有人能指出我应该如何工作的一个很好的解释,或者一个平面 - 平面相交算法的例子,我将不胜感激。

4

4 回答 4

7

这是http://geomalgorithms.com/a05-_intersect-1.html中描述的平面-平面相交解决方案的实现。本质上,您首先使用平面法线的叉积来找到两个平面中线的方向。其次,您在平面的隐式方程上使用一些代数(P . n + d = 0,其中 P 是平面上的某个点,n 是法线,d 是平面常数)来求解位于平面上的点平面的交点,并且也在 x=0、y=0 或 z=0 平面之一上。解决方案是由一个点和一个向量描述的线。我使用的是three.js 79版

/*

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)
于 2016-07-18T13:20:52.407 回答
4

当我遇到这样的问题时,我通常让一个符号代数包(在这种情况下是 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
于 2013-04-15T23:15:10.220 回答
3

先决条件


回想一下,要表示一条线,我们需要一个向量来描述它的方向和这条线所经过的点。这称为参数化形式:

line_point(t) = t * (point_2 - point_1) + point_1

其中point_1point_2是线通过的任意点,并且t参数化我们的线的标量。现在,如果我们将任意点放入上面的等式中,我们就可以找到line_point(t)线上的任何点。t

注意:这个术语(point_2 - point_1)什么都不是,而是一个描述我们线方向的向量,这个术语point_1什么都不是,但是我们的线经过的点(当然point_2)也可以使用。

算法


  1. 通过取平面法线的叉积来找到相交线的方向direction,即direction = cross(normal_1, normal_2)

  2. 以任何平面为例,例如一个平面,并在该平面上找到任意 2 个不同的点point_1point_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
    

    哪里point_1 = (x1, y1, z1)point_2 = (x2, y2, z2)

  3. 现在我们有 2 个点,我们可以构造位于第一个平面上的线的参数化表示: ,其中描述 了这条线上的任何点,并且只是一个输入标量(通常称为参数)。line_point(t) = t * (point_2 - point_1) + point_1line_point(t)t

  4. 使用标准线平面相交算法找到intersection_point线 line_point(t)第二个平面的交点(注意 代数形式部分,因为这是实现线平面相交所需的全部,如果您还没有这样做的话) .a2 * x + b2 * y + c2 * z + d2 = 0

  5. 现在找到了我们的交线,并且可以像往常一样以参数化形式构造:intersection_line_point(s) = s * direction + intersection_point,其中intersection_line_point(s) 描述了该交线上的任何点,并且s参数

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

调理


当 2 个法向量几乎共线时,这个问题变得normal_1非常病态。在几何上,这意味着这两个平面几乎彼此平行,并且在这种情况下是浮点算术的有限精度算术中以可接受的精度确定相交线变得不可能。normal_2

于 2013-04-15T23:51:07.940 回答
3

让three.js为您解决这个问题很容易。

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

m * x = v

那么 x 的解是

x = inverse( m ) * v

我们将为 m 使用 4x4 矩阵,因为 three.js 有一个inverse()用于Matrix4该类的方法。

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。

三.js r.58

于 2013-04-17T21:57:49.057 回答