【问题标题】:Laying out overlapping rectangles布置重叠的矩形
【发布时间】:2010-12-31 16:22:16
【问题描述】:

我正在尝试布局一堆重叠的矩形,它们的开头是这样的:

alt text http://img690.imageshack.us/img690/209/picture1bp.png

我想到的2-pass算法大致是:

// Pass 1 - Move all rectangles to the right until they do not overlap any other rectangles
rects = getRectsSortedOnTopLeft(); // topmost first, all rects same size
foreach(rect in rects)
{
   while(rect.collidingRects().size() != 0)
   {
       rect.x += RECT_SIZE;
   }
}

这(可能)以矩形布局结束,如下所示: alt text http://img685.imageshack.us/img685/9963/picture2bc.png

这在美学上并不令人愉悦,所以我想到了第二遍,这会将它们全部从最顶部重新开始向左移动:

// Pass 2
foreach(rect in rects)
{
    while(rect.x >= LEFT_MARGIN)
    {
        assert(rect.collidingRects().size() == 0);
        rect.x -= RECT_WIDTH;
        if(rect.collidingRects().size() != 0)
        {
           rect.x += RECT_WIDTH;
           break;
        }
    }
}

我认为这最终应该如下所示(在实践中看起来完全正确):

alt text http://img511.imageshack.us/img511/7059/picture3za.png

但是,我对这种算法持谨慎态度,因为我不确定它是否在所有情况下都能正确布局,而且它可能真的很慢。你觉得这个算法行得通吗?你能就更好的算法提出一些建议吗?

【问题讨论】:

  • 你的伪代码需要做一些工作... "rect.size -= RECT_SIZE;"应该是“rect.x -= RECT_SIZE;”,如果这会导致碰撞,您需要在最后一次向左移动后向右移动一次。
  • 是的,你是对的。我注意到在实现伪代码之后。我会在问题中解决它。实施后,它的总体表现非常糟糕:-/
  • 嗯,我撒了谎,它实际上工作得很好(一些小的边界矩形问题)。但是,x 排序没有保留,我需要“尽可能”保留 x 排序
  • 这就是我们不再使用 imageshack 的原因。

标签: algorithm user-interface qt layout


【解决方案1】:

我认为这个问题具有多项式复杂性。假设您的示例限制只有两个矩形在任何给定点重叠并不是问题的真正限制,您需要尝试将矩形向右碰撞的所有可能顺序,以产生最佳(最小宽度)结果。这是一种空间打包问题,除非您的数据集小到足以暴力破解,否则这些问题很难解决。

但是,可以对您的伪代码进行一点小改进,这将在许多情况下提高其性能。

考虑这个期望的最终结果:

A
A C
A C E
A C E
B C E
B D E
B D F
B D F
  D F
    F

(其中一个字符的所有四个都是一个矩形)

您的第一个通道会将除 A 之外的所有内容向右移动,形成一个楼梯。然后在第二遍中,您的代码将拒绝将 B 移动到左边距,因为第一次移动它的尝试将与 E 重叠。您需要做的是从左边距开始并检查您可以移动每个的最左边的位置矩形到通过 2。

伪代码:

// Pass 1 - Move all rectangles to the right until they do not overlap any other rectangles
rects = getRectsSortedOnTopLeft(); // topmost first, all rects same width
foreach(rect in rects)
    while(rect.collidingRects())
        rect.x += RECT_WIDTH;
// Pass 2 - Move all rectangles to the leftmost position in which they don't overlap any other rectangles
foreach(rect in rects)
    for(i=LEFT_MARGIN; i+=RECT_WIDTH; i<rect.x)
    {
        o = rect.x;
        rect.x = i;
        if(rect.collidingRects())
            rect.x = o;
    }

【讨论】:

  • 嗯,我认为这实际上修复了我在测试原始代码时发现的一个错误......它仍然有一些我想修复的奇怪行为。我将提供我想要修复的运行时行为的截屏视频。
  • 这里是截屏视频。我想就算法本身而言,该算法正在做正确的事情,但我想做的是能够尽可能地保持所有矩形的 x 位置:screencast.com/t/MzYxYmI1Yjg 有什么想法吗?
  • 好的,为了避免选定的矩形被重新定位在 x 轴上,我只是忽略了这个算法。似乎工作。当然,我仍然对想法持开放态度。
  • 将您的答案标记为正确,直到我能更好地描述我想要的行为:)
【解决方案2】:

您可以使用基于物理的方法,其中块是向左下落的刚体:

不,这不会一直产生最好的结果,但是观看了您的截屏视频后,我认为在交互式程序中使用它会非常直观,并且可能合适:)

【讨论】:

  • 这真是个好主意。我将对此进行原型制作,感谢您抽出宝贵时间观看截屏视频。
猜你喜欢
  • 2018-11-02
  • 2023-04-01
  • 1970-01-01
  • 2017-01-15
  • 1970-01-01
  • 1970-01-01
  • 2017-03-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多