四向导航算法

时间:2012-11-16 16:39:58

标签: algorithm keyboard user-experience

考虑一个矩形帆布,包含随机大小和位置的矩形。要在这些矩形之间导航,用户可以使用四个箭头:向上,向下,向左,向右。

您是否熟悉可以产生相当简单的用户体验的任何导航算法?

我遇到了一些解决方案,但它们似乎都不合适。我知道没有解决方案是“理想的”。但是,我正在寻找的算法类型是用于仅使用箭头键在桌面上的图标之间导航的类型。

4 个答案:

答案 0 :(得分:4)

[编辑21/5/2013:正如Gene在评论中指出的那样,我的加权方案实际上并不保证每个矩形都可以从其他每个矩形到达 - 只有每个矩形都会被连接到每个方向都有一些其他矩形。]

执行此操作的一种好方法是使用maximum weighted bipartite matching

我们想要做的是构建一个定义函数f(r,d)的表,如果它们当前处于矩形r和方向d(向上,向下,向左或向右),则返回用户将移动到的矩形。对)。我们希望这个函数有一些不错的属性,例如:

  1. 必须能够到达每个其他矩形的每个矩形
  2. 按左,然后向右或向上按,或向上然后按向下,反之亦然,应该让用户在同一个地方
  3. 按下例如left应该将用户带到左边的一个矩形(这有点难以精确陈述,但我们可以使用评分系统来衡量质量)
  4. 对于每个矩形,在图形中创建4个顶点:在该矩形处可以按下的每个可能键一个顶点。对于特定的矩形r,将它们称为r U ,r D ,r L 和r R 。对于每对矩形r和s,创建4条边:

    • (r U ,s D
    • (r D ,s U
    • (r L ,s R
    • (r R ,s L

    此图有2个连通分量:一个包含所有U和D顶点,另一个包含所有L和R顶点。每个组分都是二分的,因为例如没有U顶点连接到另一个U顶点。事实上,我们可以分别在每个组件上运行最大加权二分匹配,尽管在分组之后,例如,具有L个顶点的U个顶点和具有R个顶点的D个顶点,只讨论在整个图形上运行它一次更容易。 / p>

    根据通过该对键连接的那对矩形的感知程度,为每个边分配一个非负权重。您可以自由选择此评分函数的表单,但它应该是:

    • 与矩形之间的距离成反比(您可以使用它们的中心之间的距离)和
    • 矩形中心之间的角度与所需的水平或垂直线的距离成反比,
    • 零,只要矩形方向错误(例如,如果边缘(r U ,s D ),如果r的中心实际位于中心之上S)。或者,您可以删除这些零重量边缘。

    此功能试图满足顶部的要求3.

    [编辑#2 24/5/2013:在下面添加了一个示例函数。]

    这是满足这些属性的示例函数的C-ish伪代码。它取2个矩形的中心点和矩形1的方向(矩形2的方向始终与此方向相反):

    const double MAXDISTSQUARED = /* The maximum possible squared distance */;
    const double Z = /* A +ve number. Z > 1 => distance more important than angle */
    
    // Return a weight in the range [0, 1], with higher indicating a better fit.
    double getWeight(enum direction d, int x1, int y1, int x2, int y2) {
        if (d == LEFT  && x1 < x2 ||
            d == RIGHT && x1 > x2 ||
            d == UP    && y1 < y2 ||
            d == DOWN  && y1 > y2) return 0;
    
        // Don't need to take sqrt(); in fact it's probably better not to
        double distSquared = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
        double angle = abs(atan2(x1 - x2, y1 - y2));   // 0 => horiz; PI/2 => vert
        if (d == UP || d == DOWN) angle = PI / 2 - angle;
        return 1 - pow(distSquared / MAXDISTSQUARED, Z) * (2 * angle / PI);
    }
    

    现在运行最大加权二分匹配。这将尝试找到具有最高总权重的边缘集合,使得每个顶点(或至少尽可能多的)与所选边缘相邻,但没有顶点与多于一个边缘相邻。 (如果我们允许顶点与多个边相邻,则意味着在该矩形处按下该键会将您带到多个目标矩形,这是没有意义的。)匹配对应于按键的双向,以便按下例如向上然后向下将回到原来的位置,自动满足最高要求2.

    到目前为止,这种方法不能自动满足的唯一要求是重要的一个,即数字1:它不一定能保证每个矩形都可以到达。如果我们只使用&#34; raw&#34;作为边缘权重的质量分数,对于某些配置,这实际上可能发生,例如,如果屏幕的4个角落中都有一个矩形,中间有一个矩形,则可能无法访问中心的一个矩形。

    [编辑2013年3月21日:正如Gene所说,我在新的加权方案下对我的权利1的要求是满意的,我认为这是错误的。在许多情况下,每个矩形都是可达的,但一般来说,你需要解决NP难的哈密顿循环问题来保证这一点。我会把解释留在里面,因为它会让我们有一些方法。在任何情况下,只要检测到子循环,就可以通过向上调整连接组件之间的权重来进行攻击。]

    为了保证匹配算法总是返回一个匹配,其中每个矩形都是可达的,我们需要调整边缘权重,这样匹配得分就不可能高于匹配更多边缘。这可以通过将评分函数缩放到0到1之间,并将个矩形,n添加到每个边的权重来实现。这是因为完全匹配然后得分至少为4n ^ 2(即使质量得分为0,边缘本身的权重为n且其中有4n),而任何与较少边缘匹配的得分最多4(n-1)(n + 1)= 4n ^ 2 - 4,严格地说更少。

答案 1 :(得分:2)

对于一个拿锤子的人来说,一切都像钉子一样,这是不言而喻的。最短路径算法在这里是一个明显的工具,因为最短距离似乎是直观的。

然而,我们正在设计一个UI,其中逻辑距离比物理距离重要得多。

让我们尝试不同的思考。

一个限制是反复击中向上(向右,向下或向左)箭头应该最终循环遍历所有矩形。否则一些无法接触的“孤儿”很可能。使用基于物理(2d)距离的算法来实现这一点是困难的,因为2d中的最近项可能在对应于所使用的箭头对的1d投影中处于错误的方向。即点击向上箭头可以轻松选择当前下方的框。哎哟。

所以让我们采用一个非常简单的解决方案。只需对其质心的x坐标上的所有矩形进行排序。按下右箭头和左箭头按顺序循环显示矩形:右边是下一个最高x,左边是下一个最低x。包裹在屏幕边缘。

对y坐标也一样。按此顺序使用上下循环。

成功的关键(双关语)是在循环时向屏幕添加动态信息,向用户显示正在发生的事情的逻辑。这是一个提案。其他人是可能的。

在第一个垂直(向上或向下)键上,矩形上会出现一个苍白的半透明叠加层。它们以浅红色或蓝色阴影,图案与质心的y坐标交替。在整个窗口中还存在匹配颜色的水平哈希标记。两种颜色的唯一原因是提供线条和矩形之间对应的视觉指示。当前选择的矩形是非半透明的,并且散列标记比所有其他矩形更亮。当您继续按下向上或向下键时,突出显示的框会按照上述的质心y顺序更改。如果没有箭头键敲击半秒左右,叠加层就会消失。

如果击中水平键,则会出现非常相似的叠加,只有垂直散列标记和x顺序。

作为用户,我真的很喜欢这个方案。但是YMMV。

实现这一目标所需的算法和数据结构是显而易见的,微不足道的,并且可以很好地扩展。我们将努力使覆盖层看起来很好。

NB现在我已经完成了所有的绘图,我意识到在每个方框的质心处放置一个正确着色的点以显示哪条线与它相交是个好主意。一些说明性图表如下。

裸盒

Bare boxes

正在进行向上或向下箭头的选择

Selection with up or down arrow

正在进行的左箭头或右箭头选择

Selection with left or right arrow

答案 2 :(得分:1)

如何构建运动图如下:

  • 对于任何方向,尝试沿给定方向转到最近的矩形,其中心点是当前矩形边的中间。
  • 尝试消除循环,例如从A移动'右'应该尝试产生一个不同的矩形,而不是从A向右移动。例如在this drawing中,绿色的'右'应该是橙色,即使粉色是最近的中间 - 点
  • (感谢biziclop):如果图形中无法到达任何矩形,则重新映射其中一个相邻的矩形以获取它,可能是错误最小的矩形。重复直到所有矩形都可以到达(我认为算法会终止......)

然后存储图表并仅使用它进行导航。您不希望在会话中间更改路线。

答案 3 :(得分:0)

此问题可以建模为graph问题,algorithm of navigation可以用作shortest path routing

以下是建模。

每个矩形都是图中的顶点。从每个顶点(也称为矩形),您有四个选项 - 向上,向下,向左,向右。因此,您可以达到四个不同的矩形,即此顶点将有四个邻居,您可以将这些边添加到图形中。

我不确定这是否是问题的一部分 - “可以使用特定动作(例如向上)从矩形到达多个矩形”。如果没有,上面的建模就足够了。如果是,则将所有此类顶点添加为此顶点的邻居。因此,您可能不会得到一个4正则图。否则,您将把问题建模为4个常规图。

现在,问题是how do you define your "navigation" algorithm。如果您不想区分您的操作,即上,下,左和右都相等,那么您可以为所有边添加1的权重。

如果你决定给某个特定动作优先于其他动作,比如up比其他动作更好,那么你可以给上移的边缘加权为1,其余边为2。想法是通过分配不同的权重,你可以区分你将要旅行的边缘。

如果您确定所有up边不相等,即A和B之间的向上距离短于C和D之间的向上距离,那么您可以相应地在图中为边指定权重施工过程。

这是路由

现在如何找到路线 - 您可以使用dijkstra's algorithm找到给定顶点对之间的最短路径。如果您对多个最短路径感兴趣,可以使用k-shortest path算法查找一对节点之间的k个最短路径,然后选择最佳路径。

请注意,您最终得到的图表不一定是有向图。如果您更喜欢有向图,则可以在构造边时为边指定方向。否则你应该很好地使用无向图,因为所有你关心的是使用边到达另一个顶点。此外,如果可以使用矩形A中的up来访问矩形B,则可以使用矩形rectangle B中的down来访问A。因此,如果由于其他原因不需要它们,方向确实无关紧要。如果你不喜欢我刚才做的假设,那么你需要构建有向图。

希望这有帮助。