【问题标题】:Algorithm to join 4 co-ordinates such that it always results in a quadilateral连接 4 个坐标的算法,使其始终产生四边形
【发布时间】:2023-03-06 15:55:01
【问题描述】:

我们得到了 2D 平面上 4 个点的坐标。我们如何才能找到将它们与行连接起来形成quadilateral 的订单(只要可能)?

【问题讨论】:

  • 如果点共线怎么办?
  • 这种情况下需要画一条直线。
  • 只有 3 种可能性:ABCD、ABDC、ACBD。都试试?

标签: algorithm math geometry coordinate-systems coordinate


【解决方案1】:

考虑通过绘制由前三个点定义的三条线获得的平面的划分。它定义了 7 个区域。您可以通过三个符号面积测试(三角形ABD、BCD、CAD的代数面积)轻松找到第四个点属于哪个区域。

在每种情况下绘制四边形都很简单(每种情况可以有一个、两个或三个解)。

在下面的示例中,如果 D 在区域 -++ 中,ADBC 就可以。

实际上两个区域评估就足够了:如果第一个测试返回-(区域-+--++--+),则ADBC 是一个解决方案,否则如果第二个测试返回-(区域@ 987654329@ or +--), ABDC 是一个解决方案,否则(区域++- or +++)ABCD 是一个解决方案。

【讨论】:

  • 您是如何根据-++ 之类的 3 个术语得出签名区域测试的? -++ 在这里有什么尊严!请解释一下。
  • @shekharsuman:三角形 ABD、BCD、CAD 的代数面积。 en.wikipedia.org/wiki/Triangle#Using_coordinates
  • @shekharsuman:我不感谢你的反对。这是一个最佳解决方案,实施起来非常简单。两次区域评估,两次测试!
  • @shekharsuman:你错过了整件事。共线性检验与带符号区域的表达式相同。这也是计算几何的标准。您执行四次而不是两次,然后删除重要信息,即标志。这迫使您通过排序进行后处理(您没有清楚地详细说明)。
【解决方案2】:

考虑仿射变换

Px = Ax + u (Bx - Ax) + v (Cx - Ax)
Py = Ay + u (By - Ay) + v (Cy - Ay)

它将(0, 0) 映射到A(1, 0)B(0, 1)C。 (这将三角形 ABC 置于规范位置。)

求解 2x2 线性系统

Dx = Ax + u (Bx - Ax) + v (Cx - Ax)
Dy = Ay + u (By - Ay) + v (Cy - Ay)

为您提供与D 对应的(u, v) 的值。

那么,

if u < 0 => ABCD
else if v < 0 => BCAD
else => CABD

生成的四边形与三角形ABC 具有相同的方向。

【讨论】:

  • 这是一个更好、更智能的作品。 +1。 :) 请不要抱怨我赞成你的回答。 :P
  • 这是我其他答案的精确复制品,用规范坐标改写。计算是相同的(使用 Cramer 时的 2x2 行列式再次是带符号的区域)并且讨论涉及相同的 2 个比较/3 个结果。它确实更具可读性。
  • 但是。最后,它更具可读性。无论如何,我也从另一个答案中删除了我的反对票,因为我已经意识到了这一点。
  • @shekharsuman:谢谢。考虑所有这些区域的“深层”原因是分析解空间的几何形状。你学到了两件事:1)区域的边界是直线,所以共线性(或面积)测试就足够了,2)有 7 个不同的区域,所以 3 测试足以将它们分开。 (事实证明,两个就足够了。)
【解决方案3】:

为了清楚起见,我将p_n 的坐标视为(x_n, y_n) 的点。

为了连接 4 个点,您可以按照以下步骤操作:

  1. 用最小的x 得到点p_1
  2. 计算从p_1 到其余每个点的3 行中的slope
  3. p_1 与构成坡度最大的线的点p_2 连接。
  4. p_1 与构成斜率最小线的点p_3 连接。
  5. 将剩余的点p_4p_2p_3连接起来。

如果有不清楚的地方请告诉我。

【讨论】:

    【解决方案4】:

    编辑:这个答案已经被证明是错误的。

    1. 计算四个点的中心。
    2. 按逆时针方向(或顺时针方向)枚举点。
    3. 将它们链接在一起。

    【讨论】:

    • 第2步需要角度计算,这似乎没有必要。
    • 如果四边形不是凸的,这并不总是有效。例如,等边三角形的角上的三个点,中间的第四个点。
    • @PaulHankin 是的,你是对的……让我再想一想!
    【解决方案5】:

    编辑:正如 cmets 中所指出的,它仅在特定情况下有效,因此是一个糟糕的答案。

    可以通过找出 4 个点中的哪一对点之间的距离最大来绘制四边形。一旦找到这对,通过将剩余的两个点与该对的每个点连接起来绘制四边形。

    【讨论】:

    • (0,0), (2,1), (3,1), (10,0) 的输入与此算法相矛盾。
    • @shekharsuman:夏皮罗是对的。该算法链接 (1,0)、(1,3)、(2, 0) 和 (2,3),但 (2, 0) 与 (1,3) 交叉。
    【解决方案6】:

    您可以使用任何well-known algorithms for convex hull 的简化形式。贾维斯会很容易。如果凸包是三角形,则四边形是凸的。只需在边缘列表中的任意位置插入缺失点。如果凸包是一条线(2 个端点),只需对 x 或 y 坐标上的所有点进行排序即可得到退化四边形。 (如果更接近水平(abs delta x > abs delta y),则使用 x 进行排序,否则使用 y。)

    【讨论】:

      【解决方案7】:

      我想,你每次只需要连接两个点,我们会得到一个线段并检查其余的两个点是否在该线段的同一侧,如果不是那不是所需四边形的线段,如果是,则继续使用不同的点集(即点可以是该段的坐标之一,另一个将形成剩余的两个点)并检查相同的内容,直到得到 4 个线段

      【讨论】:

        【解决方案8】:

        四处寻找凸包算法。其中一个包括两个步骤:在给定的一组顶点(可能是凹的)上构建一个普通多边形,然后删除“凹顶点”,使剩余的多边形变为凸多边形。

        第一步是解决您的问题。

        当然,这有点矫枉过正。对于 4 个顶点,只需按顺序(以任何顺序)设置它们,然后验证连接点 1-2 和 3-4 的线段是否相交;如果是,交换点 2 和 3;或者可能边 2-3 和 1-4 相交 - 然后交换点 3 和 4。完成。

        验证线段 AB 和 CD 是否相交 测试点 A 和 B 位于 CD 线的相对两侧,而点 C 和 D 位于线 AB 的相对两侧。

        要确定点 K 所在的线 PQ 的一侧,请计算 PQ×PK 矢量积的 Z 部分:(xq-xp)(yk-yp)-(yq-yp)(xk-xp)。表达式在行的一侧为正,在另一侧为负(行上为零)。

        【讨论】:

          【解决方案9】:

          借助一个判断两条线段是否相交的函数,可以很容易地解决这个问题。

          给定点 A、B、C、D,连接顶点只有三种不同的顺序:ABCD、ABDC 和 ACBD(顶点 A 要么连接到顶点 B,要么不连接。如果连接,有两种方法订购 C 和 D。如果没有,则 A 连接到 C 和 D,并且每个都必须连接到 B)。

          如果没有任何边相交(除了在拐角处),则四个点的排序会产生一个四边形。这给出了查找工作订单的过程:

          If AB intersects with CD then return ACBD.
          If AD intersects with BC then return ABDC.
          Otherwise return ABCD.
          

          证明这很简单:

          1. ABCD 和 ABDC 都包括边 AB 和 CD,因此如果这对边相交,则正确的顺序必须是 ACBD。
          2. ABCD 和 ACBD 都包含边 AD 和 BC,因此如果这对边相交,则正确顺序必须是 ABDC。
          3. 如果 AB/CD 和 AD/BC 都不相交,则 ABCD 的顺序生成一个四边形。

          判断两条线段是否相交的代码,自己搞不定可以在网上找到。

          【讨论】:

            【解决方案10】:

            这是一种简单的、非数学的方法。我已经在几个例子上尝试过,但无法证明它是错误的。如果您这样做或知道如何使它变得更好,请告诉我:

            1. 选择其他点右侧的两个点,例如点 1 和 2。
            2. 将点 1-2 以及点 3-4 链接在一起。
            3. 每个点必须仅链接到其他两个点,因此只有两种可能性:链接点 1-3 和 2-4,或链接点 1-4 和 2-3。
            4. 检查每条线是否与另一条线相交。

            应该可以的。

            注意:选择前两点时,这里有一些特殊情况:

            1. 点 1 位于所有其他点的右侧,但点 2 和 3 位于相同的 x 坐标上。选择最接近点 1 的点。
            2. 如果三个点 1,2 和 3 具有相同的 x 坐标,则链接彼此最近的两个点。如果这些点分布均匀,请从两种可能性中选择一种。

            【讨论】:

              【解决方案11】:

              几个阶段,假设最终结果需要 4 对点(和/或它们之间的直线方程):

              1. 取任意三个点,组成一个三角形。
              2. 如果第四个点在三角形内部,则将其与三个点中的任何一个交换。
              3. 只剩下最后一个点,计算要将其附加到哪两个点。这是通过玩线方程并找到相交点的位置来完成的。说明如下。
              4. 返回三角形的两条边 + 第四点与您在第 2 阶段选择的点之间的 2 条线。

              第 2 步说明:
              假设 A 点不在三角形(即 BCD)中。每条线都将平原分为两侧。我们想找到点(B、C 或 D)s.t.它和 A 之间的线在另外两个之间(它们位于线的相对两侧)。这是我们不想附加到 A 的点。

              示例: 给定 A(0,0)、B(10,0)、C(10,10) 和 D(0,10)。我们有三角形 BCD。 BC 线在平原的同一侧留下 A 和 D。 DC也是。 AC 线将 B 和 D 留在平原的两侧 - 所以我们想将 A 连接到 B 和 C。

              【讨论】:

              • 如果已经做了一个三角形,如何用最后一个点做四边形
              • 我不明白所有的反对意见。第 2 步有点模糊,否则这是唯一正确的答案。
              • 投了反对票,正是因为这个原因。第 2 步可以写得更好
              • @CarbineCoder,请参阅说明。
              • 如果这是凹结构。对角线之间不会有任何交点。点 A(0,0)、B(5,5)、C(10,0)、D(5,10)。我不认为这个逻辑会起作用。或者简单地说 - 如果第 4 个点位于三角形内怎么办?
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-12-25
              • 1970-01-01
              • 2021-05-09
              • 2014-01-11
              • 2012-12-06
              • 1970-01-01
              相关资源
              最近更新 更多