【问题标题】:Checking convexity from outside [closed]从外部检查凸度[关闭]
【发布时间】:2013-08-01 15:50:35
【问题描述】:

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

一种方法是在周长的每个点上绘制切线,并讨论这条线与周长点相交的次数。如果没有显示相交(对于周长的所有点),我们可以断定区域是凸的。在其他情况下,区域是非凸的。

第二种方法是确定周长每个点的内角,并讨论它是否大于180。如果周边至少有一个点存在,则该区域是非凸的,它的内角大于 180。

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

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

【问题讨论】:

  • Cross posted at the Math SE。请注意,在多个网站上交叉发布问题只是为了吸引更广泛的受众is not permitted
  • @MvG 最好在注册(登录)时提供一份 codex(网站指令集)的副本。无论如何,我尝试从下次注册问题时选择最佳站点。

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


【解决方案1】:

这样做时要注意的一点是,当您遍历凸多边形的边时,所有转弯都将指向同一侧。也就是说,如果您以逆时针方向遍历顶点,则所有转弯都将向左;如果您以顺时针方向遍历顶点,则所有转弯都将向右。如果您曾经观察到转向与观察到的任何其他人相反的一侧,那么您就知道您正在处理一个非凸多边形。如果所有的转弯都在一侧,那么它是一个凸多边形。

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

还有一些其他的实现细节你应该解决(比如如何处理 n=N,你的多边形中的点数,但这应该为你提供一个开始的地方。

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

更新:针对以下问题,“非多边形区域怎么样”?一般来说,这要困难得多。从数学上讲,可以通过找到一条端点在区域内部但线段的某些部分在区域外部的线段来显示该区域是非凸的。我怀疑您正在寻找一种使用数字计算机实现此功能的方法,因此纯数学方法并不实用。

因此,在问题变得棘手之前,您将不得不对类型区域提供某种限制。也就是说,您必须限制您的问题空间,以便边界周长的奈奎斯特采样等事情不会错误地将非凸区域识别为凸区域。

假设您可以适当地限制问题,那么您可以提出的任何可以在数字计算机上实施的解决方案都必须近似该区域。您可以生成相关区域的分段线性近似值并运行上述算法,或者选择沿区域边界的适当点集并计算它们的导数。每个连续的样本都应将切线的角度沿同一方向旋转一些增量。但又一次,它涉及到抽样。

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

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

【讨论】:

  • 感谢您记住这些事实。非多边形区域呢?
  • @ZiaPandorra:见上面的更新。
  • 感谢生动的建议
【解决方案2】:

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

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() 方法已经存在,因此非常容易编写。

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

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

【讨论】:

  • 如果您运行您提出的方法,我将不胜感激。
猜你喜欢
  • 2020-08-23
  • 2014-03-05
  • 2017-05-16
  • 2020-06-21
  • 2019-12-05
  • 2021-11-07
  • 2023-04-03
  • 2019-12-24
  • 1970-01-01
相关资源
最近更新 更多