将矩形划分为N个近正方形单元格的尺寸及偏移计算算法
画布近1:1比例单元格分割算法
核心分割规则
分割目标是尽可能让所有单元格宽高比接近1:1,拆分逻辑固定为:
- 对任意待拆分矩形,若高度大于宽度,沿垂直(高度)方向对半拆分,得到的两个子块宽度与原块一致,高度为原块的1/2
- 若宽度大于等于高度,沿水平(宽度)方向对半拆分,得到的两个子块高度与原块一致,宽度为原块的1/2
- 重复拆分操作,直到得到的单元格总数等于目标数量
符合规则的分割效果参考:
不符合规则的反例参考:
计算逻辑
用队列实现广度优先拆分即可,步骤如下:
- 初始化队列,队列中初始只有1个矩形块,对应整个画布范围,参数为
xOffset=0, yOffset=0, width=画布总宽度, height=画布总高度 - 当队列内块总数小于目标单元格数时,取出队首的块,按照上述规则拆分为2个子块,计算好两个子块的偏移量和尺寸后放回队列
- 当队列内块总数等于目标单元格数时,队列中所有块的参数就是最终绘制需要的宽高和偏移量
给定参数计算示例
已知参数:目标单元格数=6,画布高度=600,画布宽度=400,拆分过程如下:
- 初始队列共1个块:尺寸400*600,高比宽大,垂直拆分
- 拆分后队列共2个块:均为400*300,偏移分别为(0,0)、(0,300),块数不足6,继续拆分
- 取出队首400300块,宽比高大,水平拆分为2个200300块,偏移(0,0)、(200,0),队列总块数变为3
- 取出队首400300块(偏移0,300),宽比高大,水平拆分为2个200300块,偏移(0,300)、(200,300),队列总块数变为4
- 取出队首200300块(偏移0,0),高比宽大,垂直拆分为2个200150块,偏移(0,0)、(0,150),队列总块数变为5
- 取出队首200300块(偏移200,0),高比宽大,垂直拆分为2个200150块,偏移(200,0)、(200,150),队列总块数变为6,拆分结束
最终6个单元格的绘制参数:
| xOffset | yOffset | width | height |
|---|---|---|---|
| 0 | 300 | 200 | 300 |
| 200 | 300 | 200 | 300 |
| 0 | 0 | 200 | 150 |
| 0 | 150 | 200 | 150 |
| 200 | 0 | 200 | 150 |
| 200 | 150 | 200 | 150 |
可直接复用的代码实现(JavaScript)
function generateCells(cellCount, canvasWidth, canvasHeight) { // 初始队列放入整个画布块 const cells = [{ xOffset: 0, yOffset: 0, width: canvasWidth, height: canvasHeight }]; while (cells.length < cellCount) { const current = cells.shift(); if (current.height > current.width) { // 沿高度方向拆分 const halfHeight = current.height / 2; cells.push({ xOffset: current.xOffset, yOffset: current.yOffset, width: current.width, height: halfHeight }); cells.push({ xOffset: current.xOffset, yOffset: current.yOffset + halfHeight, width: current.width, height: halfHeight }); } else { // 沿宽度方向拆分 const halfWidth = current.width / 2; cells.push({ xOffset: current.xOffset, yOffset: current.yOffset, width: halfWidth, height: current.height }); cells.push({ xOffset: current.xOffset + halfWidth, yOffset: current.yOffset, width: halfWidth, height: current.height }); } } return cells; } // 调用示例 const cellList = generateCells(6, 400, 600); // 遍历绘制所有单元格 cellList.forEach(cell => { draw(cell.xOffset, cell.yOffset, cell.width, cell.height); });
内容的提问来源于stack exchange,提问作者grabury
相关产品推荐
相关产品推荐



