Geometry 单位球体上的最近邻,具有大致均匀分布的点

Geometry 单位球体上的最近邻,具有大致均匀分布的点,geometry,nearest-neighbor,Geometry,Nearest Neighbor,我正在编写一个实现SCVT(球面形心Voronoi细分)的程序。我从分布在单位球体上的一组点开始(我可以选择随机点或等面积螺旋)。将会有几百到64K的积分 然后,我需要生成可能数百万个随机样本点,为每个样本找到集合中最近的点,并使用该点计算该点的“权重”。(该权重可能必须从另一个球形集合中查找,但该集合将在算法的任何给定运行中保持静态。) 然后我将原始点移动到计算点,并迭代该过程,可能是10或20次。这将为后续使用提供Voronoi瓷砖的中心 稍后,我将需要找到一个给定点的最近邻居,以查看用户单

我正在编写一个实现SCVT(球面形心Voronoi细分)的程序。我从分布在单位球体上的一组点开始(我可以选择随机点或等面积螺旋)。将会有几百到64K的积分

然后,我需要生成可能数百万个随机样本点,为每个样本找到集合中最近的点,并使用该点计算该点的“权重”。(该权重可能必须从另一个球形集合中查找,但该集合将在算法的任何给定运行中保持静态。)

然后我将原始点移动到计算点,并迭代该过程,可能是10或20次。这将为后续使用提供Voronoi瓷砖的中心

稍后,我将需要找到一个给定点的最近邻居,以查看用户单击的瓷砖。这在上面的问题中得到了很好的解决,而且不需要非常快。我需要提高效率的部分是单位球面上的数百万个最近邻。有什么建议吗

哦,我用的是x,y,z坐标,但这不是一成不变的。看起来它会简化事情。我也在使用C,因为我对它最熟悉,但我也不喜欢这个选择

我已经考虑过对样本点使用螺旋模式,因为这至少为我提供了最后一个点的查找邻居,作为下一次搜索的良好起点。但如果我这样做,它看起来会使任何类型的树搜索毫无用处

编辑:
[对不起,我想我已经清楚了标题和标签。我可以很容易地生成随机点。问题是最近邻搜索。当所有点都在单位球体上时,什么是有效的算法?]

以下是关于邻居搜索的文章: 据我所知,你们可以使用简单的算法,通过所有的Voronoi中心,计算你们的点和中心点之间的3d距离

distance_2 = (x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2

其中(x_0,y_0,z_0)是您的兴趣点(单击),而{(x,y,z)}是Voronoi中心。最小的距离将为您提供最近的中心。

使用KD Trie是加快搜索速度的好方法。如果您能够容忍一些错误,您还可以获得显著更好的性能。库将在您选择的ε范围内为您提供结果。

确定。NEARPT3算法可能对您的情况有所帮助。这完全取决于你能为你的N点使用多少空间。如果是O(N*logN),那么有一些算法,比如kD-tree-based(),可以帮助O(logN)找到最近的点。在64K点的情况下,Nlog_2 N=约10^6,这很容易放入现代计算机的内存。

您可能会发现,将点组织到称为八叉树的数据结构中对于有效搜索附近的点非常有用。请参见,您的点均匀分布在球体上。因此,将它们转换为球坐标并离散化是很有意义的。首先搜索二维网格会将最近邻的选择缩小到恒定时间内球体的一小部分。

我设计了一条曲线(我肯定我不是第一条),它沿着球体从一个极点到另一个极点旋转。它与相邻绕组的距离保持不变(如果我做得对的话)。对于
z
-1
在南极到
+1
在北极):

它使
k/2
绕球体旋转,每个绕组
sqrt(4pi/n)
来自相邻绕组,而斜率
dz/d(x,y)
1/k

无论如何,设置
k
,使缠绕距离覆盖球体上最大的瓷砖。对于主集合中的每个点,计算曲线上最近点的
θ
,并根据这些数字为点列表编制索引。对于给定的测试点,计算其(
theta
曲线上最近点的θ),并在索引中找到它。从那里向外搜索(两个方向),搜索距离当前最近邻居最远的
theta
值。达到该极限后,如果到该相邻绕组的距离小于从测试点到下一相邻绕组的距离,则找到最近的相邻绕组。如果不是,将
theta
值跳转
2pi
,并以相同的方式搜索该绕组


评论?

另一种比创建四叉树更简单的可能性是使用邻域矩阵

首先将所有点放置到二维方阵中(通过将点转换为极坐标)。然后,您可以运行完全或部分空间排序,因此点将在矩阵中排序

具有小Y(或φ)的点可以移动到矩阵的顶行,同样,具有大Y的点可以移动到底行。同样的情况也会发生在X(或θ)坐标较小的点上,这些点应该移动到左侧的列上。对称地,X值较大的点将指向右列

完成空间排序后(通过串行或并行算法,有很多方法可以实现这一点),只需访问点p实际存储在邻域矩阵中的相邻单元,即可查找给定点p的最近点

你可以在下面的文章中阅读更多关于这个想法的细节(你可以在网上找到它的PDF副本):基于紧急行为的GPU超大质量人群模拟

排序步骤为您提供了有趣的选择。您可以只使用本文中描述的偶数-奇数转置排序,这非常容易实现(即使在CUDA中)。如果只运行一次,它将为您提供一个部分排序,如果您的矩阵接近排序,这将非常有用。也就是说,如果点移动缓慢,将节省大量计算

如果你需要一个完整的排序,你可以运行这样的奇偶tran
n = a constant defining a given spiral
k = sqrt(n * pi)

r = sqrt(z^2)
theta = k * asin(z)
x = r * cos(theta)
y = r * sin(theta)