Ser*_*ver 4 algorithm math rectangles
我有 N 个矩形,所有的尺寸都相同rectWidth * rectHeight。我有一个尺寸为areaWidth * areaHeight的区域。我想在保持矩形纵横比的区域内放置 N 个矩形,调整矩形的大小以使其适合。矩形之间我想要的间隔空间。
矩形的尺寸应该是多少才能将它们全部放在矩形内并保持纵横比?
设 N 个矩形。
让矩形的大小为 (cw, ch),其中 0 < c ≤ 1。
让您想要适应的区域大小为 (W, H)。
让 s ≥ 0 为矩形之间的间距。
水平堆叠的 a > 0 个矩形的水平尺寸为 acw + (a - 1)s。
我们知道 acw + (a - 1)s ≤ W。
垂直堆叠的 b > 0 矩形的垂直尺寸为 bch + (b - 1)s。
我们知道 bch + (b - 1)s ≤ H。
然后我们有以下优化问题。
max c
受
a ≤ (W + s) / (cw + s)
b ≤ (H + s) / (ch + s)
ab ≥ N
0 < c ≤ 1
a, b > 0 和整数
现在考虑以下不等式。
a ≤ (W + s) / (cw + s)
b ≤ (H + s) / (ch + s)
任何最佳解决方案都必须至少使其中一个成为严格的不等式。
即,对于最优解 (a, b, c) 至少满足以下条件之一。
a = (W + s) / (cw + s) ↔ c = (W - s(a - 1)) / wa
b = (H + s) / (ch + s) ↔ c = (H - s(b) - 1)) / wb
让我们不失一般性地假设 a = (W + s) / (cw + s) 成立。
由于 a 必须采用 {1, 2, ..., N}
中的值之一,因此c 必须采用 {W / w, (W - s) / 2w, (W - 2s) / 3w 中的值之一, ..., (W - (N - 1)s) / Nw}。
类似的推理给出了在第二个不等式(对于 b)严格的情况下必须从 c 中得出的值列表。
如果合并这两个值列表,则在最佳解决方案中 c 最多可以有 2N 个可能值。对这些值进行排序,然后二分搜索此列表中存在可行 a 和 b 的最大 c。
检查 c 的值是否可行的方法是设置
a = floor((W + s) / (cw + s))
b = floor((H + s) / (ch + s))
然后检查那个ab?N。
这个 JavaScript 解决方案怎么样?
var areaHeight = window.innerHeight; //set here your area height
var areaWidth = window.innerWidth; //set here your area width
var N = 216; //set amount of rectangles you want to fit
var rectRatio = 9/4; //set rectangle ratio
var gutter = [5, 10]; //set x and y spacing between rectangles
var cols, rows, rectHeight, rectWidth; //variables that we need to calculate
Run Code Online (Sandbox Code Playgroud)
该函数假设矩形(画布)网格始终适合容器区域的高度。您向函数提供行数,它会计算矩形大小并确定画布宽度是否大于容器宽度。如果画布更大,我们执行 rows++ 并再次调用该函数。
function rowIterator(iterator) {
rows = iterator;
cols = Math.ceil(N/rows);
rectHeight = (areaHeight - (rows-1)*gutter[1])/rows;
rectWidth = rectHeight*rectRatio;
if (cols * rectWidth + (cols - 1)*gutter[0] > areaWidth) {
rowIterator(rows + 1);
}
}
rowIterator(1); //feed initial value
var size1 = [rectWidth, rectHeight];
Run Code Online (Sandbox Code Playgroud)
如果您还关心找到最大矩形大小而不仅仅是适合它,那么还应该对列进行迭代,并且应该选择更大的矩形大小:
function colIterator(iterator) {
cols = iterator;
rows = Math.ceil(N/cols);
rectWidth = (areaWidth - (cols - 1)*gutter[0])/cols;
rectHeight = rectWidth/rectRatio;
if (rows * rectHeight + (rows - 1)*gutter[1] > areaHeight) {
colIterator(cols + 1);
}
}
colIterator(1);
var size2 = [rectWidth, rectHeight];
Run Code Online (Sandbox Code Playgroud)
两个迭代器的迭代总数约为 N,最大矩形大小为:
optimalRectSize = [Math.max(size1[0], size2[0]), Math.max(size1[1], size2[1])]
Run Code Online (Sandbox Code Playgroud)