好的,经过一些实验和阅读android源码后,我学到了一点……首先,看来我不必担心在我的手势库中创建不同的手势来覆盖不同的角度旋转或我的圆形手势的方向(顺时针/逆时针)。默认情况下,GestureStore 使用 SEQUENCE_SENSITIVE 的序列类型(意味着起点和终点很重要)和 ORIENTATION_SENSITIVE 的方向样式(意味着旋转角度很重要)。但是,可以使用 'setOrientationStyle(ORIENTATION_INVARIANT)' 和 setSequenceType(SEQUENCE_INVARIANT) 覆盖这些默认值。
此外,引用源中的 cmets...“当使用 SEQUENCE_SENSITIVE 时,当前仅允许单笔手势”和“ORIENTATION_SENSITIVE 和 ORIENTATION_INVARIANT 仅用于 SEQUENCE_SENSITIVE 手势”。
有趣的是,ORIENTATION_SENSITIVE 似乎不仅仅意味着“方向很重要”。它的值为 2,与它相关的 cmets 和一些相关的(未记录的)常量意味着您可以请求不同级别的灵敏度。
// at most 2 directions can be recognized
public static final int ORIENTATION_SENSITIVE = 2;
// at most 4 directions can be recognized
static final int ORIENTATION_SENSITIVE_4 = 4;
// at most 8 directions can be recognized
static final int ORIENTATION_SENSITIVE_8 = 8;
在调用 GestureLibary.recognize() 期间,方向类型值(1、2、4 或 8)作为参数 numOrientations 传递给 GestureUtils.minimumCosineDistance(),因此执行一些超出我的计算支付等级(见下文)。如果有人可以解释这一点,我很感兴趣。我知道它正在计算两个手势之间的角度差,但我不明白它使用 numOrientations 参数的方式。我的期望是,如果我指定值 2,它会找到手势 A 和手势 B 的两个变体之间的最小距离——一个变体是“正常 B”,另一个是 B 旋转 180 度。因此,我希望值 8 会考虑 B 的 8 个变体,相隔 45 度。但是,即使我不完全理解下面的数学,在我看来,在任何计算中都不会直接使用 numOrientations 值 4 或 8,尽管大于 2 的值确实会导致不同的代码路径。也许这就是为什么那些其他值没有记录的原因。
/**
* Calculates the "minimum" cosine distance between two instances.
*
* @param vector1
* @param vector2
* @param numOrientations the maximum number of orientation allowed
* @return the distance between the two instances (between 0 and Math.PI)
*/
static float minimumCosineDistance(float[] vector1, float[] vector2, int numOrientations) {
final int len = vector1.length;
float a = 0;
float b = 0;
for (int i = 0; i < len; i += 2) {
a += vector1[i] * vector2[i] + vector1[i + 1] * vector2[i + 1];
b += vector1[i] * vector2[i + 1] - vector1[i + 1] * vector2[i];
}
if (a != 0) {
final float tan = b/a;
final double angle = Math.atan(tan);
if (numOrientations > 2 && Math.abs(angle) >= Math.PI / numOrientations) {
return (float) Math.acos(a);
} else {
final double cosine = Math.cos(angle);
final double sine = cosine * tan;
return (float) Math.acos(a * cosine + b * sine);
}
} else {
return (float) Math.PI / 2;
}
}
根据我的阅读,我推测最简单和最好的方法是存储一个圆形手势,将序列类型和方向设置为不变。这样,无论方向或方向如何,任何圆形都应该匹配得很好。所以我试了一下,它确实返回了高分(在大约 25 到 70 的范围内),几乎所有与圆形相似的东西。但是,对于甚至不接近圆形的手势(水平线、V 形等),它也返回了 20 左右的分数。所以,我对应该匹配和不应该匹配之间的分离感觉不好。似乎效果最好的是存储两个手势,每个方向一个,并结合使用 SEQUENCE_SENSITIVE 和 ORIENTATION_INVARIANT。对于任何模糊的圆形动作,我的得分为 2.5 或更高,但对于非圆形手势,得分低于 1(或根本不匹配)。