查找适合网格系统的所有矩形

时间:2019-06-22 09:06:42

标签: javascript algorithm math

我正在研究算法,正在寻找最佳的解决方案,以找到网格中可以添加矩形的所有位置。

我编写了简单的测试:

test('Based on layout elements getting highlighting positions where we can drop element', () => {
    const layoutElements = [
        {
            row: 3,
            column: 2,
            width: 2,
            height: 1,
        },
        {
            row: 3,
            column: 4,
            width: 1,
            height: 3,
        },
        {
            row: 4,
            column: 1,
            width: 1,
            height: 2,
        },
    ];

    const highlightingPositions = getHighlightingLayoutDropPositions({
        draggedElWidth: 2,
        draggedElHeight: 2,
        layoutWidth: 4,
        layoutHeight: 5,
        layoutElements
    });

    expect(highlightingPositions.length).toEqual(12);
});

可视化将是:

enter image description here

强力解决方案将是遍历每个单元并检查N x M的范围,其中| M是拖动元素的大小。有没有人有更好的方法呢?有什么例子吗?

1 个答案:

答案 0 :(得分:1)

根据我先前对该问题的评论,使用第二个答案在Bin Packing Js implementation using box rotation for best fit处的算法,您可以将所有空块都喂入堆,然后运行unionAll获得可用的矩形单元格块区域。 (请注意,x1 / y1坐标表示(x1-x0),而(y1-y0)表示要定义的单元/块的大小)。使用问题中的可视化内容作为示例数据,使用所有可用的单个单元格填充堆,然后调用“ unionAll” ...

x = new Packer(4,5);
x.heap = [{x0:1, y0:1, x1:2, y1:2},  // All are w:1, h:1
          {x0:2, y0:1, x1:3, y1:2},
          {x0:3, y0:1, x1:4, y1:2},
          {x0:4, y0:1, x1:5, y1:2},
          {x0:1, y0:2, x1:2, y1:3},
          {x0:2, y0:2, x1:3, y1:3},
          {x0:3, y0:2, x1:4, y1:3},
          {x0:4, y0:2, x1:5, y1:3},

          {x0:1, y0:3, x1:2, y1:4},

          {x0:2, y0:4, x1:3, y1:5},
          {x0:2, y0:5, x1:3, y1:6},
          {x0:3, y0:4, x1:4, y1:5},
          {x0:3, y0:5, x1:4, y1:6}]

x.unionAll();
console.log(x);

...导致堆减少到...

heap: Array(3)
0: {x0: 1, y0: 1, x1: 5, y1: 3}  // w:4, h:2
1: {x0: 1, y0: 1, x1: 2, y1: 4}  // w:1, h:3
2: {x0: 2, y0: 4, x1: 4, y1: 6}  // w:2, h:2

...表示可用的单元格块。请注意,heap [0]和heap [1]重叠,因为该算法只是查找要使用的最大可用矩形区域。

然后,如果您打算将元素放入网格中,并且需要知道还剩下哪些单元格,则可以使用adjustHeap方法重新计算可用空间。假设您从第3列第2行开始添加了一个大小为2个水平单元格的矩形,从上方继续...

x.adjustHeap({x0:3, y0:2, x1:5, y1:3});  // w:2, h:1
console.log(x);

..导致...的堆...

heap: Array(4)
0: {x0: 1, y0: 1, x1: 2, y1: 4}  // w:1, h:3
1: {x0: 2, y0: 4, x1: 4, y1: 6}  // w:2, h:2
2: {x0: 1, y0: 1, x1: 5, y1: 2}  // w:4, h:1
3: {x0: 1, y0: 1, x1: 3, y1: 3}  // w:2, h:2

再次,请注意生成的矩形的重叠部分,因为此功能是为了简化寻找所需大小的矩形区域的过程。

一些注意事项:

  • 在您的情况下,并非Packer中的所有功能都是必需的。
  • 我对Packer界面的布局方式并不热衷,但是为了2D Bin Packer问题,通常将其保留原样。如果在我的一个项目中使用它,我会将其转换为一个类。
  • 在研究您的示例时,我发现自己对定义x0,y0,x1,y1定义单元格的方式充满了兴趣。如果您重新设计算法以使用x,y(单元格块的起源)和w,h(单元格块的宽度和高度),则可能会更容易。