【问题标题】:Relative position of a point within a quadrilateral四边形中一点的相对位置
【发布时间】:2015-04-24 21:39:04
【问题描述】:

我试图找到最简单的方法来确定一个点在四边形中的相对位置。已知的是(见图)点1、2、3、4、5在xy坐标系中的位置:x1、y1、x2、y2、x3、y3、x4、y4、x5、y5。

还已知点1、2、3、4在ξ-η坐标系中的位置(见图)。

根据这些数据,我想确定第 5 点的 ξ 和 η 是多少。

结果

感谢所有回答的人!我发现@dbc 和@agentp 的解决方案类似。我还发现这个解决方案比@MBo 的透视变换解决方案更好,因为我不必计算矩阵的逆矩阵 (Ax=B --> x=inv(A)*B)。

我得到以下结果:

u = 0.5 * (ξ + 1)
v = 0.5 * (η + 1)

在我的例子中,所有点都在矩形内,因此 u>0 和 v>0。

【问题讨论】:

    标签: math geometry computational-geometry


    【解决方案1】:

    你这里有一个2d bilinear blended surface。为简单起见,让我们将其坐标更改为从零到一的范围:

    u = 0.5 * (ξ + 1)
    v = 0.5 * (η + 1)
    

    在这种情况下,表面评估器可以表示为

    F(u, v) = P1 + u * (P2 - P1) + v * ((P4 + u * (P3 - P4)) - (P1 + u * (P2 - P1)))
    

    即,对于给定的u,构造一条通过以下两点的线:

    Pv0 = P1 + u * (P2 - P1);
    Pv1 = P4 + u * (P3 - P4);
    

    然后在给定的v之间插值

    F(u, v) = Pv0 + v * (Pv1 - Pv0)
    

    您寻求的是值(u,v) 使得F(u, v) = P5。对于给定的u,当从Pv0 到Pv1 的线经过P5 时会发生这种情况,当P5 - Pv0 与Pv1 - Pv0 平行时会发生这种情况——即当它们的2d cross 为零时:

    cross2d(P5 - Pv0, Pv1 - Pv0) = 0
    

    ⇒

    cross2d(P5                 - (P1 + u * (P2 - P1)),  
            P4 + u * (P3 - P4) - (P1 + u * (P2 - P1))) = 0
    

    现在,两个二维向量A ⨯ B 的2d cross 由Ax*By - Ay*Bx 给出,所以方程变为

    (x5 - (x1 + u * (x2 - x1))) * (y4 + u * (y3 - y4) - (y1 + u * (y2 - y1))) - (y5 - (y1 + u * (y2 - y1))) * (x4 + u * (x3 - x4) - (x1 + u * (x2 - x1))) = 0
    

    Expanding this expression out and collecting collecting together terms in u,我们得到

        u^2 * (x1*y3 - x1*y4 - x2*y3 + x2*y4 + (-x3)*y1 + x3*y2 + x4*y1 - x4*y2)
      + u *   (-x1*y3 + 2*x1*y4 - x1*y5 - x2*y4 + x2*y5 + x3*y1 - x3*y5 - 2*x4*y1 + x4*y2 + x4*y5 + x5*y1 - x5*y2 + x5*y3 - x5*y4)
      +       (-x1*y4 + x1*y5 + x4*y1 - x4*y5 - x5*y1 + x5*y4)
    = 0
    

    现在这是u 上的二次方程,因此可以是solved。请注意,如果四边形的顶部和底部边缘平行,则二次方会演变为线性方程;你的二次方程求解器必须处理这个问题。

            double a = (x1 * y3 - x1 * y4 - x2 * y3 + x2 * y4 + (-x3) * y1 + x3 * y2 + x4 * y1 - x4 * y2);
            double b = (-x1 * y3 + 2 * x1 * y4 - x1 * y5 - x2 * y4 + x2 * y5 + x3 * y1 - x3 * y5 - 2 * x4 * y1 + x4 * y2 + x4 * y5 + x5 * y1 - x5 * y2 + x5 * y3 - x5 * y4);
            double c = (-x1 * y4 + x1 * y5 + x4 * y1 - x4 * y5 - x5 * y1 + x5 * y4);
    
            double[] solutions = Quadratic.Solve(a, b, c);
    

    可能有不止一种解决方案。退化四边形也可能没有解决方案。

    解决了u 的值,找到等价的v 很简单。给定点

    Pv0 = P1 + u * (P2 - P1);
    Pv1 = P4 + u * (P3 - P4);
    

    你寻找v这样

    v * (Pv1 - Pv0) = P5 - Pv0;
    

    选择坐标索引 0 或 1 以使 |(Pv1 - Pv0)[index]|最大化。 (如果两个坐标都几乎为零,那就放弃——这个特定的u没有解决方案。然后设置

    v = (P5 - Pv0)[index] / (Pv1 - Pv0)[index];
    

    最后,如果您有多个解决方案,则更喜欢混合的[u, v] 边界内的解决方案。然后最后设置

    ξ = 2 * u - 1;
    η = 2 * v - 1;
    

    【讨论】:

      【解决方案2】:

      这看起来像是标准的有限元参数化 (问题没有指定特定的映射,但我想有人可能会对这个特定案例感兴趣)

       {x, y}  == (
                   (1 - eta) (1 - ci) {p1x, p1y}  +
                   (1 - eta) (1 + ci) {p2x, p2y}   + 
                   (1 + eta) (1 + ci) {p3x, p3y} +
                   (1 + eta) (1 - ci) {p4x, p4y} )/4
      

      这可以通过 {eta,ci} 的封闭形式来解决,但是这个表达式很难发布。

      在实践中,计算这些常数:

       ax = p1x + p2x + p3x + p4x
       bx = p1x - p2x - p3x + p4x
       cx = p1x + p2x - p3x - p4x
       dx = p1x - p2x + p3x - p4x
       ay = p1y + p2y + p3y + p4y
       by = p1y - p2y - p3y + p4y
       cy = p1y + p2y - p3y - p4y;
       dy = p1y - p2y + p3y - p4y;
      

      求解eta 的二次方程:

       (ax by - bx ay) - 4 (by  x - bx y) +
        eta (dx ay - cx by + bx  cy - ax dy + 4 (x dy - dx y)) +
        eta^2 (cx dy - dx cy) == 0
      

      然后将ci 设为:

       ci = ((-ax + eta cx + 4 x)/(-bx + eta dx))
      

      如果多边形不是太扭曲,那么只有一种解决方案可以满足 -1<eta<1 和 -1<ci<1

      【讨论】:

      • 不幸的是,这个公式在未知数中是二次的,并且解不是唯一的。透视法在这方面更好。
      • 对 -- 但是如果实际问题是有限元公式,那么您需要使用它。
      【解决方案3】:

      参考@blaz 的自我回答(请为@blaze、@dbc 和@agentp 的回答投票)

      对于那些不愿意手动复制公式的人来说,这里是 C# 代码中的公式:

          double v_sqrt = Math.Sqrt(
              4 * (
              (x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4)) * (x4 * (-1 * y + y1) + x1 * (y - y4) + x * (-1 * y1 + y4)) +
              Math.Pow(
              (x3 * y - x4 * y - x3 * y1 + 2 * x4 * y1 - x4 * y2 + x1 * (y + y3 - 2 * y4) + x2 * (-1 * y + y4) + x * (-1 * y1 + y2 - y3 + y4))
              , 2)
              );
      
          double u_sqrt = Math.Sqrt(
                  4 * ((x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4))
                  * (
                      x4 * (-1 * y + y1) + x1 * (y - y4) + x * (-1 * y1 + y4)
                  ) +
                  Math.Pow(
                  (x3 * y - x4 * y - x3 * y1 + 2 * x4 * y1 - x4 * y2 + x1 * (y + y3 - 2 * y4) + x2 * (-1 * y + y4) + x * (-1 * y1 + y2 - y3 + y4))
                  , 2)
              );
      
          double k = 1 / (2 * ((x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4)));
          double l = 1 / (2 * ((x1 - x4) * (y2 - y3) - (x2 - x3) * (y1 - y4)));
      
          ///////////////////////////////////////////////////////////////////////////////////////////////
          double v1 = l *
              (x2 * y - x3 * y + x4 * y + x * y1 - 2 * x2 * y1 + x3 * y1 - x * y2 - x4 * y2 + x * y3 - x1 * (y - 2 * y2 + y3) - x * y4 + x2 * y4 +
              v_sqrt);
      
          ///////////////////////////////////////////////////////////////////////////////////////////////
          double u1 = -1 * k *
              (-x2 * y + x3 * y - x * y1 - x3 * y1 + 2 * x4 * y1 + x * y2 - x4 * y2 - x * y3 + x1 * (y + y3 - 2 * y4) + x * y4 + x2 * y4 +
              u_sqrt);
      
          double v2 = -1 * l *
              (x1 * y + x3 * y - x4 * y - x * y1 - 2 * x3 * y1 + x * y2 - -2 * x1 * y2 + x4 * y2 - x * y3 + x1 * y3 + x * y4 - x2 * (y - 2 * y1 + y4) +
              v_sqrt);
      
          /////////////////////////////////////////////////////////////////////////////////////////////////
          double u2 = k *
              (x2 * y - x3 * y + x4 * y + x * y1 + x3 * y1 - 2 * x4 * y1 - x * y2 + x4 * y2 + x * y3 - x1 * (y + y3 - 2 * y4) - x * y4 - x2 * y4 +
              u_sqrt);
      

      在大多数情况下它是 u1 和 v1,因此不需要计算其他的。

      我用它在一张纸上校准 Pegasus Air-Pen 设备(超声波触控笔)的坐标。如果您的点 1 到 5 的坐标也 >= 0,则效果最好。

      很抱歉将其发布为答案,但评论太长了,我认为这对我来说是一个有价值的帮助。

      【讨论】:

        【解决方案4】:

        您需要计算透视变换矩阵,将源四边形的 4 个点映射到目标四边形 (example) (more mathemathics) 的 4 个点,然后将此变换应用于第 5 个点的坐标(将矩阵乘以坐标向量)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-07
          • 1970-01-01
          • 2013-05-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多