以上maxVelocity将方向更改为对角线,解决方法

时间:2016-12-23 03:34:35

标签: android vectormath

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;
    }
}

2 个答案:

答案 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;
    }
}