【问题标题】:Packing rectangles in a rectangle, generate grids coordinates将矩形打包在一个矩形中,生成网格坐标
【发布时间】:2020-04-03 05:09:31
【问题描述】:

希望在更大的矩形中生成一些随机的矩形网格。

这看起来是一个相当简单的问题,但事实并非如此,在这里寻求建议。

这是not a packing problem,因为内部矩形可以有任何宽度和高度。

但矩形的数量并不总是相同的。

我已经有了一些不同类型的循环的结果,但没有一个是真正有效的。

例如,对于 15 个矩形,表示它们的一种可能方式是:

  O          10                                            50         60
  +----------+---------------------------------------------+----------+-------+
  |          |                                             |          |       |
  |          |                                             |          |       |
  |          |                                             |          |       |
5 +----------+---------------------------------------------+----------+-------+
  |          |                                             |                  |
  |          |                                             |                  |
  |          |                                             |                  |
  |          |                                             |                  |
  |          |                                             |                  |
  |          |                                             |                  |
15+----------+---------------------------------------------+----------+-------+
  |          |                                             |          |       |
  |          |                                             |          |       |
  |          |                                             |          |       |
  +----------+---------------------------------------------+----------+-------+
  |          |                                             |          |       |
  |          |                                             |          |       |
  |          |                ↓                            |          |       |
  +----------+---------------------------------------------+----------+-------+

坐标将类似于每个内部正方形左上角 (+) 的 [x,y] 点数组:

[[0,0],[10,0],[50,0],[60,0],[5,0],[5,10],[5,50], ...]

或者更好的是 [x,y,w,h] 值数组(左上角 x,左上角 y,宽度,高度

[[0,0,10,5],[10,0,40,5],[50,0,10,5],[60,0,10,5],[5,0,10,10],[5,10,40,10],[5,50,20,10], ...]

但我们的目标是创建一个为任意数量的内部正方形生成坐标的函数:

例如,对于 14 个矩形,表示它们的可能方式是:

  +----------+----------------------------------+---------------------+-------+
  |          |                                  |                     |       |
  |          |                                  |                     |       |
  |          |                                  |                     |       |
  |          |                                  |                     |       |
  |          |                                  |                     |       |
  +----------+----------------------------------+----------+----------+-------+
  |          |                                             |          |       |
  |          |                                             |          |       |
  +----------+--------+------------------------------------+----------+-------+
  |                   |                                    |          |       |
  |                   |                                    |          |       |
  +-------------------+-----------+------------------------+----------+-------+
  |                               |                                           |
  |                               |                                           |
  |                               |                                           |
  |                               |                                           |
  +-------------------------------+-----------------------------------+-------+

相关链接:

Packing rectangular image data into a square texture

What algorithm can be used for packing rectangles of different sizes into the smallest rectangle possible in a fairly optimal way?

How to arrange N rectangles to cover minimum area

【问题讨论】:

  • 所以唯一的限制是有 n 个矩形,并且它们完全按照给定的宽度和高度平铺外部矩形?
  • 当然。具有良好的结构。以一些斐波那契比例为例。你怎么看?

标签: php algorithm rectangles packing


【解决方案1】:

您的问题有两个方面:您希望创建一个规则网格,其中包含可能跨越多个单元格的 n 个矩形,并且您希望随机分布单元格边界的坐标。

所以我提出了愚弄算法:

  • 确定网格中的行数和列数,使每个单元格或多或少是方形的。
  • 创建一个 1×1 单元格的矩形网格。单元格的数量将大于 n
  • 合并两个相邻的单元格,直到有 n 个单元格。
  • 现在为单元格边界创建随机轴。如果您有 m 列,请创建一个递增值数组,以便第一个坐标为 0,最后一个坐标为原始 ractangle 的宽度。为此,您可以创建一个递增随机数列表,然后使用整体宽度进行标准化。
  • 最后,使用单元格的信息(位置、单元格跨度)和随机轴创建实际的矩形。

此算法使用矩形的两种表示:首先,它创建“单元格”,其中包含有关其行和列索引和跨度的信息。实际输出的是带有左、上、宽和高信息的矩形。

我不熟悉 PHP,所以这里有一个 Javascript 实现。我想你可以看到它是如何工作的:

function tile(big, n) {
    // big: outer rectangle
    // n: number of subrectangles to create

    // determine number of rows and cols

    let l = Math.sqrt(big.height * big.width / n);
    let ncol = (big.width / l + 1) | 0;
    let nrow = (big.height / l + 1) | 0;
    let cells = [];

    // create grid of m*m cells

    for (let j = 0; j < nrow; j++) {        
        for (let i = 0; i < ncol; i++) {
            cells.push(new Cell(i, j, 1, 1));
        }
    }

    // conflate rectangles until target number is reached

    while (cells.length > n) {
        let k = (cells.length * Math.random()) | 0;
        let c = cells[k];

        if (c.col + c.colspan < ncol) {
            let cc = cells[k + 1];

            c.colspan += cc.colspan;

            cells.splice(k + 1, 1);
        }            
    }

    // generate increasing lists of random numbers

    let xx = [0];
    let yy = [0];

    for (let i = 0; i < ncol; i++) {
        xx.push(xx[xx.length - 1] + 0.5 + Math.random());
    }

    for (let i = 0; i < nrow; i++) {
        yy.push(yy[yy.length - 1] + 0.5 + Math.random());
    }

    // fit numbers to outer rectangle

    for (let i = 0; i < ncol; i++) {
        xx[i + 1] = (big.width * xx[i + 1] / xx[ncol]) | 0;
    }

    for (let i = 0; i < nrow; i++) {
        yy[i + 1] = (big.height * yy[i + 1] / yy[nrow]) | 0;
    }

    // create actual rectangles

    let res = [];
    for (let cell of cells) {
        let x = xx[cell.col];
        let w = xx[cell.col + cell.colspan] - x;
        let y = yy[cell.row];
        let h = yy[cell.row + cell.rowspan] - y;

        res.push(new Rect(x, y, w, h));
    }

    return res;
}

注意事项:

  • 上面的代码只在水平方向合并单元格。您可以更改此设置以垂直合并单元格或同时合并两个单元格,但由于目前的算法,如果不进行重大修改,您将无法创建超过一个单元格宽度和高度的单元格。
  • x | 0 是一种将浮点数转换为整数的廉价方法。我用它来将最终坐标捕捉到整数值,但您也可以在 PHP 中使用s * ((x / s) | 0)s * intval(x / s) 将它们捕捉到任何网格大小s

代码不太关心美学。它随机选择单元格大小和单元格合并,这样你可能会得到交叉关节,这看起来不太好。不过,您可以稍微影响结果的规律性:

  • 当您确定列数和行数时,您必须在结果中加一,以便在每种情况下都可以合并单元格。 (即使你有一个正方形并将一个平方数作为 n 传递,你也会得到连接的矩形。)如果你添加更多,你会得到更多的连接矩形,结果看起来更不规则。李>
  • Math.random() 返回一个介于 0 和 1 之间的随机数。创建轴时,我在结果中添加了 0.5,这样您就不会得到非常窄的单元格。加的少,坐标不规则,加的多,分布更均匀。
  • 或许行坐标均匀,clumns坐标不规则可以得到很好的效果。

您在评论中提到了好看的属性。当您创建网格并放置带有约束的矩形而不是先创建网格然后移除关节时,也许更容易创建一个好看的结构。

【讨论】:

  • (查看代码并使用它here。)
  • 首先非常感谢您的详细解答。你肯定使用了一个有趣的逻辑。我应该能够用 php 重写它。如您所见,这是一个有趣的问题。你的演示是正确的。这有许多可能的设备。用几行很难解决。当然,数学可以在这里提供帮助!将发布 php 转换。
猜你喜欢
  • 1970-01-01
  • 2014-12-20
  • 1970-01-01
  • 2020-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-23
  • 1970-01-01
相关资源
最近更新 更多