Is there an algorithm for automatic sizing and distributing squares/rectangles in a window?
我试图找到这样的算法,但到目前为止我没有成功,希望你能帮助我。提前致谢!
所以我的问题是:我有一个画布。通过单击一个按钮,我可以创建一个矩形。当我有一个矩形时,它被绘制以占据大部分画布。当我再次按下它时,会出现一个新的矩形,然后重新绘制两个矩形以占据几乎一半的可用画布。然后创建第三个矩形,将三个矩形分布在两排,以保持每个矩形的长宽比例一定,尽可能多的占据画布。依此类推,对于 n 个矩形,请参见图片:
是否有任何众所周知的算法可以做到这一点?
谢谢!
您的矩形都具有相同的大小,因此您的任务是为您的布局找到最佳的行数和列数。布局由边界矩形、矩形数量 k 和首选宽高比 α* 以及矩形之间的间隙 d 组成:
1 2 3 4 5 6 7 8 9 | const box = { count: 7, alpha: 1.2, gap: 8, nrow: 0, // to be determined ... ncol: 0, // ... width: 0, // ... height: 0, // ... }; |
一个非常简单的算法会根据输入找到列数 m 的第一个猜测值,然后尝试几个 m 以找到最大面积,同时保持合理的纵横比。
你的总面积是 A = W · H。一个盒子的面积是 a = w · h 或 a = h / α,其中 α = w / h。理论最大面积(如果间隙为 0)是 a* = A / k,其中 k 是矩形的数量。您可以使用它来估计 w 的第一个猜测,然后估计列数 m.
我们优化的"分数"是必须最大化的区域。为了不允许出现令人不快的纵横比,我们通过将分数除以误差的平方 (α ? α*)2 来合并当前纵横比 α。
这是一种可以实现的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | function layout(canvas) { let A = canvas.width * canvas.height; let a = A / box.count; let x = Math.sqrt(a * box.alpha); let m = (canvas.width / x) | 0 - 2; if (m < 1) m = 1; let best = 0.0; for (;;) { let n = (((box.count - 1) / m) | 0) + 1; let w = (canvas.width - (m - 1) * box.gap) / m; let h = (canvas.height - (n - 1) * box.gap) / n; if (h < 0) h = 0; if (w < 0) w = 0; let alpha = w / h; let area = box.count * (w + box.gap) * (h + box.gap); let dalpha = alpha - box.alpha; let score = area / (dalpha * dalpha); if (score < best) break; box.width = w; box.height = h; box.ncol = m; box.nrow = n; best = score; m++; } } |
当然还有改进的余地,例如在猜测第一枪时。您可以在 jsbin 上进行粗略的实现。