【问题标题】:Exposé Layout AlgorithmExposé 布局算法
【发布时间】:2011-05-25 01:50:27
【问题描述】:

我正在制作一些类似于 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 的绝对值。

注意:您可能会注意到这没有优化根本

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

【问题讨论】:

  • 任何信息都会很好。我不知道要研究什么,我似乎找不到任何东西。只需为问题取一个通用名称即可。
  • 如果没有先验知识,您至少必须查看每个人的尺寸,所以这已经是 O(n)。除非您有其他信息,否则我看不出任何合理的方法可以使它成为 O(1)。
  • 项目都具有相同的纵横比,并且只要它们的纵横比相同就可以调整大小。你可以看它,因为它们的宽度是纵横比,它们的高度是 1,所以尺寸是已知值。

标签: algorithm math user-interface layout


【解决方案1】:

你可以打包物品

  1. 没有水平间隙
  2. 没有垂直间隙

好的,让我们在没有垂直间隙的情况下打包。那么横向间隙为:

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);
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多