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