如何查询所有位于aline上的点

时间:2014-04-01 09:08:16

标签: algorithm geometry

假设我有一组积分,

enter image description here

然后我定义了行L.如何获得b,d和f?

enter image description here

这可以使用kd-tree解决(稍作修改)?

== EDIT ==

我的计划如何运作:

  1. 定义一组积分
  2. L稍后定义,它与点集
  3. 无关

    我现在唯一的想法是:

    1. 获取第L行的中间点 m
    2. 基于点 m ,使用KD-Tree获取长度(L)/ 2半径内的所有点
    3. 对于每一点,测试它是否位于第L行
    4. 如果查询行上的某些点略有谎言,也许我会添加共线阈值。
    5. 我的方法的运行时间取决于L长度,线越长,查询越大,需要检查的点越多。

5 个答案:

答案 0 :(得分:5)

您可以进行对数时间查找。我的算法以巨大的内存使用成本(高达立方数的点数)来实现:

如果您事先知道线的方向,则可以非常轻松地实现对数时间查找:让a*x + b*y = c为线的等式,然后a / b描述方向,{{{ 1}}描述了行位置。对于每个cab除外)和点,[0, 0]都是唯一的。然后根据点c的值对点进行排序;当你得到这一行时,在这个索引中进行搜索。

如果您的所有行都是正交的,则需要两个索引,一个用于c,一个用于x。如果使用四个索引,也可以按45°的线条查找。你不需要准确的方向;如果您知道所有点的边界区域,则可以搜索平行于跨越边界区域内查询线的索引方向的条带中的每个点:

strip

以上段落将“方向”定义为比率y。然而,这产生无限比率。更好的定义将“方向”定义为一对a / b,其中(a, b)a中至少有一个非零且两对b(a1, b1)定义iff (a2, b2)的方向相同。然后{a1 * b2 == b1 * a2代表(a / b, 1)非零,b代表(1, 0)零}是描述方向空间的一种特殊方式。然后我们可以选择b作为“无穷远处的方向”,然后按其第一个组件排序所有其他方向。

注意浮点不准确。建议使用有理算法。如果选择浮点运算,请务必在检查点线入射时使用epsilon比较。

算法1 :只需选择一些值(1, 0),准备n索引,然后在查询时选择一个。不幸的是,缺点很明显:查找仍然是范围扫描,因此是线性的,并且随着方向越来越远离索引的速度,预期的加速下降。如果边界区域比大多数点的区域大得多,那么它也没有提供任何有用的东西(你可以分别从密集区域中搜索极值点)。

理论查找速度仍然是线性的。

为了以这种方式实现对数查找,我们需要一个每个可能方向的索引。不幸的是,我们不能拥有无限多的索引。幸运的是,类似的方向仍然会产生类似的指数 - 只有少数交换的指数不同。如果方向足够相似,它们将产生相同的索引。因此,我们可以在整个方向范围内使用相同的索引。也就是说,只有两个不同点位于同一条线上的方向才会导致索引的变化。

算法2 以巨大的索引为代价实现对数查找时间:

准备时:

  • 对于每对点(A,B),确定从A到B的方向。将方向收集到有序集中,将集合称为重要方向集。
  • 将此组变为列表,并在两端添加“无穷远方向”。
  • 对于每对连续的重要方向,选择该范围内的任意方向,并为该方向准备所有点的索引。将索引收集到列表中。不要在此索引中存储任何特定的键值,只能引用点。
  • 为这些索引准备一个索引,其中方向是关键。

当用一条线查找点时:

  • 确定线方向。
  • 在索引索引中查找正确的点索引。如果线方向落在两个范围之间的边界,则任意选择一个。如果没有,您可以保证在线上最多找到一个点 由于只有n个重要方向,因此此索引中有O(n^2)个范围。查找将花费O(n^2)时间找到正确的。
  • 使用相对于线方向的位置作为键,查找该范围的索引中的点。此查询将花费O(log n)时间。

如果“无穷远处的方向”不在重要方向之间,则第一个和最后一个索引是相同的,因此可以获得轻微的改进。可以根据使用的索引进行进一步的改进。进入点数组的索引数组非常紧凑,但如果使用二进制搜索树(例如red-black treeAVL tree)作为点索引,则可以通过以下方式进行进一步的改进:将按值相同的子树合并为相同的参考。

答案 1 :(得分:2)

如果点均匀分布,则可以在Sqrt(n) x Sqrt(n)网格中划分平面。每个网格单元平均包含1个点,这是一个常量。

每条线与最多2 * Sqrt(n)个网格单元相交[对吗?证明需要:)]。检查这些单元格需要O(Sqrt(n))时间,因为每个单元格平均包含一定数量的点(当然,如果这些点存在偏差,则不会保留这些点。)

答案 2 :(得分:0)

可以尝试下一个:

  1. 对于每个点,找到distance from a point to a line

  2. 更简单的是,对于每个点,将点坐标放在线方程中,它是否与线上的匹配(意味着0 = 0)

  3. 修改

    如果你有很多分 - 还有另外一种方法。 如果您可以对点进行排序,请创建2个排序列表:

    • 1按x值排序
    • 2按y值排序

    请说明您的行从(x1,y1)开始,到(x2,y2)

    结束

    很容易过滤其x值不在[x1,x2]之间或其y值不在[y1,y2]之间的所有点

    如果你没有分数 - 意味着这一行没有分数。

    现在将该行拆分为2,现在你有2行 - 再次运行相同的流程 - 你可以看到它的去向。

    一旦你有足够多的积分(供你选择) - 让我们说10,检查他们是否按常规方式上线

    这也使你能够接近"因为你需要这一行,并跳过没有相关点的地方

答案 3 :(得分:0)

  • 计算所有积分的边界框
  • 将该边界框划分为x个y单元格的统一网格
  • 将您的每个点存储在其所属的单元格中

现在,对于您要测试的每一行,您所要做的就是找到它相交的单元格,然后使用"距离行= 0"来测试这些单元格中的点。

当然,如果你要为一组给定的点测试很多行,那么效率很高。

答案 4 :(得分:0)

如果你有足够的内存,那么就可以使用Hough-algo方法。 使用匹配点列表(不是计数器)填充r-theta数组。然后对于每一行找到它的r-theta方程,并用给定的r-theta坐标检查列表中的点。

微妙的事情 - 如何选择阵列分辨率。