Android VelocityTracker
类中的缺陷在于,如果您在X方向上的速度超过maxVelocity,则将其更改为等于maxVelocity,并且对于Y进行更改。但是,这意味着如果我们以20°角和以200,我们的maxVelocity为20。我们的速度在45°角处更改为20 * sqrt(2)。正确的答案是通过实际速度与maxVelocity之比来缩放mXVelocity和mYVeloicity。
我的问题是我是否必须求助于两个平方根才能解决此错误?
速度是物体的方向和速度。由于达到了最大速度而改变方向必须视为缺陷。这显然也引起缺陷,即对角速度比正交速度快。
有问题的代码类似于:
mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) : Math.min(accumX, maxVelocity);
mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) : Math.min(accumY, maxVelocity);
要解决此问题,我使用:
tracker.computeCurrentVelocity(units); //maxVelocity
double velocityX = tracker.getXVelocity();
double velocityY = tracker.getYVelocity();
double actualVelocitySq = velocityX * velocityX + velocityY * velocityY;
double maxVelocitySq = maxVelocity * maxVelocity;
if (actualVelocitySq > maxVelocitySq) {
//double excessFactor = Math.sqrt(maxVelocitySq) / Math.sqrt(actualVelocitySq);
double excessFactor = Math.sqrt(maxVelocitySq/actualVelocitySq); //leewz's optimization
velocityX *= excessFactor;
velocityY *= excessFactor;
}
有什么办法可以避免双平方根?还是其他可以解决此棘手错误的东西?
更新:
答案似乎是根据最大超过最大速度的一个分量来缩放两个分量。这并不是严格按照实际速度进行缩放,而是通过简单的数学方法解决了大部分问题。
double scale;
double vectorX = Math.abs(velocityX);
double vectorY = Math.abs(velocityY);
if (vectorX > maxVelocity) {
scale = maxVelocity / vectorX;
if (vectorY > maxVelocity) {
scale = Math.min(scale, maxVelocity / vectorY);
}
velocityX *= scale;
velocityY *= scale;
} else {
if (vectorY > maxVelocity) {
scale = maxVelocity / vectorY;
velocityX *= scale;
velocityY *= scale;
}
}
最佳答案
您可以删除Math.sqrt(maxVelocitySq)
,因为您知道maxVelocitySq = maxVelocity * maxVelocity
。即使没有,也可以通过先进行除法来使用单个sqrt()
:
double excessFactor = Math.sqrt(maxVelocitySq / actualVelocitySq);
从数学上讲,我认为求平方根是必需的,但是如何求平方根仍然对您开放。特别地,Fast Inverse Square Root适用于您的用例。这是使用
fisr()
的代码。if (actualVelocitySq > maxVelocitySq) {
double excessFactor = fisr(actualVelocitySq / maxVelocitySq);
velocityX *= excessFactor;
velocityY *= excessFactor;
}
Here's a Java implementation of FISR.
注意事项:FISR是为较老的Intel CPU设计的,这些Intel CPU的浮点运算速度很慢(特别是除法,上面的代码仍然使用该运算法则),而不是在ARM(通用体系结构)上运行的JIT虚拟机(例如Java)对于Android)。切记对代码进行概要分析,以查看平方根成本是否足够显着优化,然后评估FISR是否带来了有价值的改进。