将矩形包装成矩形,生成网格坐标

问题描述 投票:1回答:1

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

这似乎是一个相当简单的问题,但不是在这里寻求建议。

这是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

php algorithm rectangles packing
1个回答
1
投票
您的问题有两个方面:您想创建一个具有

n个矩形的规则网格,该矩形可能跨越多个单元格,并且希望随机分布单元格边界的坐标。

所以我提出了下面的算法:

    确定网格中的行数和列数,以便每个单元格或多或少都是正方形。
  • 创建一个1×1单元格的矩形网格。单元格的数量将大于
  • n
合并两个相邻的单元格,直到有
  • n
  • 个单元格。现在为单元格边界创建随机轴。如果您有
  • m
  • 列,请创建一个递增值的数组,以使第一个坐标为0,最后一个坐标为原始ractangle的宽度。您可以通过创建一个递增的随机数列表,然后使用整体宽度进行标准化来实现此目的。最后,使用单元格的信息(位置,单元格跨度)和随机轴创建实际的矩形。
  • 此算法使用矩形的两种表示形式:首先,它创建“单元格”,其中包含有关其行和列索引以及范围的信息。实际输出是具有左侧,顶部,宽度和高度信息的矩形。

    我不熟悉PHP,所以这里是Java语言的实现。我认为您可以看到它是如何工作的:

    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中的ss * ((x / s) | 0)将它们捕捉为任何网格大小s * intval(x / s)
  • 该代码不太在乎美观。它会选择像元大小和要随机合并的像元,这样您可能会得到交叉接头,看起来不太好。您可以稍微影响结果的规律性:

      确定列和行的数量时,必须在结果中添加一个,以便在每种情况下都可以合并单元格。 (即使您有一个正方形并且将平方数作为
    • n
  • 传递,也将获得连接的矩形。)如果添加更多,您将获得更多的连接矩形,结果看起来将更加不规则。Math.random()返回0到1之间的随机数。创建轴时,我在结果中加了0.5,这样就不会得到非常狭窄的单元格。如果添加得更少,则坐标将更加不规则;如果添加得更多,则坐标将更均匀地分布。
  • 也许通过使行坐标均匀并且丛集坐标不规则,可以获得很好的效果。
  • 您在评论中提到了好看的属性。当创建网格并放置具有约束的矩形而不是先创建网格然后去除接缝时,创建美观的结构可能会更容易。
  • © www.soinside.com 2019 - 2024. All rights reserved.