【问题标题】:Generate new polygons from a cut polygon (2D)从切割多边形(2D)生成新多边形
【发布时间】:2010-12-19 00:40:39
【问题描述】:

我被这个小问题困住了,我解决这个问题的算法并不适用于所有情况。有人知道如何解决这个问题吗?

这是一个多边形示例:

example http://img148.imageshack.us/img148/8804/poly.png

正式说明

我们有一个以 CW 顺序定义多边形的点列表。我们也可以用is_cut(p)查询一个点是否是一个切割点,其中p是一个给定的点。现在我们要计算由这个“切割”引起的新多边形。

算法应该这样做:

输入:{a, c1, b, c4, c, c5, d, c6, e, c3, f, c2}

输出:{a, c1, c2}{b, c4, c3, f, c2, c1}{d, c6, c5}{e, c3, c4, c, c5, c6}

这是我当前的算法:

follow your points, CW
if the point is a cut point
-> go back trough the list looking for cut points
--- if next cut point is connected to the current cut point 
    and not part of the current poly, follow it
--- else keep searching
else
-> continue until you hit your starting point.
that's a poly
do this for every non-cut-point

如果您从cf 开始,则此算法不成立。

【问题讨论】:

  • 当我看到你的照片时,我终于明白了输出。但是我不认为,给定这个输入,计算机可以以某种方式神奇地猜测 C 坐标都属于一起。所以我认为除了多边形的坐标之外,您还需要一个单独的输入数组来指定这些索引中的哪些是要剪切的索引。更合乎逻辑的是:一个多边形和一个定义切割线的向量
  • 正确,我之前计算了 c_n 个点,因此我可以提供一个函数 is_cut(p),它会形成这样一个列表 {c1,...,cn},其中 n mod 2 == 0. 我很抱歉图片,但是 stackoverflow 不允许我发布图片:(。
  • 我还添加了一个伪代码算法,我用它来知道。
  • 嗯……那张照片让我想起了我每天在地下看到的东西。 (图片)alloyfirms.ru/bank/5295_moscow.gif
  • @pavel:这是我的地下地图ecampmany.com/NY/Subwaymap.gif

标签: algorithm polygon intersection computational-geometry


【解决方案1】:

首先,您应该计算切割线的哪些部分属于原始多边形的内部。这是一个经典问题,其解决方案很简单。鉴于您的点 c1, c2, c3 ... c6 完全按照此顺序沿线布置,那么线段 c1-c2c3-c4 等将始终属于多边形内部 (*)。

现在我们可以构造简单的递归算法来切割多边形。给定您的大输入数组 {a, c1, b, c4, c, c5, d, c6, e, c3, f, c2},从任何多边形点开始,例如,b;将其添加到数组 result。向前遍历输入数组。如果遇到

  • 普通多边形节点,将其推送到数组result
  • ck 节点,其中k 是奇数,寻找c(k+1) 并继续从其位置遍历。
  • ck 节点,其中k 是偶数,寻找c(k-1),跳转到它的位置并继续向前遍历。

对于最后两种情况,按照遇到它们的顺序将这些节点添加到 result 数组。将ck 节点添加到集合cut,并将另一个节点(c(k+1)c(k-1),无论你有什么)添加到全局集合中done.

如果您必须超出最后一个元素,请转到输入数组中的第一个元素。

迟早你会遇到你要遍历的初始节点。现在在 result 数组中,您已经切割了一个多边形。记住它。从属于 cut 集合且不属于全局 done 集合的每个节点的位置开始递归地重复该过程。

这就是我所看到的解决方案。但它是计算几何学,所以它可能会变得比看起来更复杂。


对于我们的例子,从b开始:

  1. done={},从b开始。第一次通过后会得到result=[b,c4,c3,f,c2,c1]cut={c4,c2}done={c3,c1};递归到c4c2 节点。
  2. done={c3;c1},从 c4 开始(从 1 开始递归)。此通关后,您将获得result=[c4,c,c5,c6,e,c3,c4]cut={c5,c3}done+={c6,c4};递归到c5
  3. done={c3;c1;c4;c6},从 c2 开始(从 1 递归)。此通关后,您将获得result=[c2,a,c1]cut={c1}done+={c2};不要递归到c1,因为它在done集合中;
  4. done={c3;c1;c4;c6;c2},从 c5 开始(从 2 递归)。此通关后,您将获得result=[c5,d,c6]cut={c5}done+={c6};不要递归到c5,因为它在done集合中;

瞧——你得到了你需要的 4 个多边形。


(*) 请注意,它需要更多的“数学”表示线。例如,如果其中一个多边形顶点在线上,则该顶点应加倍,即如果c 点更靠近右侧并且在红线上,则该直线上会有[c1, c2, c3, c, c, c6] 点,多边形数组将是[a, c1, b, c, c, c, d, c6, e, c3, f, c2]

有时(不在此示例中),它可能会导致切割“空”多边形,例如[a, a, a]。如果您不需要它们,您可以在后期消除它们。无论如何,它是具有大量边界情况的计算几何。我不能将它们全部包含在一个答案中...

【讨论】:

  • 引用:...段 c1-c2、c3-c4 等将始终属于多边形内部...,并不总是成立。例如,删除切割点c4c5,让c 成为切割点。
  • @Bart K.,没有错。添加说明。
  • 对不起,我不是故意暗示你错了。只是你让它听起来很容易,而(正如你自己提到的)需要考虑很多棘手的极端情况。
  • 惊人的答案!太好了,在您解释了该怎么做之后,您逐步完成了它。
【解决方案2】:

您可以应用 Weiler Atherton 剪裁(实际上是 Pavel 的建议),但有一个很大的警告。

由于浮点错误,W/A 剪裁算法极难正常工作 - 在剪裁线穿过顶点或恰好沿着多边形边缘的情况下,算法可能会混淆它应该遵循多边形周边的哪个“路径”,然后输出不正确的结果。

【讨论】:

  • 我的建议可以很容易地扩展到处理这种情况,但是我的算法不需要知道任何关于浮点运算的知识,它只是遍历给定的数组(也不需要太多精度)。
  • 哪个是正确的:“它是具有大量边界情况的计算几何”或“[它] 可以轻松扩展到处理此类情况”?任何尝试实现这些方法的人都可以告诉你,上面的算法只需要几分钟就可以实现,而且要花更长的时间才能真正开始在通用和有用的意义上工作。如果您在遍历节点层次结构时做出了一个错误的决定(很容易做到,因为大家都知道“计算机不能做数学”),您将生成错误的输出。
【解决方案3】:

每个点找到1边

选择一个未切割的桥(例如 a)并将其设置为在左侧(实际上不符合)

当您越过切点时,您到达的点的一侧会发生变化。所以你找到左/右点。

问题是您还应该考虑点的顺序应该是预先定义的。 (例如顺时针)

2从cx的每个中间部分开始,顺时针和逆时针走一次。

对于每个多边形,您只在一个方向上击中中间部分一次。

如果您“溢出” c,则意味着您达到了外部多项式。 如果你定义了位于 polgon 上的 c0 和 cmax 并且你有比,你可能会解决这个问题

input =  {a, c1, c0 ,c1, b, c4, c, c5, d, c6, c7, c6, e, c3, f, c2}

【讨论】:

    【解决方案4】:

    最简单的实现是Sutherland-Hodgman。它的一个问题是它在连接线一侧的多晶硅上留下了很少的零面积条。在你的例子中,这会给你类似的东西:

    {a c2 c3 e c6 c5 c c4 c1} 和 {b c1 c2 f c3 c6 d c5 c4}

    如果您能忍受这一点或弄清楚如何将它们分解成您想要的部分,那么您会发现进行实际剪辑的代码将尽可能简单。

    该实现只需要两个堆栈和一次通过多边形的顶点。在每个顶点上,您检查是否从上一个顶点开始越线。如果是这样,计算交叉点并将其推送到其中一个堆栈上。然后将新顶点推送到其中一个堆栈上。真的很简单。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-28
      • 1970-01-01
      • 2020-11-02
      • 1970-01-01
      • 2011-08-09
      • 2015-07-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多