Polyline优雅的“左撇子”测试

时间:2012-05-14 12:20:03

标签: algorithm math geometry

假设:

  • (X,Y)坐标,即车辆的位置。
  • (X,Y)的数组,它们是折线中的顶点。请注意,折线仅包含直线段,没有弧线。

我想要的是什么:

  • 计算车辆是在折线的左侧还是右侧(或在道路的顶部)。

我的方法:

  • 迭代所有线段,并计算到每个线段的距离。然后,对于最近的段,您执行简单的左侧测试(例如,如here所述)。

可能出现的问题:

  • 当三个点形成小于90度的角度时(如图像中所示),会出现更复杂的情况。当车辆处于如下所示的红色区段时,最近的区段可以是两个中的一个。但是,如果第一个段被选为最近的段,那么 left-of 测试将产生 right ,否则 left 。我们可以很容易地看到(至少,我希望),正确的结果应该是车辆是的折线。

Error scenario

我的问题:

  • 我如何优雅地,但主要有效地处理这种特定情况?

到目前为止我的解决方法:

  • 从顶点开始计算该段上的一个点。
  • 使用欧几里德距离
  • 计算从车辆到两个点的距离
  • 保留计算点最接近的分段。

我对这个修复不太满意,因为我觉得我错过了一个更优雅的解决方案,我的修复感觉相当“hacky”。效率是关键,因为它用于实时嵌入式系统。

现有的代码库是用C ++编写的,所以如果你想用特定的语言编写,C ++就有我的偏好。 谢谢!

[编辑] 我将我的修复从垂直点更改为平行点,因为我认为跟踪线段比计算向外法线更容易。

4 个答案:

答案 0 :(得分:1)

让无穷大= M,其中M足够大。你可以认为一切都在方形[-M,M] x [-M,M]中,用你的折线分割正方形,你现在有两个多边形。然后检查汽车是否在给定的多边形中,可以非常简单地用角度完成。

我认为你的第一点和你的最后一点在坐标中有M。您可能需要添加其中一些点以具有多边形:( - M,-M),(M,-M),(M,M)和(-M,M)。

在折线左边有一个多边形后,求和角OĈP,其中O是固定点,C是汽车,P是多边形的一个点。如果总和为0则汽车在多边形之外,否则它在里面。

答案 1 :(得分:1)

此主题已停用很长时间,我相信它已经死了。我有一个解决方案。

  

但是,如果第一个段是,那么左侧测试将产生正确   选择为最近的段,否则

你使用过一些含糊不清的语言。我将使用来说明折线中的线段和象限来说明它们所划分的区域。因此,在您的情况下,您有一个红色象限,它似乎位于一个的右侧,而另一个位于另一个的左侧。

如果左侧测试为不同的段产生不同的答案,则应重新对段本身进行测试。在你的情况下,你有:

  • 象限位于第一段的右侧
  • 象限位于第二段的左侧

两个部分都不同意象限所在的位置,因此您还要进行两次消歧测试:

  • 第二段位于第一段的右侧
  • 第一段位于第二段的右侧

这使我们得出结论,第二段在第一段和象限之间 ,因为这两段中的每一段都位于第二段的不同侧。因此,第二段比第一段“更接近”,并且应该使用左右测试的答案作为正确答案。

(我几乎可以肯定你只能处理两个消除歧义测试中的一个,为了清楚起见,我已将两者都放在一起)

为了完整起见:我相信这个解决方案也能满足您对效率和优雅的要求,因为它使用了您从一开始就使用的相同方法(左侧测试),因此它符合所有指定的条件:它优雅,效率高,可以解决问题。

答案 2 :(得分:0)

只是一个简单的想法:是否可以连接折线的最后一个和第一个顶点,以便它变成多边形?然后你可以做一个简单的内/外检查确定车辆是左/右行(这个程度取决于多边形的方向)。

但是,此方法确实假设在连接最后一个和第一个顶点后多边形仍然不是自相交的。

答案 3 :(得分:0)

这是计算几何的一个标准问题。由于您要测试一个点(x0,y0)是否是给定曲面(您的折线)的左侧,您需要确定要根据其高度进行测试的段。一种简单的方法是构建每个段的较低点的树,并在其中搜索测试点的前任。一旦你有了这个片段,你就可以直接进行左边的测试:如果它在两个端点之间,或者它们在适当的一侧,那么你返回true。

我假设您保证折线的垂直范围大于您可能找到查询点的位置,并且该线不会垂直重叠。后一种假设可能很差。

响应OP的评论进行扩展:

请注意,问题中的角度示例与第一个假设相矛盾 - 折线未达到搜索点的高度。

概念化我的方法的一种方法是垂直排序您的线段,然后迭代它们,将点的y坐标与线段进行比较,直到您的点高于下端点并低于更高端点。然后,使用段的端点来计算给定y处的x截距。如果该点具有较低的x-coordinate,则它位于左侧,如果它具有更大的x坐标,则它位于右侧。

在实际实现中有两种方法可以改进这种解释,其中一种我提到过:

  1. 使用平衡搜索树查找正确的细分,而不是遍历排序列表,以便将时间从O(n)带到O(log n)
  2. 将搜索重新概念化为通过搜索点找到折线和水平线y = y0的交点。然后只需将交叉点的x值与搜索点进行比较。