我正在寻找一种算法来找到3个球体之间的公共交点。
如果没有完整的算法,详细描述数学方法也会非常有帮助。
到目前为止,这是我找到的唯一有用的资源: http://mathforum.org/library/drmath/view/63138.html
但是那里描述的方法都不够详细,无法编写算法。
我更喜欢第二篇帖子中描述的纯代数方法,但任何方法都可以。
我正在寻找一种算法来找到3个球体之间的公共交点。
如果没有完整的算法,详细描述数学方法也会非常有帮助。
到目前为止,这是我找到的唯一有用的资源: http://mathforum.org/library/drmath/view/63138.html
但是那里描述的方法都不够详细,无法编写算法。
我更喜欢第二篇帖子中描述的纯代数方法,但任何方法都可以。
这是我刚从维基百科文章中翻译的Python答案。不需要算法,有一个闭合形式解决方案。
import numpy
from numpy import sqrt, dot, cross
from numpy.linalg import norm
# Find the intersection of three spheres
# P1,P2,P3 are the centers, r1,r2,r3 are the radii
# Implementaton based on Wikipedia Trilateration article.
def trilaterate(P1,P2,P3,r1,r2,r3):
temp1 = P2-P1
e_x = temp1/norm(temp1)
temp2 = P3-P1
i = dot(e_x,temp2)
temp3 = temp2 - i*e_x
e_y = temp3/norm(temp3)
e_z = cross(e_x,e_y)
d = norm(P2-P1)
j = dot(e_y,temp2)
x = (r1*r1 - r2*r2 + d*d) / (2*d)
y = (r1*r1 - r3*r3 -2*i*x + i*i + j*j) / (2*j)
temp4 = r1*r1 - x*x - y*y
if temp4<0:
raise Exception("The three spheres do not intersect!");
z = sqrt(temp4)
p_12_a = P1 + x*e_x + y*e_y + z*e_z
p_12_b = P1 + x*e_x + y*e_y - z*e_z
return p_12_a,p_12_b
numpy.array([x,y,z])
创建的。 - roipoussiere这个答案的Python实现和使用示例可以在此GitHub仓库中找到。
使用此方法,解析解实际上非常好,可以告诉您何时存在解决方案,何时不存在解决方案(也可能只有一个解决方案)。没有理由使用牛顿法。
在我的测试中,我认为这比下面给出的三边测量技术更容易理解和简单。但是,两种技术都可以给出正确的答案。
考虑两个球体的交点。为了可视化它,请考虑连接两个球体中心的3D线段N。考虑这个横截面
(来源:googlepages.com)
其中红线是法线为N的平面的横截面。由于对称性,您可以从任意角度旋转此横截面,并且红线段的长度不会改变。这意味着两个球体的交点形成的结果曲线是一个圆,并且必须位于法线为N的平面中。
话虽如此,让我们开始寻找交点。首先,我们想要描述两个球体相交的结果圆。您不能使用1个方程式来描述3D中的圆,因为3D中的圆本质上是3D中的曲线,而您无法通过1个方程式来描述3D中的曲线。
考虑图片
(来源:googlepages.com)
让P成为蓝色和红色线的交点。让h是从点P向上沿着红色线的线段长度。让两个球体的距离表示为d。让x是从小圆心到P的距离。然后我们必须有
x^2 +h^2 = r1^2
(d-x)^2 +h^2 = r2^2
==> h = sqrt(r1^2 - 1/d^2*(r1^2-r2^2+d^2)^2)
即你可以解决h,这是交点圆的半径。您可以从x沿着连接2个圆心的线N找到圆的中心点C。
然后,您可以将圆完全描述为(X、C、U、V都是向量)
X = C + (h * cos t) U + (h * sin t) V for t in [0,2*PI)
其中U和V是垂直的向量,位于法向量N所在的平面上。
最后一部分最容易了。只需找到此圆与最终球体的交点即可。这只需要将圆的参数方程中的x、y、z代入最后一个方程式中,并解出t即可。
编辑 ---
您将得到的方程实际上非常复杂,您将有许多正弦和余弦等于某个值。要解决这个问题,可以有两种方法:
使用等式
e^(it) = cos t + i sin t
将余弦和正弦表示为指数形式,然后将所有e^(it)项分组,您应该会得到一个e^(it)的二次方程,可以使用二次公式解出e^(it),然后解出t。这将给您精确的解。这种方法实际上会告诉您是否存在一个解,两个解或存在一个解,具体取决于二次方法中有多少个点是实数。
使用牛顿法解出t,这种方法并不精确,但其计算方法更容易理解,并且对于这种情况非常有效。
这里是对Eric上面发布的图片的另一种解释:
设H为三个球心所在平面。设C1、C2、C3分别为球与H相交的圆。设Lij为连接Ci和Cj两个交点的直线,则三条直线L12、L23、L13相交于一个点P。设M为通过P且垂直于H的直线,则你需要求得的两个交点位于直线M上;因此,你只需要将M与任意一个球相交即可。