高于 maxVelocity 将方向更改为对角线,解决方法
Above maxVelocity changes direction to diagonal, workaround
Android 的 VelocityTracker
class 中的缺陷是,如果 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 设计的,这些 CPU 在浮点运算(尤其是除法,上面的代码仍在使用)上很慢,而不是 JIT 的虚拟机(例如 Java's) 运行 在 ARM 上(Android 的通用架构)。请记住分析您的代码以查看平方根成本是否足以进行优化,然后衡量 FISR 是否提供了有价值的改进。
诀窍是不根据实际矢量的大小进行缩放,而是根据超出要求的最大量的分量进行缩放。然后按比例缩放 x 和 y。它不需要比除法更难的数学。并且根本不影响矢量的角度。虽然 maxVelocity 的结果可能会以一定角度超出实际速度 sqrt(2) 倍。它更符合 maxVelocity 功能的文档。
maxVelocity float: The maximum velocity that can be computed by this
method. This value must be declared in the same unit as the units
parameter. This value must be positive.
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;
}
}
Android 的 VelocityTracker
class 中的缺陷是,如果 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 设计的,这些 CPU 在浮点运算(尤其是除法,上面的代码仍在使用)上很慢,而不是 JIT 的虚拟机(例如 Java's) 运行 在 ARM 上(Android 的通用架构)。请记住分析您的代码以查看平方根成本是否足以进行优化,然后衡量 FISR 是否提供了有价值的改进。
诀窍是不根据实际矢量的大小进行缩放,而是根据超出要求的最大量的分量进行缩放。然后按比例缩放 x 和 y。它不需要比除法更难的数学。并且根本不影响矢量的角度。虽然 maxVelocity 的结果可能会以一定角度超出实际速度 sqrt(2) 倍。它更符合 maxVelocity 功能的文档。
maxVelocity float: The maximum velocity that can be computed by this method. This value must be declared in the same unit as the units parameter. This value must be positive.
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;
}
}