2

AndroidVelocityTracker课程中的缺陷是,如果您在 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;
    }
}
4

2 回答 2

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

这是 FISR 的 Java 实现。

警告:FISR 是为老一代的英特尔 CPU 设计的,这些 CPU 在浮点运算(尤其是除法,上面的代码仍然使用)上很慢,而不是在 ARM(一种常见的架构)上运行的 JIT 虚拟机(如 Java)安卓)。请记住分析您的代码以查看平方根成本是否足以优化,然后衡量 FISR 是否提供了有价值的改进。

于 2016-12-29T20:51:22.130 回答
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;
    }
}
于 2017-01-03T21:58:03.667 回答