使用二进制空间分区树的多边形测试中的快点

时间:2014-08-14 17:19:10

标签: c++ c algorithm geometry computational-geometry

我正在尝试以一种在以下情况下有效的方式编写Ray强制转换算法(http://en.wikipedia.org/wiki/Point_in_polygon):

  • 算法将使用相同的多边形多次调用,但a 不同点
  • 多边形具有大量顶点

多边形很简单,但不一定是凸面。

我将使用右侧点(xp,yp)的水平光线:xr = xp + a,a> = 0,yr = yp。

不必循环遍历多边形的所有边并检查该点是否在边的y范围内,我想使用一些二进制空间分区树技术(http://en.wikipedia.org/wiki/Binary_space_partitioning)来快速找到这样的边。

我想象一个盒子的二叉树:

struct Box {
    float               min, max;
    Box               *leftChild; // [min,mid]
    Box              *rightChild; // [mid,max]
    std::vector<int> edgeIndices; // edges that are completely within the box
};
  1. 所有边都放在根框中,其中min = min y(多边形)和max = max y(多边形)。这成为当前的盒子。
  2. 当前框(min,max)分为:left :( min,mid)和right:(mid,max)。完全位于左侧或右侧的边缘将移动到该子框中。
  3. 对于左右儿童重复步骤2,直到每个框包含少于预定数量的边缘或该儿童的深度超过预定义的最大深度。

    现在为了找到哪个边与一个值yp相交:从根框开始并向下遍历,沿着路径将所有边加在一起。

    如何找到最佳中间值?我希望树尽可能平坦和平衡。也就是说,左边和右边的孩子的边数应该大致相同。

    我可以,例如在min y或max y上对边进行排序,并使用中间边的平均y作为分割点(mid)。

4 个答案:

答案 0 :(得分:1)

如果你有一个非凸多边形,其中大多数边穿过某个y值,那么当你查询具有该y值的点时,你将获得边数的基本线性时间来解决多边形查询中的点。如果你有很多预处理时间和预处理空间,那么你可以根据y坐标对顶点进行排序,并在每对相邻的y坐标顶点之间定义一条水平切割线,并根据它们的x值对边缘进行排序。穿过水平切割线。这将给出最差O(n ^ 2)大小的数据结构,但可能更小。然后,给定一个查询点,您可以二进制搜索以找到其y坐标最接近查询点的y坐标之上和之下的两个顶点,然后在这些边上进行二分搜索以查找查询点的x-位置坐标位于边列表中,然后根据边的排序列表中的点的x位置是偶数还是奇数来报告内部或外部。查询时间为O(log n)

答案 1 :(得分:1)

您可以使用BSP树,其中节点是2D平面,将空间划分为两个区域。在这种方法中,叶子总是凸多边形,它们位于主多边形的外部或内部。这与Quake和所有FPS克隆的制作方式类似(寻找PVS - 可能的可见集)。请注意,创建此结构将需要大量多边形切割,因为每个节点将主多边形划分为子多边形。使用这种结构非常简单:从根开始,用节点的平面检查你的点,然后选择一个包含它的子节点。最后你到达叶子,无论是在内部还是外部。然而,关键问题是如何选择分界面。不幸的是,我没有答案。显然,人们可以选择多边形边而不是任意线,并考虑其他几个因素。最常见的是:最小化未来的分割数或最均匀地划分空间。但坦率地说,我不太确定这个结构,因为它适用于游戏和其他交互式演练。我认为它适用于具有大量边缘的多边形。

答案 2 :(得分:1)

您可以使用树形图而不是bsp树。树形图沿x轴和y轴分割,您可以按降序对边缘进行排序。

答案 3 :(得分:0)

您正在构建的结构实际上是一个边界体积层次结构,可用于光线跟踪。我们的想法是在边界体积层次的叶子中有边缘,并在光线与盒子相互作用时下降树。

http://en.wikipedia.org/wiki/Bounding_volume_hierarchy

为了有效地下降到树中,您可以使用表面区域启发式(SAH)。它也可以用于边界卷层次结构。我们的想法是使用下降到左侧或下侧的概率来估计遍历层次结构的成本,然后最小化该成本。当进一步下降到层次结构中的成本高于仅通过所有剩余边缘循环时,SAH也可以实现停止条件。

这个问题链接到描述算法的论文: KDTree Splitting