【问题标题】:Fitting a rectangle inbetween existing, non-overlapping rectangles在现有的非重叠矩形之间拟合一个矩形
【发布时间】:2015-12-22 18:10:50
【问题描述】:

我有一个问题,最好用计算机屏幕上的窗口来说明:创建另一个窗口,尽可能大,不要与任何现有窗口重叠。

换句话说:给定有限表面(一张纸或屏幕)上的一组 N 个矩形,找到可以放在这些矩形之间的最大矩形。 (坐标可以是任意的,所以位图在这里不是一个可行的解决方案。)

下图显示了三个矩形(黑色)和可以拟合的最大矩形(红色)。

http://www.irstafoto.se/blogmtrl/rectangle-illustration.jpg

我为此编写了一个简单的算法,它考虑了矩形使用的所有 x 和 y 坐标对。不幸的是,它是 O(N^5),因为在最坏的情况下,必须检查每个矩形候选者是否与其他矩形重叠。

还有什么更好的吗?

最大面积 = 0; max_rect = 无 xc = 图片中的所有矩形 x 坐标 [x1, ..., x6]) yc = 所有矩形 y 坐标(图片中的 y1, ..., y6]) xc = [0] + xc + [W]; /* W 是区域的宽度 */ yc = [0] + yc + [H]; /* H 是区域的高度 */ 排序(xc); 排序(yc); 对于 xc 中的每个 x0 对于 xc 中的每个 x1 > x0 对于 yc 中的每个 y0 对于 yc 中的每个 y1 > y0 r = 矩形(x0,y0,x1,y1) if (area(r) > max_area and !overlapping(r)) max_area = 面积(r) max_rect = r

【问题讨论】:

  • 是的。使用“扫描线算法”可以做得更好,这是正确的谷歌搜索词。

标签: algorithm computational-geometry rectangles


【解决方案1】:

我的建议:

对 X 和 Y 进行独立排序,以便您可以将所有角坐标映射到 [0,2N] 范围内的整数索引。

用黑色填充二进制图像,其中空间被缩小坐标中的矩形占据。图像大小将为 (2N+1)x(2N+1)。

找出可以放置在白色区域中的最大矩形。这可以在与图像面积成比例的时间内完成。 (参见文章《基于矩形列表的对象描述符:方法与算法》。)

然后对于每个最大矩形,计算实际面积,给定真实坐标,并保持最大

这应该是一个整体的 O(N²) 过程。

【讨论】:

  • 不幸的是,我想不出从 x 或 y 坐标到 [0,2N-1] 范围内的整数值的仿射变换。
  • 根本不需要计算转换,您只需将值替换为它们的等级。您得到的是“合乎逻辑”的图像,而不是按比例缩放的图像,只是顺序很重要(我的图片与您的图片有关)。您甚至可以在不明确表示此图像的情况下实现该算法。
  • 我不相信这种转换是仿射的,因此它不会报告错误的最大值。例如,如果 A 和 B 是矩形,因此 area(A) > area(B) 但在变换后的坐标中 area(A')
  • @KjellPost:抱歉,你真的不明白转换是如何工作的。
  • 你能举个例子吗?谢谢!
【解决方案2】:

半四叉树方法怎么样?您可以创建一个具有 9 个属性的节点,矩形本身,4 个矩形,其区域可用于节点当前矩形的北、南、东和西;最后是4个节点,每个节点在相应的区域都有子树。节点类看起来像这样:

class node 
{
    public var nr:Rectangle;
    public var sr:Rectangle;
    public var wr:Rectangle;
    public var er:Rectangle;

    public var nn:node = null;
    public var sn:node = null;
    public var wn:node = null;
    public var en:node = null;

    public var rect:Rectangle;
}

当创建一个新节点时,你应该只用包含当前矩形边的线来剪裁边界区域。这不是典型的四叉树。这里子节点的区域可能会重叠。

另外两个基本动作。首先添加矩形。从第一个实心矩形开始,您创建一个节点,然后为每个剩余的矩形将它们添加到树中。要将矩形添加到节点,您应该检查它是否与其任何区域重叠。如果是这样,请将其剪辑到该区域并将其向下推到该节点。如果节点为空(或 null),则创建一个新节点。

终于找到了一个最大的矩形。这是从根节点开始递归完成的。您应该从覆盖所有 4 个区域的矩形中获得最大的矩形。这很容易,因为您已经将它们作为节点的属性。但是有一个技巧——如果这个区域有一个子节点,你应该使用这个节点最大的矩形(这里是递归)。

【讨论】:

    猜你喜欢
    • 2017-03-14
    • 2018-11-02
    • 2015-06-13
    • 2016-10-17
    • 2012-06-21
    • 1970-01-01
    • 2012-03-28
    • 2015-01-25
    • 2017-01-15
    相关资源
    最近更新 更多