Line Segment容器用于快速Ray交叉? (2D)

时间:2009-04-09 03:38:39

标签: c++ geometry intersection line-segment

我有一条光线,我需要找到它击中的最近的线段。如果我先对行段进行排序,我认为可以在O(log n)时间内执行此操作,但我不记得如何对它们进行排序...我认为某种树最适合,但我如何排序它们的起点和终点都是?如果可能的话,我还想快速插入这个数据结构。

一条光线与一条线段有很多代​​码,但我需要一条光线对比很多线段...我不知道google的条款。

指向相应文章的链接很好,C ++代码甚至更好。谢谢! :)

PS:线段实际上是非自相交多边形的边缘,按CCW顺序排序......但我认为以不同的方式对它们进行排序可能有一些优势吗?

这都是2D。


第二个想法,我不完全确定 是否可能。某种空间分区可能有所帮助,但除此之外,我无法想出任何方式对线进行排序,以便可以将它们与任意光线进行比较。

5 个答案:

答案 0 :(得分:7)

您可以使用多边形的边界框(min-max x,y坐标)并在框内构建网格。然后,对于每个单元格,记住穿过单元格的所有行。

找到这样的部分:

  • 找出射线首先击中的单元格(O(1))
  • 使用Grid traversal algorithm通过网格“绘制”光线。当您点击非空单元格时,检查其所有行,检查交叉点是否在单元格内并选择最近的交点。如果所有交叉点都在单元格之外,则继续(这是O(网格长度))。

您还可以使网格分层(即。quadtree - 您要求的树),然后使用相同的算法进行操作。 This is done in raytracing in 3D,时间复杂度为O(sqrt(N))。


或者,使用我在光线跟踪器中执行的方法:

  • 构建包含行的quadtree(文章中描述了构建四叉树) - 如果节点(=区域)包含太多对象到4个子节点(子区域),则将它们分开
  • 收集光线击中的四叉树的所有叶节点

    为根计算光线矩形交叉(不是硬)。如果根被光线击中,则递归地继续其子项。

关于这一点很酷的是,当一个树节点命中时,你已经跳过处理整个子树(可能是一个大的矩形区域)。

最后,这相当于遍历网格 - 您收集光线路径上的最小单元格,然后测试其中的所有对象以进行交叉。您只需测试所有这些并选择最近的交叉点(这样您就可以探索光线路径上的所有线条)。

这是O(sqrt(N))。

在网格遍历中,当您找到交叉点时,可以停止搜索。要通过四叉树遍历实现这一目标,您必须以正确的顺序搜索子项 - 按距离对4个矩形交叉点进行排序,或者巧妙地遍历4个单元格网格(我们回到遍历)。

这只是一种不同的方法,我认为相对难以实现,而且效果很好(我在实际数据上测试了它 - O(sqrt(N)))。再次,如果你至少有几行,你只会受益于这种方法,当多边形有10条边时,与仅仅测试它们的好处相比,我认为很少。

答案 1 :(得分:1)

你怎么确定你会击中他们中的任何一个?如果它们是线条,则不太可能。

如果它确实是你试图测试的多边形(即平面),那么通常的方法就是首先与平面相交,然后在内部/外部测试该点(在2d坐标中)多边形。

也许我误解了你的确在做什么。

一般情况下,通过空间分区(以及邮箱等技术,如果您的测试费用昂贵),可以加速复杂数字的交叉点。

[更新:我误读了原始意图]你仍然可以使用(2d)空间分区,但开销可能不值得。个人测试很便宜,如果你的多边形不复杂,走路可能会更便宜。很难从描述中说出来。

答案 2 :(得分:1)

您在寻找基于扫描线/基于活动边缘表的方法吗?您可以查看Scanline Rendering的Wikipedia条目,或在Graphics Gems目录中搜索算法(主要是C,但也有一些C ++代码)。

答案 3 :(得分:1)

请记住,排序最多只能进行O(n log n)操作。你可能最好单独检查一下。

答案 4 :(得分:0)

要求澄清,这是正确的吗?

  • 您有一组动态的线段 L
  • 查询:从此点给出任意点(x,y)和任何光线方向,您需要确定 L中最近的线条(如果有的话)?

所以点(x,y)没有修复? (可能是任何一点,任何方向?)