从外面检查凸度

时间:2013-08-01 15:50:35

标签: algorithm math computational-geometry convex non-convex

是否有任何方法或算法可以从外部(周边)确定区域的凸(或非凸)属性?

一种方法是在每个周边点绘制切线,并讨论该线与周边点相交的次数。如果没有显示交叉(对于所有周边点),我们可以得出结论,区域是凸的。否则区域是非凸的。

第二种方法是确定每个周长点的内部天使,并讨论它是否大于180。如果周长中至少存在一个点,那么该区域是非凸的,它的内部天使大于180。

还有其他更简单的方法吗?

任何想法或解决方案都将不胜感激,谢谢。

2 个答案:

答案 0 :(得分:3)

执行此操作时要注意的一点是,当您遍历凸多边形的两侧时,所有转弯都将在同一侧。也就是说,如果您以逆时针方向绕顶点移动,则所有转弯都将在左侧;如果沿顺时针方向绕顶点移动,则所有转弯都将在右侧。如果你观察到转向观察到的任何其他物体的另一侧,那么你知道你正在处理一个非凸多边形。如果所有转弯都在一侧,则它是一个凸多边形。

所以,你需要做的就是一次看三个顶点,称它们为 v n v n +1 v n + 2 。然后,您可以确定连接 v n v n + 2 顶点 v n + 1 坐在上面。对于CCW, v n + 1 应位于线段的右侧,对于CW,它应位于左侧。有一种answer to another question which provides方法可以确定这一点。

您应该解决其他实施细节(例如如何处理n = N,多边形中的点数,但这应该为您提供一个起点。

基于此方法的实现将在O(N)时间和空间中运行。

更新:在回答下面的问题时,“非多边形区域如何”?一般来说,这要困难得多。在数学上,通过找到在该区域内部具有端点但在该区域外部的线段的某些部分的线段,可以将区域显示为非凸的。我怀疑你正在寻找一种使用数字计算机实现这一目标的方法,因此纯数学方法并不实用。

因此,在问题变得棘手之前,您将不得不对类型区域提供某种约束。也就是说,你必须约束你的问题空间,以便像边界周边的奈奎斯特采样这样的东西不会错误地将非凸区域识别为凸起。

假设您可以正确地约束问题,那么您可以提出的任何可以在数字计算机上实现的解决方案都必须接近该区域。您可以生成所讨论区域的分段线性近似并运行上面的算法,或者沿着区域的边界选择适当的点集并计算它们的导数。每个连续的样本应该将切线的角度沿相同方向旋转一些增量。但同样,采样也会下降。

如果您有关于构成您所在地区边界的任何非线性的性质的其他信息,您可能能够象征性地证明边界的一部分是否是凸的。然后问题减少到显示它在连接到相邻部分时保持凸起,这也将是特定问题。

所以,我的建议是,对于数字计算机实现,根据需要用多边形近似区域边界,并在该近似值上运行上面定义的方法。

答案 1 :(得分:1)

我使用的算法(伪代码):

function isConvex(vertices[Count] V):
  convex = true
  if Count <= 3 return convex
  for N = 0 to Count while convex:
    // line segment between previous and subsequent vertices
    LineSegment segment1 = new LineSegment(
         V[(N + Count - 1) % Count], V[(N + 1) % Count]);
    // line segment between the point and any other point
    LineSegment segment2 = new LineSegment((V[N], V[N+2 % Count]);
    if not segment1.intersects(segment2) then convex = false;
  return convex

我不知道这是否比你已经尝试过的算法更优或更简单。 LineSegment.intersects()方法已经存在,这使得它非常容易编写。

实际代码使用上一次迭代中的segment2作为当前迭代的第1段,使其更快,但即使在伪代码中也更复杂。

而且,对于它的价值,这个算法的原始版本是用汇编语言编写的,不再存在的处理器,所以我不会提供实际的代码; - )。