我试图检测触摸运动的速度,我并不总是得到我期望的结果。 (补充说:速度太快了) 任何人都可以发现,如果我正在做一些时髦或建议更好的方式吗?
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
self.previousTimestamp = event.timestamp;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.view];
CGPoint prevLocation = [touch previousLocationInView:self.view];
CGFloat distanceFromPrevious = distanceBetweenPoints(location,prevLocation);
NSTimeInterval timeSincePrevious = event.timestamp - self.previousTimestamp;
CGFloat speed = distanceFromPrevious/timeSincePrevious;
self.previousTimestamp = event.timestamp;
NSLog(@"dist %f | time %f | speed %f",distanceFromPrevious, timeSincePrevious, speed);
}
你可以尝试(在touchesBegan中将distanceSinceStart和timeSinceStart归零):
distanceSinceStart = distanceSinceStart + distanceFromPrevious;
timeSinceStart = timeSincestart + timeSincePrevious;
speed = distanceSinceStart/timeSinceStart;
这将为您提供自开始触摸以来的平均速度(总距离/总时间)。
或者你可以做一个移动平均速度,也许是一个指数移动平均线:
const float lambda = 0.8f; // the closer to 1 the higher weight to the next touch
newSpeed = (1.0 - lambda) * oldSpeed + lambda* (distanceFromPrevious/timeSincePrevious);
oldSpeed = newSpeed;
如果要为最近的值赋予更多权重,可以将lambda调整为接近1的值。
你可以尝试(在touchesBegan中将distanceSinceStart和timeSinceStart归零):
distanceSinceStart = distanceSinceStart + distanceFromPrevious;
timeSinceStart = timeSincestart + timeSincePrevious;
speed = distanceSinceStart/timeSinceStart;
这将为您提供自开始触摸以来的平均速度(总距离/总时间)。
或者你可以做一个移动平均速度,也许是一个指数移动平均线:
const float lambda = 0.8f; // the closer to 1 the higher weight to the next touch
newSpeed = (1.0 - lambda) * oldSpeed + lambda* (distanceFromPrevious/timeSincePrevious);
oldSpeed = newSpeed;
如果要为最近的值赋予更多权重,可以将lambda调整为接近1的值。
主要问题是速度计算会非常 不准确 什么时候 timeSincePrevious
非常小(几毫秒)。为了看到这一点,让我们说 timeSincePrevious
是1毫秒。然后计算出的速度将为0 distanceFromPrevious
是0,如果是1000则 distanceFromZero
是1。
出于这个原因,我建议使用lambda的以下值:
const float labmda = (timeSincePrevious>0.2? 1: timeSincePrevious/0.2);
也就是说,当我们使用一个小小的lambda时 timeSincePrevious
是小。
过滤器建议可能没问题,但它没有解决问题:峰值将被平滑,但保持不变。
如果您注销了触摸事件,那么这些峰值看起来就像是一个触摸,其前一个时间点(0.001215毫秒)的时间差非常小,之前触摸的是大时间增量。
距离= 17.269917,timeDelta = 0.016132,速度= 1070.504639
距离= 15.206906,timeDelta = 0.017494,速度= 869.251709
距离= 15.882380,timeDelta = 0.017583,速度= 903.297546
距离= 14.983324,timeDelta = 0.030101,速度= 497.771088 //低峰值
距离= 15.435349,timeDelta = 0.001215,速度= 12703.991211 //高峰!
距离= 15.882380,timeDelta = 0.017343,速度= 915.795898
距离= 15.890248,timeDelta = 0.016302,速度= 974.742249
距离= 16.560495,timeDelta = 0.016468,速度= 1005.606445
距离= 16.101242,timeDelta = 0.017291,速度= 931.201050
我所做的是计算最近触摸事件之间的平均时间增量,如果触摸有异常时间增量(±30%),我会忽略它的速度(保持前一事件的速度)