为什么这个随机生成的球形点云分布不均匀?
Why is this randomly generated spherical point cloud not uniformly distributed?
我正在尝试模拟从点源发出的辐射。为此,在给定源坐标和所需的发射光线长度的情况下,我在球坐标中随机生成一个方向矢量,将其转换为笛卡尔坐标,并 return 正确的终点。然而,当我 运行 这样做,并在 Blender 中可视化生成的点云(由所有随机生成的端点组成)时,我发现它在球体的 "poles" 处更密集。我希望这些点沿球体均匀分布。我怎样才能做到这一点?
随机生成函数:
def getRadiationEmissionLineSeg(p, t):
if(p.size == 4):
#polar angle spans [0, pi] from +Z axis to -Z axis
#azimuthal angle spans [0, 2*pi] orthogonal to the zenith (in the XY plane)
theta = math.pi * random.random()
phi = 2 * math.pi * random.random()
#use r = 1 to get a unit direction vector
v = sphericalToCartesian(1, theta, phi)
#parametric vector form: vec = p + tv
#p = point that lies on vector (origin point in case of a ray)
#t = parameter (-inf, inf) for lines, [0, inf) for rays
#v = direction vector (must be normalized)
return p + t * v
球面坐标->直角坐标转换函数:
def sphericalToCartesian(r, theta, phi):
x = r * math.sin(theta) * math.cos(phi)
y = r * math.sin(theta) * math.sin(phi)
z = r * math.cos(theta)
return npy.array([x, y, z, 0])
当你通过球面坐标变换点并且角度theta接近pi时,作为[0,2pi]x{theta}的图像的圆变得越来越小。由于 theta 是均匀分布的,所以靠近极点的点会更多。可以在网格图像上看到。
如果你想在球体上生成均匀分布的点,你可以利用这样一个事实,如果你用两个平行的平面切割一个球体,平面之间的球面条带的面积只取决于平面之间的距离飞机。因此,您可以使用两个均匀分布的随机变量在球体上获得均匀分布:
- -r 和 r 之间的 z 坐标,
- [0, 2pi) 与经度对应的角度 theta。
然后你可以很容易地计算出 x 和 y 坐标。
示例代码:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
r = 1
n = 1000
z = np.random.random(n)*2*r - r
phi = np.random.random(n)*2*np.pi
x = np.sqrt(1 - z**2)*np.cos(phi)
y = np.sqrt(1 - z**2)*np.sin(phi)
fig = plt.figure(figsize=(8, 8))
ax = plt.axes(projection='3d')
ax.scatter(x, y, z)
plt.show()
n=100,250,1000
的结果:
我正在尝试模拟从点源发出的辐射。为此,在给定源坐标和所需的发射光线长度的情况下,我在球坐标中随机生成一个方向矢量,将其转换为笛卡尔坐标,并 return 正确的终点。然而,当我 运行 这样做,并在 Blender 中可视化生成的点云(由所有随机生成的端点组成)时,我发现它在球体的 "poles" 处更密集。我希望这些点沿球体均匀分布。我怎样才能做到这一点?
随机生成函数:
def getRadiationEmissionLineSeg(p, t):
if(p.size == 4):
#polar angle spans [0, pi] from +Z axis to -Z axis
#azimuthal angle spans [0, 2*pi] orthogonal to the zenith (in the XY plane)
theta = math.pi * random.random()
phi = 2 * math.pi * random.random()
#use r = 1 to get a unit direction vector
v = sphericalToCartesian(1, theta, phi)
#parametric vector form: vec = p + tv
#p = point that lies on vector (origin point in case of a ray)
#t = parameter (-inf, inf) for lines, [0, inf) for rays
#v = direction vector (must be normalized)
return p + t * v
球面坐标->直角坐标转换函数:
def sphericalToCartesian(r, theta, phi):
x = r * math.sin(theta) * math.cos(phi)
y = r * math.sin(theta) * math.sin(phi)
z = r * math.cos(theta)
return npy.array([x, y, z, 0])
当你通过球面坐标变换点并且角度theta接近pi时,作为[0,2pi]x{theta}的图像的圆变得越来越小。由于 theta 是均匀分布的,所以靠近极点的点会更多。可以在网格图像上看到。
如果你想在球体上生成均匀分布的点,你可以利用这样一个事实,如果你用两个平行的平面切割一个球体,平面之间的球面条带的面积只取决于平面之间的距离飞机。因此,您可以使用两个均匀分布的随机变量在球体上获得均匀分布:
- -r 和 r 之间的 z 坐标,
- [0, 2pi) 与经度对应的角度 theta。
然后你可以很容易地计算出 x 和 y 坐标。
示例代码:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
r = 1
n = 1000
z = np.random.random(n)*2*r - r
phi = np.random.random(n)*2*np.pi
x = np.sqrt(1 - z**2)*np.cos(phi)
y = np.sqrt(1 - z**2)*np.sin(phi)
fig = plt.figure(figsize=(8, 8))
ax = plt.axes(projection='3d')
ax.scatter(x, y, z)
plt.show()
n=100,250,1000
的结果: