找到从点到最近边缘

时间:2015-10-23 14:01:33

标签: c++ algorithm polygon quadtree r-tree

设置

  • 函数需要提供从点到多边形最近边缘的距离
  • 已知点位于多边形内部
  • 多边形可以是凸面或凹面
  • 需要测试许多点(数百万)
  • 每个点需要运行许多单独的多边形(数十个)
  • 预先计算和持久存储的数据结构是一种选择。
  • 最终搜索功能将使用C ++

对于函数实现,我知道一种简单的方法是使用标准距离到线段公式来测试到多边形的所有段的距离。这个选项规模相当慢,我相信应该有更好的选择。

我的直觉是,对于这种类型的功能应该有一些非常快速已知的算法,这些算法可以在游戏引擎中实现,但我不知道在哪里看。

我找到了在四叉树中存储线段的参考,这将提供非常快速的搜索,我认为它可以用于我的目的,以快速缩小哪个线段看作最近的线段和那么只需要计算到一个线段的距离。 https://people.cs.vt.edu/~shaffer/Papers/SametCVPR85.pdf

我无法找到任何代码示例来说明这是如何工作的。我不介意从头开始实现算法,但是如果存在一个经过测试的工作代码库,那么就不会明白这一点。

我一直在研究几个四叉树实现,我认为它的工作方式是为每个多边形创建一个四叉树,并将带有边界框的每个多边形线段插入到该多边形的四叉树中。

"查询"我将要创建的函数的一部分将包括创建一个点作为一个非常小的边界框,然后将其用于搜索四叉树结构,然后只能找到多边形的最接近部分。

http://www.codeproject.com/Articles/30535/A-Simple-QuadTree-Implementation-in-C

https://github.com/Esri/geometry-api-java/blob/master/src/main/java/com/esri/core/geometry/QuadTree.java

我真正的问题是,这对于快速搜索时间功能看起来是一种合理的方法吗?

有什么东西可以更快地运作吗?

编辑: 我一直在环顾四周,发现使用四叉树的一些问题。四叉树的工作方式有利于碰撞检测,但不能设置为允许有效的最近邻搜索。 https://gamedev.stackexchange.com/questions/14373/in-2d-how-do-i-efficiently-find-the-nearest-object-to-a-point

R-Trees看起来是更好的选择。 https://en.wikipedia.org/wiki/R-tree

efficient way to handle 2d line segments

根据这些帖子,R-tree看起来像赢家。也很方便看到C ++ Boost已经实现了它们。这看起来足够接近我计划做的事情,我将继续实施并验证结果。

3 个答案:

答案 0 :(得分:4)

修改 由于我已经实现了PMR四叉树,我现在看到,最近邻搜索比我描述的要复杂一点。 如果搜索点的四元搜索结果为空,则会变得更复杂。 我记得Hannan Sammets中的某个描述:多维搜索结构。 给出下面的答案,我想到了搜索具有指定距离的所有物体。对于PMR四叉树来说这很容易,但只是找到最接近的更复杂。 修改结束

我不会使用R-Tree R树上的弱点(和强点!)是将空间分隔成矩形 已知有三种算法可以进行分离,但没有一种算法适用于所有情况。 R树实现起来非常复杂。 那为什么呢?仅仅因为R-Trees在完美实现时可以比四叉树快两倍。四叉树和R树之间的速度差异无关紧要。货币差异是。 (如果你有两个工作代码我将使用PMR四叉树,如果你只有R-Tree的代码然后使用它,如果你没有使用PMR四叉树)

Quad tree(PMR)始终有效,并且易于实现。

使用PMR四叉树,您只需找到与搜索点相关的所有段。结果将是几个部分,然后你只需检查它们并准备就绪。

告诉四棵树的人不适合或邻居搜索,不知道有数百种不同的四棵树。对于点四叉树而言,非适用性是正确的,而不适用于存储边界框的PMR树。

我曾经重新描述了在POINT-Quadtree中寻找邻居点的强制性描述。对于PMR-quadtree我无事可做(对于指定矩形区间内的搜索),没有代码更改,只需迭代结果并找到最接近的。

我认为对于你的问题,有比Quad树或R-Tree更好的解决方案,但重点是PMR始终有效。只需实现一次,并使用if进行所有空间搜索。

答案 1 :(得分:3)

由于要测试的点比多边形多得多,您可以考虑对多边形进行一些相当广泛的预处理,以加快平均测试次数,以找到每个点最近的线段。

考虑这样的方法(假设多边形没有洞):

  1. 走多边形的边缘并沿每条等距线
  2. 定义线段
  3. 测试线段的哪一侧是限制最近线段的潜在集合
  4. 构建算术编码树,每个测试加权由线段的半空间剔除的空间量。这应该可以在确定一个点的最近段时提供良好的平均性能,并且可以同时开启多点并行测试的可能性。
  5. 此图表应说明这一概念。蓝线定义多边形,红线是等距线。

    请注意,需要支持凹多边形会大大增加复杂性,如6-7-8区域所示。凹面区域意味着延伸到无穷大的线段可以由任意相隔很远的顶点定义。

    您可以通过将凸包拟合到多边形然后对大多数点进行快速凸起测试来分解此问题,并且仅对影响范围内的点进行额外的工作"凹区域,但我不确定是否有快速的方法来计算该测试。

    Equidistance decomposition

答案 2 :(得分:1)

我不确定你提出的四叉树算法有多棒,所以我会让别人对此发表评论,但我想到了一些可能快速而强大的东西。

我的想法是你可以通过KD树表示一个多边形(假设顶点是时间上的静态),然后找到最近的两个顶点,进行最近的2邻居搜索,无论该多边形位于该多边形中的哪个点。如果我的想法是正确的,那么这两个顶点应该是创建最近的线段的顶点,而不管凸度。