【问题标题】:Find order of points to make a quadrilateral查找点的顺序以制作四边形
【发布时间】:2013-08-06 15:12:43
【问题描述】:

在将an answer 分配给"Given four coordinates check whether it forms a square" 时,我遇到了this answer,它检查平行四边形,然后检查直角。这有效,但前提是输入的点按特定顺序。也就是说,P1 和 P3 必须彼此“相反”,而不是相邻。

所以,问题。如果进来的四个点可以按任何顺序排列,你如何对它们进行排序,使它们按“正确”的顺序形成一个四边形?

我能想到的最简单的方法是:

for each valid permutation of points[]{ // see below for "valid"
    generate line segment for:
        points[0] -> points[1]
        points[1] -> points[2]
        points[2] -> points[3]
        points[3] -> points[0]
    if any line segment crosses another // use cross product
        continue
    return permutation
}

我知道大多数排列都是简单的旋转(0123 == 1230),所以我可以保持第一点“固定”。另外,我认为我可以通过仅考虑每个排列点的02 中的点来减少它,因为其他两个的顺序无关紧要。例如,如果0123 是一个多边形,那么0321 也是,因为它会生成相同的线段。

这让我只需要检查三个基本排列:

  • [0,1,2,3]
  • [0,1,3,2]
  • [0,2,1,3]

每个排列都有 6 次分段检查,因此总共有 18 次比较。

我想不出任何其他方法来做到这一点,但似乎我错过了一些东西。有一个更好的方法吗?正方形问题的答案很好,但如果我必须进行额外(最多)18 次检查以验证点的顺序是否正确,那么使用角间距离会更快。

【问题讨论】:

  • 这个问题是专门针对正方形问题的四边形,你想要一个所有四边形的通用解决方案还是可以?
  • 最好使用通用解决方案。问题开始是“如何弄清楚如何将它们放入方形问题中”,但我猜它可能还有其他有用的应用程序。
  • 我有一个愚蠢的问题:我们说的是二维点,对吧?
  • @beaker 是的,2D 仅用于此问题。

标签: algorithm geometry


【解决方案1】:

每个排列都有 6 次分段检查,因此总共有 18 次比较。

您不需要检查所有线段:检查线段[0-2][1-3](即两条对角线)是否相交就足够了。您需要检查线段是否相交,而不是线段所属的线,即线段之外的交叉点不算在内。

一旦你确定了起点"A",你最终会得到六种可能的排列:

其中两个(A-B-D-CA-C-D-B)都不错;剩下的四个是坏的。只需两张支票,您就可以得到一张好的:

  • 检查初始排列;如果好,就留着;否则
  • 交换点 1 和 2,并检查排列;如果好,就留着;否则
  • 恢复到原始排列,交换点 2 和 3,并保持该排列;它一定是“好”的。

【讨论】:

  • 这是有道理的。两个排列检查,每个交叉检查。我认为没有比这更简单的了。
  • 请注意 ABDC = ACDB、ABCD = ADCB 和 ACBD = ADBC。添加第 4 行(第 4 点和第 1 点之间的线),您应该会看到它。
  • @Dukeling 对,我故意跳过了方向对称性(顺时针与逆时针),以说服自己该图涵盖了所有六种可能性。
【解决方案2】:

实现一个名为 isParallelAndEqual(p0,p1,q0,q1) 的方法。这将检查线 p1-p1 和 q0-q1 是否平行且长度相等。

给定点 a、b、c 和 d,最终结果如下所示:

ifParallelAndEqual(a,b,c,d)||ifParallelAndEqual(a,c,b,d)

【讨论】:

  • 我更喜欢四边形的通用解决方案,不一定是平行四边形。不过,同意它对此很有用。
  • 在一般的四边形中,答案可能是模棱两可的。考虑这样一种情况,您在任何地方都有 3 个点,而第四个点在前三个点规定的三角形内。在这种情况下没有确切的答案(或者,所有答案组合都是有效的)
  • 没错,我想我的意思只是凸的。好点,我没有考虑过。
【解决方案3】:

您不能简单地检查以下所有内容,直到找到正确的内容吗? (也就是检查P1对面的点)

P3 = P1 + (P2-P1) + (P4-P1)
P2 = P1 + (P3-P1) + (P4-P1)
P4 = P1 + (P2-P1) + (P3-P1)

对于方形变体,如果它们恰好是轴对齐的,您可以这样做:(也就是说,相反的点是没有共同坐标的点)

if (P1.x != P3.x && P1.y != P3.y)
  check P3 = P1 + (P2-P1) + (P4-P1)

if (P1.x != P2.x && P1.y != P2.y)
  check P2 = P1 + (P3-P1) + (P4-P1)

if (P1.x != P4.x && P1.y != P4.y)
  check P4 = P1 + (P2-P1) + (P3-P1)

otherwise return false

【讨论】:

  • 你的第一点最有道理,现在我想了想。但是,第二个拒绝旋转的正方形。
  • 轴对齐方法是我想到的第一件事,但它确实限制了有用性。尽管如此,+1。不知道我的大脑是如何跳过我可以运行公式三遍的事实的。当然,这实际上只适用于正方形/平行四边形问题,而不是一般的四边形。
【解决方案4】:

这样做不是更简单吗:

  1. 检查点 0, 12 是否跨越三角形(如果它们是共线的,则四边形也是退化的)
  2. 检查以下路段是否有交叉:

[0, 3] and [1, 2]
[1, 3] and [0, 2]
[2, 3] and [0, 1]

如果它们都不相交,则四边形是非凸的。

否则,您应该只有一个相交的案例。您在那里找到了相反的顶点。

【讨论】:

  • 如果3,0,1 是共线的(按这个顺序),它不会看到[1,3][0,2] 相交吗?这是我在纸上提出的第一个反例,但我担心可能还有其他反例。我想我可以检查所有点组合的共线性,但是......
  • @Geobits 我认为这取决于交叉点检查。如果使用叉积,是不是很容易找到边界情况? (在[0,1] 中表示相交,所以正好 0 或 1 表示边界情况?)
  • 确实取决于。对于叉积,如果您使用浮点数学,则必须非常小心。有效/退化四边形之间的差异可能非常小,并且“完全为零”效果不佳。
猜你喜欢
  • 2011-10-23
  • 1970-01-01
  • 2012-12-06
  • 2015-08-21
  • 2017-12-28
  • 1970-01-01
  • 1970-01-01
  • 2013-10-22
  • 2012-08-26
相关资源
最近更新 更多