我正在编写一个实现SCVT(Spherical Centroidal Voronoi Tesselation)的程序。我从分布在单位球体上的一组点开始(我有随机点或等面积螺旋的选项)。将有几百到64K点。
然后我需要产生几百万随机样本点,每个样本找到集合中最近的点,并用它来计算该点的“权重”。 (这个权重可能必须从另一个球形集中查找,但对于任何给定的算法运行,该集合将保持静态。)然后我将原始点移动到计算点,并迭代该过程,可能是10或20次。这将为我提供Voronoi瓷砖的中心供后续使用。
稍后我将需要找到一个给定点的最近邻居,以查看用户点击了哪个图块。这在上述问题中很容易解决,并且无论如何都不需要超快。我需要高效的部分是单位领域数百万最近邻居。有什么指针吗?
哦,我正在使用x,y,z坐标,但这并不是一成不变的。看起来它会简化一些事情。我也使用C,因为我最熟悉它,但也没有坚持这个选择。 :)
我考虑过将螺旋模式用于采样点,因为这至少可以让我找到最后一个点的邻居作为下一次搜索的良好起点。但是,如果我这样做,看起来它会使任何类型的树搜索无用。
编辑: [对不起,我以为我很清楚标题和标签。我可以轻松生成随机点。问题是最近邻搜索。当所有点都在单位球上时,什么是有效的算法?]
答案 0 :(得分:3)
您的点均匀分布在球体上。因此,将它们转换为球坐标并离散是很有意义的。首先搜索2D网格将缩小在恒定时间内对球体的一小部分的最近邻居的选择。
答案 1 :(得分:1)
您可能会发现将点组织成称为八叉树的数据结构对于有效搜索附近点非常有用。见http://en.wikipedia.org/wiki/Octree
答案 2 :(得分:1)
我设计了一条曲线(我确定我不是第一条曲线)沿着球体从一极到另一极旋转。它与相邻绕组保持恒定距离(如果我做得对)。对于z
(北极的-1
到北极的+1
):
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)
围绕球体进行k/2
次旋转,每个绕组sqrt(4pi/n)
来自相邻绕组,而斜率dz/d(x,y)
为1/k
。
无论如何,设置k
使得缠绕间距离覆盖球体上的最大图块。对于主集中的每个点,计算曲线上最近点的theta
,并按这些数字索引点列表。对于给定的测试点,计算它(曲线上最近点的theta
),并在索引中找到它。从那里向外(在两个方向上)搜索到与当前最近邻居一样远的theta
值。达到该限制后,如果到该邻居的距离小于从测试点到下一个相邻绕组的距离,则找到最近的邻居。如果没有,请将theta
值跳过2pi
并以相同的方式搜索该绕组。
批判?
答案 3 :(得分:0)
以下是有关邻居搜索的文章:http://en.wikipedia.org/wiki/Nearest_neighbor_search 根据我的理解,你可以使用通过所有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中心。最小的距离将为您提供最近的中心。
答案 4 :(得分:0)
使用KD Trie是加快搜索速度的好方法。如果您可以容忍某些错误,您还可以获得明显更好的性能。 ANN库会在您选择的ε中为您提供结果。
答案 5 :(得分:0)
行。 NEARPT3 http://www.ecse.rpi.edu/Homepages/wrf/Research/nearpt3/nearpt3.pdf算法可能对您的情况有所帮助。这一切都取决于你能为N点使用多少空间。如果它是O(N * logN),则存在诸如基于kD树(http://www.inf.ed.ac.uk/teaching/courses/inf2b/learnnotes/inf2b-learn06-lec.pdf)的算法,其将用于O(logN)以找到最近点。在64K点Nlog_2 N =约10 ^ 6的情况下,这很容易适应现代计算机的内存。
答案 6 :(得分:0)
另一种比创建四叉树更简单的可能性是使用邻域矩阵。
首先将所有点放入2D方阵(通过将点转换为极坐标)。然后,您可以运行完整或部分空间排序,因此点将在矩阵内排序。
具有小Y(或phi)的点可以移动到矩阵的顶行,同样,具有大Y的点将移动到底行。具有小X(或θ)坐标的点也会发生同样的情况,这些点应移动到左侧的列。对称地,具有大X值的点将转到右列。
在进行空间排序后(有许多方法可以通过串行或并行算法实现这一点),您可以通过访问点P实际存储在其中的相邻单元格来查找给定点P的最近点。邻域矩阵。
您可以在下面的论文中阅读有关此想法的更多详细信息(您可以在线找到它的PDF副本):基于紧急行为的GPU上的超大规模人群模拟。
排序步骤为您提供有趣的选择。您可以使用本文中描述的奇偶换位排序,这种排序非常简单(即使在CUDA中)。如果你只运行一次,它会给你一个局部排序,如果矩阵接近排序,这可能已经很有用了。也就是说,如果你的点移动缓慢,它将为你节省大量的计算。
如果你需要一个完整的排序,你可以多次运行这种奇偶换位传递(如下面的维基百科页面所述):