我有N个矩形项目,长宽比为Aitem(X:Y) 我有一个长宽比为Aview的矩形显示区域
项目应按表格式排列(即r行,c列)。
理想的网格行x列是什么,因此单个项目最大? (行* colums> = N,当然 - 即可能有“未使用的”网格位置)。
一个简单的算法可以迭代rows = 1..N,计算所需的列数,并保持行/列对的最大项。
我想知道是否存在非迭代算法(例如,对于Aitem = Aview = 1,行/列可以用sqrt(N)近似)。
答案 0 :(得分:2)
注意:我无法理解Frédéric的答案,所以我自己解决了这个问题并提出了看似相同的解决方案。我想我也可以解释一下我做了什么,以防它有用。
首先,我将视图的宽高比标准化为项目的宽高比。 (我假设你不想旋转物品。)
a = (view_width/view_height) / (item_width/item_height)
现在用正方形包装宽度/高度比a
的矩形相当于用项目打包视图。理想的情况是我们的网格(现在是方格)完全填充矩形,这将给我们
a = c/r
其中r
和c
是行数和列数:
N = r*c
乘以/除以这两个方程给我们
N*a = c^2 N/a = r^2
c = sqrt(N*a) r = sqrt(N/a)
如果网格是完美的,r
和c
将是整数,但如果没有,则必须尝试Frédéric提到的三个选项,并保留r*c
最小的那个选项。仍然超过N
:
floor(r), ceil(c)
ceil(r), floor(c)
ceil(r), ceil(c)
答案 1 :(得分:1)
您的解决方案可以轻松改进以处理通用案例:
如果我们(临时)忘记了需要整数个行和列,我们有
rows * columns = N
x = aitem * y
aview = rows * x = rows * aitem * y
1 =列* y =(N /行)*(aview / [aitem * rows])= N * aview /(aitem *rows²)
因此rows = sqrt(N * aview / aitem)和columns = N / rows = sqrt(N * aitem / aview)
然后ceil(行)和ceil(列)是一个解决方案,而floor(行)和floor(列)太小而不能一起解决(如果行和列不是整数)。这留下了3种可能的解决方案:
编辑以更正公式。第一个结果是错误的(见评论)
答案 2 :(得分:0)
好问题。如果您的视图的尺寸为A x B(固定)且您的项目的尺寸为x b(变量,最大化),那么您需要:
trunc(A / a) * trunc(B / b) >= N
我不知道如何解决这个问题 - 截断是棘手的部分,因为它是非线性的。
答案 3 :(得分:0)
我无法获得该问题的答案对我有用,但是我找到了一个Neptilo中类似问题的简洁实现。但是,它不适用于矩形,仅适用于正方形。因此,我运用了mckeed中的想法来对矩形进行归一化,然后遵循正方形的算法。
结果是fitToContainer()
函数。给它提供适合n
,containerWidth
和containerHeight
以及原始itemWidth
和itemHeight
的矩形数量。如果商品没有原始的宽度和高度,请使用itemWidth
和itemHeight
指定所需的商品比例。
例如,fitToContainer(10, 1920, 1080, 16, 9)
产生{nrows: 4, ncols: 3, itemWidth: 480, itemHeight: 270}
,因此四列和三行480 x 270(像素或任何单位)。
要在1920x1080的相同示例区域中容纳10个正方形,您可以调用fitToContainer(10, 1920, 1080, 1, 1)
,得到{nrows: 2, ncols: 5, itemWidth: 384, itemHeight: 384}
。
function fitToContainer(n, containerWidth, containerHeight, itemWidth, itemHeight) {
// We're not necessarily dealing with squares but rectangles (itemWidth x itemHeight),
// temporarily compensate the containerWidth to handle as rectangles
containerWidth = containerWidth * itemHeight / itemWidth;
// Compute number of rows and columns, and cell size
var ratio = containerWidth / containerHeight;
var ncols_float = Math.sqrt(n * ratio);
var nrows_float = n / ncols_float;
// Find best option filling the whole height
var nrows1 = Math.ceil(nrows_float);
var ncols1 = Math.ceil(n / nrows1);
while (nrows1 * ratio < ncols1) {
nrows1++;
ncols1 = Math.ceil(n / nrows1);
}
var cell_size1 = containerHeight / nrows1;
// Find best option filling the whole width
var ncols2 = Math.ceil(ncols_float);
var nrows2 = Math.ceil(n / ncols2);
while (ncols2 < nrows2 * ratio) {
ncols2++;
nrows2 = Math.ceil(n / ncols2);
}
var cell_size2 = containerWidth / ncols2;
// Find the best values
var nrows, ncols, cell_size;
if (cell_size1 < cell_size2) {
nrows = nrows2;
ncols = ncols2;
cell_size = cell_size2;
} else {
nrows = nrows1;
ncols = ncols1;
cell_size = cell_size1;
}
// Undo compensation on width, to make squares into desired ratio
itemWidth = cell_size * itemWidth / itemHeight;
itemHeight = cell_size;
return { nrows: nrows, ncols: ncols, itemWidth: itemWidth, itemHeight: itemHeight }
}