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;
}
}
答案 0 :(得分:1)
您可以删除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是为老一代的英特尔CPU而设计的,这些CPU在浮点运算(特别是上述代码仍然使用的分区)上很慢,而不是JIT的虚拟机(例如Java&#39; s)在ARM上运行(Android的常见架构)。请记住分析您的代码,看看平方根成本是否足以进行优化,然后衡量FISR是否值得进行改进。
答案 1 :(得分:0)
诀窍是不根据实际矢量的大小进行缩放,而是按最大量超出要求的分量进行缩放。然后按比例缩放x和y。它不需要比分裂更难的数学。而且根本不会影响矢量的角度。而maxVelocity的结果可以在某个角度超过实际速度因子sqrt(2)。它更符合maxVelocity所做的文档。
maxVelocity float:可由此计算的最大速度 方法。该值必须以与单位相同的单位声明 参数。该值必须为正。
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;
}
}