如何计算两个矩形之间的距离?(背景:Lua中的游戏。)

给定两个带有像素的x,y,宽度,高度和以度为单位的旋转值的矩形-如何计算它们之间轮廓的最近距离?

背景:我在使用Lua编写的游戏中随机生成地图,但想要确保某些矩形彼此之间不会太接近-这是必需的,因为如果矩形进入某些近距离位置,地图将变得不可解决,因为一个球需要从它们之间通过。速度不是太大的问题,因为我没有很多矩形,而且地图仅在每个级别生成一次。我在StackOverflow上找到了以下两个链接:这和这。

非常感谢!

原文链接 https://stackoverflow.com/questions/4978323

点赞
stackoverflow用户445112
stackoverflow用户445112

这个问题取决于你需要什么样的距离。你需要中心点的距离、边缘的距离还是最近角的距离?

我猜你指的是最后一种。如果X和Y值表示矩形的中心,那么你可以通过应用这个技巧找到每个角落。

//伪代码
Vector2 BottomLeftCorner = new Vector2(width / 2, heigth / 2);
BottomLeftCorner = BottomLeftCorner * Matrix.CreateRotation(MathHelper.ToRadians(degrees));
//如果LUA没有内置的向量/矩阵计算请在网上搜索“旋转向量”。
//这个可以帮助:http://www.kirupa.com/forum/archive/index.php/t-12181.html

BottomLeftCorner += new Vector2(X, Y); //添加原点以使它成为世界位置。

对所有矩形的所有角进行操作,然后只需循环遍历所有角并计算距离(使用 abs(v1 - v2))。

希望这可以帮助你。

2011-02-12 14:27:36
stackoverflow用户380331
stackoverflow用户380331

伪代码:

distance_between_rectangles = some_scary_big_number;

对于每一个矩形1的边缘edge1:
    对于每一个矩形2的边缘edge2:
        distance = 计算从edge1到edge2的最短距离
        
        if (distance < distance_between_rectangles):
            distance_between_rectangles = distance

在每个矩形的边缘上循环,计算两个矩形之间最短的距离。如果找到的距离比目前记录的距离更短,就更新记录的距离。使用此处提到的方法来计算从一个边缘到另一个边缘的最短距离。

2011-02-23 10:40:11
stackoverflow用户384670
stackoverflow用户384670

编辑:正如OK所指出的,这个解决方案假设所有的矩形都是竖直的。要使其适用于 OP 所要求的旋转矩形,您还必须计算每个矩形的角到另一个矩形最近边的距离。但如果该点位于线段的两个端点以上或以下,并且在两个线段的左侧或右侧(在电话位置1、3、7或9与线段相关的位置),则在大多数情况下可以避免进行该计算。

Agnius的答案依赖于一个DistanceBetweenLineSegments()函数。这里有一个不需要这个函数的案例分析:

(1)检查矩形是否相交。如果是,则它们之间的距离为0。
(2)如果不是,则将r2视为电话键盘“#5”的中心。
(3)r1可能完全在极端象限之一中(#1,#3,#7或#9)。如果是这样,距离就是一个矩形角落到另一个矩形角落的距离(例如,如果r1在象限#1中,则距离是从r1的右下角到r2的左上角的距离)。
(4)否则,r1位于r2的左侧、右侧、上方或下方,距离就是相关边之间的距离(例如,如果r1在上方,则距离为r1的低y和r2的高y之间的距离)。
2014-03-20 07:22:13
stackoverflow用户474563
stackoverflow用户474563

有许多算法可以解决这个问题,Agnius 算法效果很好。然而,我更喜欢下面的方法,因为它看起来更直观(你可以在纸上完成)并且它们不依赖于查找两条线之间的最小距离,而是依赖于点和线之间的距离。

困难的部分是实现数学函数,以找到一条直线和一个点之间的距离,并找到一个点是否面对一条直线。但是,你可以使用简单的三角函数解决所有这些问题。我在下面列出了解决这些问题的方法。

对于以任意角度呈放的多边形(三角形、矩形、六边形等)

  1. 如果多边形重叠,返回 0。
  2. 在两个多边形的中心之间画一条线。
  3. 从每个多边形中选择相交的边。(在这里,我们简化问题)
  4. 找到这两条边中的最小距离。(你可以只遍历每个多边形的 4 个点,查找到另一个形状的边的最小距离)。

只要形状的任意两条边不创建大于 180 度的角度,这些算法就可以工作。原因是,如果某个角度大于 180 度,那么这意味着一些角落会向内膨胀,就像一个星形。

边缘和点之间的最小距离

  1. 如果点没有面对面,那么返回点和边缘角之间的两个距离中的最小值。
  2. 从三个点(边的两个点加上单独的点)中绘制一个三角形。
  3. 我们可以使用勾股定理轻松获得三条绘制线之间的距离。
  4. 使用Heron 公式获得三角形的面积。
  5. 计算高度,现在使用 Area = 12â‹…baseâ‹…height,其中 base 是边的长度。

检查一个点是否面对一条边

和以前一样,从一条边和一个点绘制三角形。现在使用余弦定理仅通过知道边距离就可以找到所有角度。只要从边缘到点的每个角度都小于 90 度,该点就面向边缘。

如果你感兴趣,我在 这里 用 Python 实现了所有这些。

2014-09-24 14:28:35
stackoverflow用户805502
stackoverflow用户805502

不是在 Lua 中,这是基于 M Katz 的建议的 Python 代码:

def rect_distance((x1, y1, x1b, y1b), (x2, y2, x2b, y2b)):
    left = x2b < x1
    right = x1b < x2
    bottom = y2b < y1
    top = y1b < y2
    if top and left:
        return dist((x1, y1b), (x2b, y2))
    elif left and bottom:
        return dist((x1, y1), (x2b, y2b))
    elif bottom and right:
        return dist((x1b, y1), (x2, y2b))
    elif right and top:
        return dist((x1b, y1b), (x2, y2))
    elif left:
        return x1 - x2b
    elif right:
        return x2 - x1b
    elif bottom:
        return y1 - y2b
    elif top:
        return y2 - y1b
    else:             # 矩形相交
        return 0.

其中:

  • dist 是点之间的欧几里得距离
  • 矩形 1 由点 (x1, y1)(x1b, y1b) 形成
  • 矩形 2 由点 (x2, y2)(x2b, y2b) 形成
2014-10-03 11:17:57
stackoverflow用户739912
stackoverflow用户739912

实际上有一个快速的数学解决方案。

Length(Max((0, 0), Abs(Center -otherCenter) -(Extent + otherExtent)))

其中 Center = ((Maximum - Minimum) / 2) + MinimumExtent = (Maximum - Minimum) / 2。 基本上,上面的代码将有重叠的轴归零,因此距离始终正确。

最好保持矩形的这种格式,因为在许多情况下(例如旋转)更可取。

2016-01-28 15:56:51
stackoverflow用户1945316
stackoverflow用户1945316

请检查 Java 版本,它有约束条件:所有的矩形都是平行的。对于所有相交的矩形,它返回 0:

   public static double findClosest(Rectangle rec1, Rectangle rec2) {
      double x1, x2, y1, y2;
      double w, h;
      if (rec1.x > rec2.x) {
         x1 = rec2.x; w = rec2.width; x2 = rec1.x;
      } else {
         x1 = rec1.x; w = rec1.width; x2 = rec2.x;
      }
      if (rec1.y > rec2.y) {
         y1 = rec2.y; h = rec2.height; y2 = rec1.y;
      } else {
         y1 = rec1.y; h = rec1.height; y2 = rec2.y;
      }
      double a = Math.max(0, x2 - x1 - w);
      double b = Math.max(0, y2 - y1 - h);
      return Math.sqrt(a*a+b*b);
   }
2016-07-31 18:48:01
stackoverflow用户2983585
stackoverflow用户2983585

我刚刚在 N 维空间写了这段代码。但是我并没有找到一个通用的解决方案。

// 考虑一个包含两个点(最小值和最大值)的矩形对象
double distance(const rectangle& a, const rectangle& b) const {
    // 无论你使用的是什么类型的点
    point_type closest_point;
    for (size_t i = 0; i < b.dimensions(); ++i) {
        closest_point[i] = b.min[i] > a.min[i] ? a.max[i] : a.min[i];
    }
    // 在这里使用通常的欧几里德距离
    return distance(a, closest_point);
}

计算矩形和点之间的距离:

double distance(const rectangle& a, const point_type& p) const {
    double dist = 0.0;
    for (size_t i = 0; i < dimensions(); ++i) {
        double di = std::max(std::max(a.min[i] - p[i], p[i] - a.max[i]), 0.0);
        dist += di * di;
    }
    return sqrt(dist);
}

如果你想旋转其中一个矩形,你需要旋转坐标系。

如果你想旋转两个矩形,你可以旋转矩形 a 的坐标系,然后我们需要更改这一行:

closest_point[i] = b.min[i] > a.min[i] ? a.max[i] : a.min[i];

因为这只考虑了 b 中最近的一个顶点作为候选项。你需要改变它来检查到所有的点到 b 中的距离。它总是一个顶点。

见:https://i.stack.imgur.com/EKJmr.png

2020-06-13 16:54:46
stackoverflow用户11034968
stackoverflow用户11034968

另一个解决方案是计算矩形上的点数,并选择距离最近的对。

优点:适用于所有多边形。

缺点:略微不精确且速度较慢。

import numpy as np
import math

POINTS_PER_LINE = 100

# 获取多边形外边界上的点
# 多边形格式:((x1, y1), (x2, y2), ...)
def get_points_on_polygon(poly, points_per_line=POINTS_PER_LINE):

    all_res = []

    for i in range(len(poly)):

        a = poly[i]

        if i == 0:
            b = poly[-1]

        else:
            b = poly[i-1]

        res = list(np.linspace(a, b, points_per_line))

        all_res += res

    return all_res

# 计算两个多边形之间的最小距离
# 多边形格式:((x1, y1), (x2, y2), ...)
def min_poly_distance(poly1, poly2, points_per_line=POINTS_PER_LINE):

    poly1_points = get_points_on_polygon(poly1, points_per_line=points_per_line)

    poly2_points = get_points_on_polygon(poly2, points_per_line=points_per_line)

    distance = min([math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2) for a in poly1_points for b in poly2_points])

    # slower
    # distance = min([np.linalg.norm(a - b) for a in poly1_points for b in poly2_points])

    return distance
2021-09-02 14:39:45
stackoverflow用户7206675
stackoverflow用户7206675

我解决这个问题的方法:

1.将两个矩形合并成一个大矩形 2.从大矩形中减去第一个矩形和第二个矩形 3.减法后剩下的是两个矩形之间的矩形,该矩形的对角线是两个矩形之间的距离。

下面是C#的示例代码:

public static double GetRectDistance(this System.Drawing.Rectangle rect1, System.Drawing.Rectangle rect2)
{
    if (rect1.IntersectsWith(rect2))
    {
        return 0;
    }

    var rectUnion = System.Drawing.Rectangle.Union(rect1, rect2);
    rectUnion.Width -= rect1.Width + rect2.Width;
    rectUnion.Width = Math.Max(0, rectUnion.Width);

    rectUnion.Height -= rect1.Height + rect2.Height;
    rectUnion.Height = Math.Max(0, rectUnion.Height);

    return rectUnion.Diagonal();
}

public static double Diagonal(this System.Drawing.Rectangle rect)
{
    return Math.Sqrt(rect.Height * rect.Height + rect.Width * rect.Width);
}
2022-05-08 17:40:50