【问题标题】:Is there an easy and fast way of checking if a polygon is self-intersecting?是否有一种简单快捷的方法来检查多边形是否自相交?
【发布时间】:2011-06-20 01:12:19
【问题描述】:

我有一个System.Windows.Shapes.Polygon 对象,其布局完全由一系列点决定。我需要确定这个多边形是否是自相交的,即多边形的任何边是否在一个不是顶点的点与任何其他边相交。

有没有简单/快速的方法来计算这个?

【问题讨论】:

    标签: c# .net geometry polygon shapes


    【解决方案1】:

    检查是否有任何一对非连续线段相交。

    【讨论】:

    • 它们都应该在顶点处相交;那么问题就变成了在任意一组线段之间检查非顶点相交的最快方法是什么。
    • 好点,编辑它以检查非连续段是否相交。我认为没有内置方法,您必须编写一个方法。首先获取 Polygon.Points
    • 你不是说打开线段吗?我从未听说过不连续的线段。
    【解决方案2】:
    • 简单、缓慢、低内存占用:将每个段与所有其他段进行比较并检查交叉点。复杂度O(n2).

    • 稍快,中等内存占用(上面的修改版本):将边缘存储在空间“桶”中,然后在每个桶的基础上执行上述算法。 m 个桶的复杂度 O(n2 / m)(假设均匀分布)。

    • 快速和高内存占用:使用空间散列函数将边分割成桶。检查碰撞。复杂度O(n)

    • 快速且低内存占用:使用扫描线算法,例如here(或here)所描述的算法。复杂度O(n log n)

    最后一个是我最喜欢的,因为它具有良好的速度-内存平衡,尤其是Bentley-Ottmann algorithm。实现也不太复杂。

    【讨论】:

    • 在我们发言时,我正试图了解最后一个算法;特别是,我无法跟踪结构 T 的含义/目的。
    • T 是一个结构,它包含穿过扫描线 L 的线段。最有效的结构是二叉搜索树(另见Bentley–Ottmann algorithm)。
    • 我又加了一个link where the Bentley-Ottmann algorithm 用插图来描述。
    • 所以 C(p) 是所有线段(在 T 中找到),其中 p 是与线段共线的点。
    • 两个扫线算法链接都挂了:*(
    【解决方案3】:

    为了完整起见,我在此讨论中添加了另一个算法。

    假设读者知道轴对齐的边界框(如果不知道,请谷歌)使用“扫描和修剪算法”快速找到具有 AABB 冲突的边缘对可能非常有效。 (去谷歌上查询)。然后在这些对上调用交叉点例程。

    这里的优点是您甚至可以与非直边(圆和样条线)相交,并且该方法更通用,尽管几乎同样有效。

    【讨论】:

      【解决方案4】:

      我是这里的新手,这个问题已经够老了。但是,这是我的 Java 代码,用于确定由一组有序点定义的多边形的任何一对边是否交叉。您可以删除用于调试的打印语句。我也没有包含返回找到的第一个交叉点的代码。

      /**
       * Checks if any two sides of a polygon cross-over.
       * If so, returns that Point.
       * 
       * The polygon is determined by the ordered sequence
       * of Points P 
       * 
       * If not returns null
       * 
       * @param V vertices of the Polygon
       * 
       * @return
       */
      public static Point verify(Point[] V)
      {
          if (V == null)
          {
              return null;
          }
      
          int len = V.length;
      
          /*
           * No cross-over if len < 4
           */
          if (len < 4)
          {
              return null;
          }
      
          System.out.printf("\nChecking %d Sided Polygon\n\n", len);
      
          for (int i = 0; i < len-1; i++)
          {
              for (int j = i+2; j < len; j++)
              {
                  /*
                   * Eliminate combinations already checked
                   * or not valid
                   */
      
                  if ((i == 0) && ( j == (len-1)))
                  {
                      continue;
                  }
      
                  System.out.printf("\nChecking if Side %3d cuts Side %3d: ", i, j);
      
                  boolean cut = Line2D.linesIntersect(
                          V[i].X,
                          V[i].Y,
                          V[i+1].X,
                          V[i+1].Y,
                          V[j].X,
                          V[j].Y,
                          V[(j+1) % len].X,
                          V[(j+1) % len].Y);
      
                  if (cut)
                  {
                      System.out.printf("\nSide %3d CUTS Side %3d. Returning\n", i, j);
                      return ( ... some point or the point of intersection....)
                  }
                  else
                  {
                      System.out.printf("NO\n");
                  }
              }
          }
      
          return null;
      }
      

      【讨论】:

      • 我不同意彼得·杜尼霍的观点。这段代码有用的,因为重要的是算法,而不是编程语言。此外,Java 和 C# 非常相似,任何对此问题感兴趣的人都可以轻松地将代码移植到他们的目标语言。
      • @likebike 也许你可以投票给我一些积分?如果您认为这很关键,我也可以在 C# 中重新执行此操作。
      • @ParaParasolian,我投了赞成票。你有-1;现在你有 0。我认为你应该有更多。
      • 我同意理论上语言并不重要,如果你专注于有效的算法。但这并不是解决问题的有效方法。
      • @lwallent 您能否提供(或指出)更有效的方法?
      猜你喜欢
      • 2019-11-23
      • 2016-03-26
      • 1970-01-01
      • 2021-07-11
      • 1970-01-01
      • 2016-02-14
      • 1970-01-01
      • 1970-01-01
      • 2018-03-09
      相关资源
      最近更新 更多