【问题标题】:Find closest 2d point on polyline in constant time在恒定时间内找到折线上最近的二维点
【发布时间】:2016-04-20 03:15:11
【问题描述】:

是否有一种算法可以针对给定的 2d 位置找到由 n - 1 个线段(n 个线顶点)组成的 2d 多段线上的最近点 在恒定时间内?天真的解决方案是遍历所有段,测试每个段到给定位置的最小距离,然后对于最近的段,计算到给定位置的确切最近点,其复杂度为 O(n)。不幸的是,硬件限制阻止我使用任何类型的循环或指针,这意味着也没有像四叉树这样的优化来分层查找 O(log n) 中最近的段。

理论上,我有无限的时间来预先计算任何可用于查找的数据结构,并且这种预先计算可以任意复杂,只有运行时的查找本身需要在 O(1) 中。然而,硬件的第二个限制是我只有非常有限的内存,这意味着为域的每个可能的数值位置找到线上的最近点并将其存储在一个巨大的数组中是不可行的。也就是说,内存消耗应该在O(n^x)之内。

因此,问题归结为如何在没有任何循环的情况下在 2d 位置找到折线的最近段或其索引。这可能吗?

编辑:关于给定的位置……它可以是相当随意的,但只考虑一条线的最近邻域中的位置是合理的,给定一个恒定的最大距离。

【问题讨论】:

  • 您的“线”通常被称为折线,这样可以减少一些混淆。
  • 你说内存消耗应该在O(n^x)。我知道n 是顶点数。 x 是什么? nx 的合理范围是多少?你世界的xy 的范围是多少?例如,我是否需要支持对职位[0,0][987654321,123456789] 的查询?让我们得到所有定义的约束。

标签: algorithm data-structures 2d line computational-geometry


【解决方案1】:

创建一个轴对齐的框,其中包含所有带有一些填充的线段。将其离散为整数索引的 WxH 网格。对于每个网格单元,计算最近的线段,并将其索引存储在该网格单元中。

要查询一个点,在 O(1) 时间内计算它落在哪个网格单元格中。查找最近线段的索引。执行标准 O(1) 算法来精确计算直线上最近的点。

这是一个 O(1) 几乎精确的算法,将占用 O(WH) 空间,其中 WH 是网格中的单元数。

例如,这里是一些线段强加的空间的细分:

这是一个 9x7 的空间平铺,其中每种颜色对应一个边缘索引:红色 (0)、绿色 (1)、蓝色 (2)、紫色 (3)。注意空间的离散化如何引入一些错误。您当然会使用更精细的空间细分来尽可能减少错误,但代价是必须存储更大的网格。这种粗略的平铺仅用于说明。

您可以保持算法 O(1),并通过获取查询点、识别它所在的单元格,然后查看除该单元格之外的 8 个相邻单元格来使其更加精确。确定这 9 个单元格标识的边集。 (该集合最多包含 9 条边。)然后为每条边找到最近的点。然后在那些(最多 9 个)最近的点中保持最近的。

在任何情况下,这种方法对于某些病态情况总是会失败,因此您必须在决定是否要使用此方法时考虑到这一点。

【讨论】:

  • 您说要创建轴对齐的框,但您的图像显示的区域不是轴对齐的。您提出的解决方案不适用于轴对齐的框,尽管它确实减少了平均情况下所需的实际工作量。如果你的盒子不是轴对齐的,你仍然需要做点多边形测试,这使得解决方案不是 O(1)。
  • @JimMischel 你误解了我的建议。我画的图片没有离散化,只是为了说明目的。您将在我的图片上覆盖一个网格,并在网格的每个单元格中写入与其重叠最多的边缘索引。我将更新一个额外的数字以使这一点更清楚。
  • 我明白了。现在我了解您的“O(1) 几乎准确”评论。基本上,您可以保证一定程度的准确性,但不能保证完美。精度随着使用的内存量而增加。似乎合理,缺乏病理数据。
  • @JimMischel 绝对病理数据会破坏这种方法。这里的关键是它是一个真正具有这种数据结构的 O(1) 复杂度算法。
  • 对于O(log W + log H) 方法是否可以使用四叉树(实现为 n 维数组)的分层方法?具体来说,您从 2x2 开始,然后在数学上(您绘制的虚线对此效果很好)确定每个正方形中的所有点是否更接近不同的线,如果是,则该正方形可以分解为更小的正方形,如果不是,那么就没有必要了。基本上,您使用二进制网格坐标。这样,您可以仅在真正需要的地方增加网格的分辨率。诚然,您的示例中只有大约 9 个领域可以从中受益。
【解决方案2】:

您可以使用R-Tree 优化此类搜索,这是一种支持快速搜索的通用空间数据结构。这不是一个恒定时间算法;它的平均情况是 O(log n)。

你说你可以预先计算数据结构,但你不能使用任何循环。但是,是否有一些限制可以防止任何循环?任意搜索不太可能命中现有数据点,因此它至少必须在树中左右查看。

这个 SO 答案包含一些图书馆的链接:

Java commercial-friendly R-tree implementation?

【讨论】:

  • 感谢您的意见,我知道 R-Trees。不幸的是,就我而言,R-Tree 的遍历是不可能的。否则,它将是首选工具。
【解决方案3】:

您可以在O(1) 时间内找到一条线上最近的几何点,但这不会告诉您哪个给定顶点最接近它。您可以为此做的最好的事情是二分搜索,即O(log n),但当然需要循环或递归。

如果您正在设计 VLSI 或 FPGA,则可以并行评估所有顶点。然后,您可以比较邻居,并做一个大的连线或编码跨越最近几何点的线段的索引。从技术上讲,您会根据连线或中元素的数量获得某种O(log n) 延迟,但这种情况通常被视为接近恒定。

【讨论】:

    猜你喜欢
    • 2023-01-02
    • 1970-01-01
    • 2013-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-01
    • 1970-01-01
    • 2015-03-17
    相关资源
    最近更新 更多