【问题标题】:How to check if line segment intersects square如何检查线段是否与正方形相交
【发布时间】:2014-12-12 00:09:21
【问题描述】:

我有一条由两点 a 和 b 确定的线段。我还有一个由 x0

我的想法是使用这张图片

function(a, b, x0, x1, y0, y1) {
  if (a or b is inside square)
    return true;
  else {
    switch (which quadrant is a in) {
      case 1: return (ab intersects top of square);
      case 2: return (ab intersects left of square);
      case 3: return (ab intersects bottom of square);
      case 4: return (ab intersects right of square);
    }
  }
}

我想知道是否有更好的方法来解决这个问题。

【问题讨论】:

  • 这是一个绝妙而正确的想法。
  • 对不起,如果我误解了,但是为什么正方形内​​的a或b表示相交?如果 a 和 b 都在正方形内怎么办?
  • @shole 我正在检查与正方形的整个域的交集,而不仅仅是边界。所以里面的 a 和 b 都算作一个交集。
  • 那么除了检查正方形内的 a 和 b 是否都返回 true 之外,它还能使用我的答案吗?

标签: javascript algorithm geometry


【解决方案1】:

我想到的一个简短答案就是测试线段与您的线和正方形的 4 条线的交点 使用标准的计算几何叉积。

这是一个快速教程 http://web.stanford.edu/class/cs97si/09-computational-geometry.pdf

Define ccw(A,B,C) = (B-A) X (C-A) where A,B,C is some point ccw(A,B,C) < 0 means C lies on the left side of line AB ccw(A,B,C) > 0 means C lies on the right side of line AB

所以测试线段相交就像,给出两条线 AB(你的线段)和 CD(正方形的任何一侧)

它们正确相交(即不包括触摸案例)当夫

ccw(A,B,C) * ccw(A,B,D) &lt; 0 AND ccw(C,D,A) * ccw(C,D,B) &lt; 0

简单的意思是“C和D位于线AB的不同侧,而A和B位于线CD的不同侧”-->交点

【讨论】:

  • 谢谢大家,这很有用
【解决方案2】:

您可以使用不等式和线段的参数方程解析解决此问题(我们使用dx/dy 表示xb-xa/yb-ya):

    x0 < xa + t.dx < x1
    y0 < xb + t.dy < y1
     0 <      t    < 1

然后重写,让同一个词的三个括号出现:

    (x0 - xa).dy < t.dx.dy < (x1 - xa).dy
    (y0 - ya).dx < t.dx.dy < (y1 - ya).dx
               0 < t.dx.dy < dx.dy

注意:乘以负数d时,不等式的成员必须交换;因此有四种情况。 (实际上9d 也可以是0。这些情况在这里很容易忽略。)

最后,表示这些括号是兼容的,即至少有一个可能的tvalue:

    Max((x0 - xa).dy, (y0 - ya).dx, 0) < Min(x1 - xa).dy, (y1 - ya).dx, dx.dy)

仔细观察,您可以识别出您的方法的元素:例如,0 &lt; (x1 - xa).dy 是与右侧的比较,(x0 - xa).dy &lt; (y1 - ya).dx 是与对角线的比较。

这种方法先用2 - 计算dx/dy,然后用4 &lt;&gt;(比较)来讨论9 的情况,然后用4 -5 *5 &lt;&gt; 来计算斜线段结束。

类似这样的东西(小心,未选中!):

dx= xb - xa; dy= yb - ya;
if (dx > 0)
{
    if (dy > 0) return Max((x0 - xa).dy, (y0 - ya).dx, 0) < Min(x1 - xa).dy, (y1 - ya).dx, dx.dy);
    else if (dy < 0) return Max((x1 - xa).dy, (y0 - ya).dx, 0) < Min(x0 - xa).dy, (y1 - ya).dx, dx.dy);
    else return Max(y0 - ya, 0) < Min(y1 - ya, dy);
}
else if (dx < 0)
{
    if (dy > 0) return Max((x0 - xa).dy, (y1 - ya).dx, 0) < Min(x1 - xa).dy, (y0 - ya).dx, dx.dy);
    else if (dy < 0) return Max((x1 - xa).dy, (y1 - ya).dx, 0) < Min(x0 - xa).dy, (y0 - ya).dx, dx.dy);
    else return Max(y1 - ya, 0) < Min(y0 - ya, dy);
}
else
{
    if (dy > 0) return Max(x0 - xa, 0) < Min(x1 - xa, 0);
    else if (dy < 0) return Max(x1 - xa, 0) < Min(x0 - xa, 0);
    else return false;
}

【讨论】:

    【解决方案3】:

    您只需要检查 2 个案例。

    如果该线在上顶点位于第 1 行之上或在下顶点位于第 3 行之下。如果这两个条件中的任何一个返回 true,则没有交集。

    例如,要检查第 1 行,您将为由 a、b 确定的行计算 y=mx+n 并检查 y(x0) &gt; y1 是否与 y(x1) &gt; y1 类似

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-26
      • 2013-01-03
      • 2019-01-24
      • 2011-04-19
      • 1970-01-01
      • 2021-07-13
      相关资源
      最近更新 更多