The flaw here in Android's VelocityTracker
class that if your velocity in the X direction exceeds the maxVelocity it is changed equal maxVelocity and the same for the Y. But, that means that if we are going at 20° angle and at a speed of 200, and our maxVelocity is 20. Our velocity is changed to be 20*sqrt (2) at a 45° angle. The correct answer is to scale the mXVelocity and mYVeloicity by the ratio of the actual velocity and maxVelocity.
My question is do I have to resort to two square-roots to fix this error?
Velocity is the direction and speed of an object. Changing the direction because of the maximum velocity was reached must be considered a defect. This also clearly causes a flaw in that a diagonal velocity is faster than the orthogonal one.
The problematic bit of code akin to:
mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) : Math.min(accumX, maxVelocity);
mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) : Math.min(accumY, maxVelocity);
To work around this I use:
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;
}
Is there some way to do avoid the double square-root? Or some other thing that otherwise fixes this screwy bug?
Update:
The answer seems to be scale both components according to the one component that exceeds the maximum velocity by the most. This isn't strictly scaling according to the actual velocity but it fixes the bulk of the problem with easy math.
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;
}
}