2016-12-23 1 views
2

La faille ici dans la classe VelocityTracker d'Android que si votre vitesse dans la direction X dépasse la vitesse maxVelocity, elle est égale à maxVelocity et la même chose pour le Y. Mais, cela signifie que si nous allons à un angle de 20 ° et à une vitesse de 200, et notre maxVelocity est de 20. Notre vitesse est modifiée pour être de 20 * sqrt (2) à un angle de 45 °. La bonne réponse consiste à mettre à l'échelle le mXVelocity et le mYVeloicity par le rapport de la vitesse réelle et de la maxVelocity.ci-dessus maxVelocity change de direction en diagonale, contournement

Ma question est de savoir si je dois recourir à deux racines carrées pour corriger cette erreur?

La vitesse est la direction et la vitesse d'un objet. Changer la direction en raison de la vitesse maximale a été atteint doit être considéré comme un défaut. Cela entraîne également une lacune en ce sens qu'une vitesse diagonale est plus rapide que la vitesse orthogonale.

Le bit problématique d'un code semblable à:

mXVelocity = accumX < 0.0f ? Math.max(accumX, -maxVelocity) : Math.min(accumX, maxVelocity); 
mYVelocity = accumY < 0.0f ? Math.max(accumY, -maxVelocity) : Math.min(accumY, maxVelocity); 

Pour contourner ce que j'utilise:

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

Est-il possible de ne pas éviter la double racine carrée? Ou une autre chose qui résout autrement ce bug visqueux?


Update:

La réponse semble être échelle deux composants selon l'une composante qui dépasse la vitesse maximale par le plus. Ce n'est pas strictement l'échelle en fonction de la vitesse réelle, mais il résout la majeure partie du problème avec des mathématiques faciles.

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

Note aux lecteurs: Le code de la faille dans la question est 'VelocityTracker.computeCurrentVelocity (unités, MaxVelocity) d'Android', pas le code de la asker. – leewz

Répondre

1

Vous pouvez couper Math.sqrt(maxVelocitySq), parce que vous savez maxVelocitySq = maxVelocity * maxVelocity. Même sans cela, vous pouvez utiliser un seul sqrt() en faisant la première division:

double excessFactor = Math.sqrt(maxVelocitySq/actualVelocitySq); 

Mathématiquement, je crois prennent une racine carrée est nécessaire, mais comment vous prenez la racine carrée est toujours ouverte pour vous. En particulier, Fast Inverse Square Root fonctionne pour votre utilisation. Voici le code utilisant fisr().

if (actualVelocitySq > maxVelocitySq) { 
    double excessFactor = fisr(actualVelocitySq/maxVelocitySq); 
    velocityX *= excessFactor; 
    velocityY *= excessFactor; 
} 

Here's a Java implementation of FISR.

caveat: FISR a été conçu pour une ancienne génération de processeurs Intel qui étaient lents à opérations en virgule flottante (division en particulier, que le code ci-dessus utilise encore), pas une machine virtuelle JIT'd (comme Java) fonctionnant sur ARM (une architecture commune pour Android). N'oubliez pas de profiler votre code pour voir si le coût de la racine carrée est suffisamment important pour optimiser, puis de mesurer si le FISR donne une amélioration valable.

+0

Je jure que j'avais couru les numéros et ne pouvais pas faire la division en premier, mais apparemment pas comme c'est clairement le cas. Juste vérifié les graphiques et oui, doit avoir mal fait à la main. Je jure qu'il y a des mathématiques vectorielles qui peuvent effectivement éviter les racines carrées dans les cas où je pensais qu'elles devraient être nécessaires. Bien que deviner et vérifier se retrouverait avec l'algorithme de la racine carrée. Donc, à moins qu'il y ait un moyen de résoudre le résultat de l'ampleur sans résoudre pour l'ampleur, il pourrait exiger de telles choses. – Tatarize

+0

1. Vous avez peut-être utilisé la division entière dans vos tests. 2. Une manière de normaliser sans sqrt signifierait que FISR n'a pas besoin d'exister. Vous pouvez l'éviter dans les cas où le vecteur est multiplié par sa longueur, cependant. 3. Êtes-vous sûr que la racine carrée est coûteuse? La vitesse de calcul est déjà coûteuse. 4. Ne pas deviner et vérifier, mais l'approximation de Newton. Un sqrt personnalisé peut faire moins d'itérations que le sqrt intégré. – leewz

+0

L'objectif serait de ne pas normaliser en théorie. Mais, venez à la même réponse générale que la normalisation vous donnerait. Même si vous avez triché et normalisé à maxX et maxY à maxVelocity. Puisque les triangles x, y, v sont congruents avec X, Y, V. Si nous mettons à l'échelle selon maxX ou maxY plutôt que V, nous pouvons simplement mettre à l'échelle en fonction du facteur de mise à l'échelle maximum requis du composant. Et appliquez ce maximum à l'autre aussi. Ainsi, X ou Y reste à maxVelocity mais ne change pas le vecteur réel, sans utiliser de racine carrée. – Tatarize

0

L'astuce consiste à ne pas mettre à l'échelle en fonction de l'amplitude du vecteur réel mais plutôt de la composante qui a le plus dépassé le besoin. Puis mettre à l'échelle x et y par cela. Il ne nécessite aucune mathématique plus difficile que la division. Et ne fubar l'angle du vecteur du tout. Tandis que le résultat de la maxVelocity pourrait, d'un certain angle, dépasser la vitesse réelle d'un facteur de sqrt (2). Il se conforme mieux à la documentation de ce que fait MaxVelocity.

maxVelocity float: Vitesse maximale pouvant être calculée par cette méthode . Cette valeur doit être déclarée dans la même unité que le paramètre . Cette valeur doit être 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; 
    } 
}