Python:球面的交集

时间:2019-01-08 01:38:18

标签: python python-3.x numpy math

我对编程非常陌生,但是当我最近学习如何以参数形式表示一个球体时,我决定进行一个有趣的项目。与三个球相交时,有两个相交点是截然不同的,除非它们仅在一个奇异点处重叠。

球面的参数表示:

我的代码是从Python/matplotlib : plotting a 3d cube, a sphere and a vector?的答案中修改而来的,增加了指示x,y和z原点以及球体半径的能力。许多类似的问题都是用C ++,Java和C#编写的,我根本无法理解(我几乎不知道自己在做什么,所以对我来说很容易。)

我的代码:

import numpy as np

def make_sphere_x(x, radius):
  u, v = np.mgrid[0:2 * np.pi:5000j, 0:np.pi:2500j]
  x += radius * np.cos(u) * np.sin(v)
  return x

def make_sphere_y(y, radius):
  u, v = np.mgrid[0:2 * np.pi:5000j, 0:np.pi:2500j]
  y += radius * np.sin(u) * np.sin(v)
  return y

def make_sphere_z(z, radius):
  u, v = np.mgrid[0:2 * np.pi:5000j, 0:np.pi:2500j]
  z += radius * np.cos(v)
  return z

#x values
sphere_1_x = make_sphere_x(0, 2)
sphere_2_x = make_sphere_x(1, 3)
sphere_3_x = make_sphere_x(-1, 4)
#y values
sphere_1_y = make_sphere_y(0, 2)
sphere_2_y = make_sphere_y(1, 3)
sphere_3_y = make_sphere_y(0, 4)
#z values
sphere_1_z = make_sphere_z(0, 2)
sphere_2_z = make_sphere_z(1, 3)
sphere_3_z = make_sphere_z(-2, 4)

#intercept of x-values
intercept_x = list(filter(lambda x: x in sphere_1_x, sphere_2_x))
intercept_x = list(filter(lambda x: x in intercept_x, sphere_3_x))
print(intercept_x)

问题:

  1. 很显然,必须有一种更好的方法来找到截距。现在,代码以相等的间隔生成点,并且在np.mgrid中的虚数下指定了间隔数。如果增加此比例,则相交的机会会增加(我认为),但是当我尝试将其增加至10000j或更高时,它只会吐出一个内存错误。

  2. 数组中存在明显的间隙,即使我可以使用超级计算机并将该值提升为淫秽值,此方法也很可能是错误的。现在,该代码将导致一个空集。

  3. 代码效率极低,不是说这是优先事项,而是人们喜欢三分法吗?

如果我在Stack Overflow上编码或提出问题方面的菜鸟错误,请随时发火。您的帮助非常宝贵。

2 个答案:

答案 0 :(得分:1)

使用scipy.optimize.fsolve,可以找到给定函数的根,前提是初始猜测在解决方案范围内。我用这种方法解决了您的问题,它似乎对我有用。唯一的缺点是它只能为您提供一个交叉路口。要找到第二根,您必须修改初始条件,直到fsolve找到第二根为止。

首先,我们通过定义(任意)半径和每个球体的中心来定义球体:

a1 = np.array([0,0,0])
r1 = .4
a2 = np.array([.3,0,0])
r2 = .5
a3 = np.array([0,.3,0])
r3 = .5

然后我们定义如何在给定角度u,v的情况下转换回笛卡尔坐标

def position(a,r,u,v):
    return a + r*np.array([np.cos(u)*np.sin(v),np.sin(u)*np.sin(v),np.cos(v)])

现在,我们考虑寻找方程的根。对于任何交点,都认为对于完美的u1,v1,u2,v2,u3,v3,位置position(a1,r1,u1,v1) = position(a2,r2,u2,v2) = position(a3,r3,u3,v3)是相等的。因此,我们找到三个必须为零的方程,即两个位置矢量的差。实际上,由于每个向量都有3个分量,所以我们有9个方程,足以确定6个变量。

我们发现将函数最小化为:

def f(args):
    u1,v1,u2,v2,u3,v3,_,_,_ = args
    pos1 = position(a1,r1,u1,v1)
    pos2 = position(a2,r2,u2,v2)
    pos3 = position(a3,r3,u3,v3)
    return np.array([pos1 - pos2, pos1 - pos3, pos2 - pos3]).flatten()

fsolve需要相同数量的输入和输出参数。因为我们有9个方程式,但只有6个变量,所以我只使用了3个虚拟变量,因此尺寸匹配。由于fsolve仅接受一维数组,因此必须在最后一行中展平数组。

现在可以使用fsolve和(相当随机的)猜测找到交点:

guess = np.array([np.pi/4,np.pi/4,np.pi/4,np.pi/4,np.pi/4,np.pi/4,0,0,0])

x0 = fsolve(f,guess)
u1,v1,u2,v2,u3,v3,_,_,_ = x0

您可以通过将收到的角度插入position函数中来检查结果是否正确。

答案 1 :(得分:0)

使用三角函数可以更好地解决该问题。

将问题简化为2D圆,我们可以这样做:

const sum = require('./sum1');

sum();

test('adds 1 + 2 to equal 3', () => {
  expect(result).toBe(3);
});