Exposé布局算法

时间:2010-12-14 05:00:42

标签: algorithm math user-interface layout

我正在制作的东西与Mac OS X在Exposé中的窗口类似。它适应项目的纵横比和可用区域的纵横比。

基本上,可用区域分为行和列。项目放在每个单元格(行和列的交集)中。尽管单元格的宽高比,但项目必须保持其宽高比(此处为width / height)。单元格数必须大于或等于项目数。在单元格数大于项目数的情况下,最后一行将不会被充分利用。 目标是尽可能多地使用项目的可用区域。我很确定每个单元格的宽高比与项目的宽高比越接近越好。

当可用区域的宽高比等于项目的宽高比时,以下情况很有效:

rows    := round(sqrt(count));
columns := ceiling(sqrt(count));

其中:count是项目数; round(x)x四舍五入到最接近的整数值,将中间情况从零点四舍五入;并且ceiling(x)返回不小于x的最小整数值。

我知道Compiz使用以下类似算法,但它没有考虑项目和可用区域的宽高比:

rows    := floor(sqrt(count + 1));
columns := ceiling(count / rows);

其中:floor(x)返回不大于x的最大整数值。

我将以下O(n)算法放在一起,该算法测试行和列的每个组合并寻找最佳拟合,但肯定有一个O(1)算法,因为这产生与第一个完全相同的结果(O( 1))当项目和可用区域的纵横比相同时的算法:

fit (itemCount, itemRatio, availableRatio)
{
    bestRows := infinity;
    bestColumns := infinity;
    bestDiff := infinity;

    for (rows := 1; rows <= count; rows += 1)
    {
        columns := ceiling(count / rows);

        cellWidth  := availableRatio / columns;
        cellHeight := 1.0 / rows;
        cellRatio := cellWidth / cellHeight;

        diff := abs(cellRatio - itemRatio);

        if (diff < bestDiff)
        {
            bestRows := rows;
            bestColumns := columns;
            bestDiff := diff;

            if (diff = 0)
                break;
        }
    }

    return (bestRows, bestColumns);
}

其中:abs(x)返回x的绝对值。

注意:您可能会注意到它未经过优化

那么,尽可能使用最可用区域的最佳方法是什么? (换句话说,我如何找到最合适的?)

1 个答案:

答案 0 :(得分:0)

您可以使用

打包这些项目
  1. 没有水平差距
  2. 没有垂直差距
  3. 好吧,让我们打包没有垂直差距。然后水平间隙是:

    Gh = nrows * availRatio - ncolumns * itemRatio
    

    或用N

    编写
    Gh = x * availRatio - N * itemRatio / x
    

    Gh接近0

    x² = N * itemRatio / availRatio
    x = sqrt(N * itemRatio / availRatio)
    

    你必须检查ceil(x)和floor(x),y​​ = floor(N / x)

    没有水平间隙产量的包装:

    y = sqrt(N * availRatio / itemRatio)
    

    你必须检查ceil(y)和floor(y),x = floor(N / y)

    因此,最多有4种组合来检查差距。然后选择具有最小正间隙的那个。

    fit (itemCount, itemRatio, availableRatio) {
        x := sqrt(itemcount * itemRatio / availableRatio);
        x1 := floor(x);
        y1 := ceil(itemCount / x1);
        x2 := ceil(x);
        y2 := ceil(itemCount / x2);
    
        y := sqrt(itemcount * availableRatio / itemRatio);
        y3 := floor(x);
        x3 := ceil(itemCount / y3);
        y4 := ceil(x);
        x4 := ceil(itemCount / y4);
    
        gap := y1 * availableRatio - x1 * itemRatio;
        x := x1;
        y := y1;
    
        gap2 := y2 * availableRatio - x2 * itemRatio;
        if (gap2 >= 0 && gap2 < gap || gap < 0) {
          gap := gap2;
          x := x2;
          y := y2;
        }
    
        gap3 := x3 * itemRatio / availRatio - y3;
        if (gap3 >= 0 && gap3 < gap || gap < 0) {
          gap := gap3;
          x := x3;
          y := y3;
        }
    
        gap4 := x4 * itemRatio / availRatio - y4;
        if (gap4 >= 0 && gap4 < gap || gap < 0) {
          gap := gap4;
          x := x4;
          y := y4;
        }
    
        return (x, y);
    }
    

    除了使用间隙,您还可以使用最小区域来决定,因为最后一行/列可能没有很好地填充。