你可以尝试基于
四叉树或其他空间索引的2D数据结构来实现算法。
具体思路如下:
在四叉树的每个叶子节点中,存储与该正方形相交的任何线段的引用。初始状态下,分辨率为零,即所有线段都在未划分的边界框节点中。
对于每条射线,查看射线的起点并细分包含它的节点,直到节点仅与一个线段相交。如果细分后该节点不与任何线段相交,则通过沿着射线移动到下一个节点来继续搜索。如果节点内部相交了一条线段,则已经找到了第一个相交点,可以停止沿该射线的搜索。如果射线没有与节点内的线段相交,则可以从搜索中剪枝该线段,并移动到射线相交的下一个节点。
显然,这个算法可以并行运行,通过同时沿着每条射线进行搜索。虽然四叉树是共享的,但随着它的细分,线程很快就不会竞争访问。
运行时间:
运行时间有点难分析,因为它取决于线段和射线的二维结构。也许有人可以帮助更好地分析运行时间,但这是我最好的尝试:
如果存在一个小距离d,它比最接近的非相交线段的任何射线的距离小,并且比同一射线上任意两个交点之间的距离小,则我们可以得到一个上限。然后我们可以称r=D/d为问题的“分辨率”,其中D是包围框的维数。
运行时间将受到
N * r
的限制,但这是一个极其粗略的界限,因为它基本上假设每条射线必须在其整个长度上以分辨率d进行解决。
让我们试着改进这个界限。
对于任何一条射线,考虑它的起点和第一个交点之间的部分。对于该部分上的任何点,我们可以询问哪个非相交线段最接近该点。然后我们可以询问有多少个不同的非相交线段最接近这条射线部分上的某个点。换句话说,如果我们制作了非相交线段的
Voronoi 图,我们正在询问这条射线部分将与多少个单元相交。如果我们让p成为任何射线的此问题的最大答案,则我们可以得到更好的上限。
N*p*log(r)
在沿着射线搜索时考虑最大所需分辨率。
因此,如果p和r是常数,我们有一个线性时间算法!
不幸的是,我非常确定p、N和r之间存在某种关系,阻止了p和r保持大致恒定。粗略猜测,我会说r ~ sqrt(N)
,这意味着回到了N log N
的运行时间。
并行化很有趣。如果我们假设有C个核心,那么搜索运行时间为N/C*p*log(r)
,但仍然存在划分子树的瓶颈问题。有log(r)
级别,每个段必须在至多N个位置上划分到这个级别,所以需要N/C*log(r)
的时间,这意味着总运行时间将是
(N/C)*p*log(r)
这基本意味着假设 C < N,它是完全可并行化的。
结论
在单核算法方面,这可能不太好,但对于具有特殊结构和/或可并行化的问题,它可能效果很好。我不建议尝试实现此算法,除非您已经仔细考虑过,并且确定可以平滑处理粗糙的边缘,并且我在分析中没有犯错误。我还建议搜索基于类似概念的已发布算法。