Pas cher algorithme pour trouver la mesure de l'angle entre les vecteurs
Trouver l'angle entre les deux vecteurs n'est pas difficile en utilisant le cosinus de la règle. Cependant, parce que je suis de programmation pour une plate-forme avec des ressources très limitées, je tiens à éviter des calculs tels que sqrt
et arccos
. Même de simples divisions devrait être limitée autant que possible.
Heureusement, je n'ai pas besoin de l'angle en soi, mais seulement besoin d'une certaine valeur qui est proportionnelle à ladite angle.
Je suis à la recherche pour certains le calcul à bas prix algorithme pour calculer une quantité qui est lié à l'angle entre deux vecteurs. Jusqu'à présent, je n'ai pas trouvé quelque chose qui correspond à la facture, et je n'ai pas été en mesure de venir avec quelque chose de moi-même.
- hmm: question importante: les composantes des vecteurs stockés en virgule fixe ou flottante format de point?
- Ni. Depuis les coordonnées en question sont de pixel de coordonnées, ils sont toujours des valeurs entières. Pas de virgule flottante/point fixe est nécessaire. Donc, je suppose que vous pourriez dire qu'ils sont point fixe avec un multiplicateur de 1 🙂
Vous devez vous connecter pour publier un commentaire.
Avez-vous essayé un CORDIC algorithme? C'est un cadre général pour la résolution de polar ↔ rectangulaire problèmes avec seulement ajouter/soustraire/bitshift + table, essentiellement du fait de la rotation par les angles de la forme tan-1 (2n). Vous pouvez compromis de précision avec des temps d'exécution en modifiant le nombre d'itérations.
Dans votre cas, prenez un vecteur comme un point de référence fixe, et la copie de l'autre, un vecteur temporaire, qui vous tourner à l'aide de la cordic angles vers le premier vecteur (environ bissection) jusqu'à ce que vous atteignez un souhaité précision angulaire.
(edit: utiliser le signe du produit scalaire de déterminer à chaque étape s'il faut faire pivoter vers l'avant ou vers l'arrière. Bien que si multiplie sont assez bon marché pour permettre à l'aide de produit scalaire, alors ne vous embêtez pas avec CORDIC, peut-être utiliser une table de sin/cos paires de matrices de rotation de l'angle π/2n pour résoudre le problème avec la bissection.)
(edit: j'aime Eric Bainville de la suggestion dans les commentaires: faites pivoter les deux vecteurs vers zéro et de garder trace de la différence d'angle.)
Si vous n'avez pas besoin du réel euclidien angle, mais quelque chose que vous pouvez utiliser comme base pour l'angle des comparaisons, puis, changeant de taxi de la géométrie peut être un choix, parce que vous pouvez les déposer à la trigonométrie et c'est la lenteur, tout en maintenant LA PRÉCISION (ou au moins avec vraiment mineur de perdre de la précision, voir ci-dessous).
Dans les principaux navigateur moderne moteurs de l'accélération facteur est entre 1,44 - 15.2 et la précision est presque le même que dans atan2. Le calcul de diamant, l'angle est de moyenne 5.01 fois plus rapide que atan2 et à l'aide de code en ligne dans Firefox 18 l'accélération atteint facteur 15.2. Comparaison de la vitesse: http://jsperf.com/diamond-angle-vs-atan2/2.
Le code est très simple:
Le code ci-dessus vous donne un angle entre 0 et 4, tandis que atan2 vous donne l'angle entre-PI et PI, comme le montre le tableau suivant:
Noter que le diamant, l'angle est toujours positive et dans la gamme de 0 à 4, tandis que atan2 donne aussi négatif radians. Afin de diamant de l'angle est un peu plus normal. Et une autre remarque est que atan2 donne un peu de résultat plus précis, parce que la longueur de la gamme est 2*pi (ie 6.283185307179586), tandis que des diamants, des angles, il est de 4. Dans la pratique, cela n'est pas très important, par exemple. rad 2.3000000000000001 et 2.3000000000000002 sont à la fois des diamants, des angles 1.4718731421442295, mais si l'on baisse la précision par la chute d'un zéro, rad 2.300000000000001 et 2.300000000000002 donne à la fois de différents diamant angle. Cette "précision perdre" des diamants, des angles est si petit, qu'il a une certaine influence significative seulement si les distances sont énormes. Vous pouvez jouer avec les conversions en http://jsbin.com/bewodonase/1/edit?output (Ancienne version: http://jsbin.com/idoyon/1):
Le code ci-dessus est assez rapide pour l'angle de comparaisons, mais dans de nombreux cas, il est nécessaire de convertir le diamant de l'angle en radians et vice verca. Si par exemple vous. ont une certaine tolérance comme radian angles, et puis vous avez une 100 000 fois la boucle où cette tolérance est comparé à d'autres angles, il n'est pas sage de faire des comparaisons à l'aide de atan2. Au lieu de cela, avant de faire la boucle, vous modifiez le radian tolérance de taxi (diamant angles) de la tolérance et de faire en boucle des comparaisons à l'aide de diamant de la tolérance et de cette façon vous n'avez pas à utiliser de ralentir les fonctions trigonométriques de vitesse dans les parties critiques du code ( = dans les boucles).
Le code qui effectue cette conversion est: est-ce
Comme vous le remarquez qu'il y a
cos
etsin
. Comme vous le savez, ils sont lents, mais vous n'avez pas à faire la conversion en boucle, mais avant de faire la boucle et l'accélération est énorme.Et si pour une raison quelconque, vous devez les convertir en diamant angle en radians, par exemple. après le bouclage et d'angle comparaisons de revenir par exemple. l'angle minimum de comparaisons ou quoi que radians, le code est comme suit:
Ici, vous utilisez
atan2
, qui est lent, mais l'idée est d'utiliser ce en dehors de toute boucle. Vous ne pouvez pas convertir diamant angle en radians par simple multiplication par un facteur, mais au lieu de trouver un point dans le taxi de la géométrie de qui de diamant de l'angle entre ce point et l'axe X positif est le diamant de l'angle en question et la conversion de ce point de radians à l'aide de atan2.Cela devrait être assez rapide pour l'angle de comparaisons.
Bien sûr, il ya d'autres atan2 speedup techniques (par exemple. CORDIC et de tables de recherche), mais autant que je sache, ils sont tous en vrac précision et peut être encore, plus lent que atan2.
CONTEXTE: j'ai testé plusieurs techniques: point des produits, l'intérieur des produits, de la loi du cosinus, unité des cercles, des tables de recherche etc. mais rien n'a été suffisant dans le cas où à la fois la vitesse et la précision sont importantes. Enfin j'ai trouvé une page en http://www.freesteel.co.uk/wpblog/2009/06/encoding-2d-angles-without-trigonometry/ qui a les fonctions souhaitées et les principes.
Je suppose d'abord que aussi taxi distances pourraient être utilisés précis et rapide de la distance des comparaisons, parce que la plus grande distance euclidienne est plus grand aussi en taxi. J'ai réalisé que, contrairement aux distances euclidiennes, l'angle entre le début et la fin du point a d'effet sur le taxi à distance. Seulement longueurs verticale et horizontale des vecteurs peuvent être convertis facilement et rapidement entre euclidienne et de taxi, mais dans tous les autres cas, vous devez prendre de l'angle en compte et puis le processus est trop lent (?).
Donc en conclusion, je pense que la vitesse des applications critiques, où est une boucle ou la récursivité de plusieurs comparaisons des angles et/ou les distances, les angles sont plus rapides à comparer en taxi de l'espace et des distances euclidiennes (carré, sans l'aide de sqrt) de l'espace.
Retour dans la journée de quelques K de mémoire vive et des machines avec peu de fonctions mathématiques, j'ai utilisé les tables de recherche et de l'interpolation linéaire. L'idée de base est simple: créer un tableau avec autant de résolution que vous avez besoin de plus d'éléments de réduire l'erreur créée par interpolation). Puis d'interpolation entre les valeurs de recherche.
Voici un exemple dans le traitement (original lien mort).
Vous pouvez le faire avec vos autres fonctions trigonométriques ainsi. Sur le processeur 6502 cela a permis en 3D fil des graphiques de l'image à être calculée avec un ordre de grandeur de la vitesse d'augmentation.
Ici, DONC je n'ai pas encore le privilège de commenter (si j'ai en maths.se) c'est en fait une réponse à Timo post sur diamant angles.
L'ensemble du concept de diamant angles basé sur la norme L1 est le plus intéressant, et si c'était simplement une comparaison dont le vecteur a plus de/moins de w.r.t. l'axe X positif, il serait suffisant. Cependant, l'OP a fait mention de l'angle entre les deux génériques de vecteurs, et je présume que l'OP veut le comparer à une certaine tolérance pour trouver la douceur/d'angle de statut ou qqch comme ça, mais malheureusement, il semble que seulement avec les formules fournies sur jsperf.com ou freesteel.co.royaume-uni (liens ci-dessus), il semble qu'il n'est pas possible de le faire à l'aide de diamant angles.
Observer le résultat suivant de mon Asymptote de la mise en œuvre de la formule:
De sorte que le point est que vous ne pouvez pas faire de diamant(alpha)-diamant(bêta) et de la comparer à une certaine tolérance à la différence que vous pouvez faire avec la sortie de atan2. Si tout ce que vous voulez faire est de diamant(alpha)>diamant(bêta) alors je suppose que le diamant est fine.
La solution serait trivial si les vecteurs ont été définis/stocké à l'aide de coordonnées polaires au lieu de coordonnées cartésiennes (ou, 'ainsi que' l'aide de coordonnées cartésiennes).
produit scalaire de deux vecteurs (x1, y1) et (x2, y2) est
et est équivalent au produit des longueurs des deux vecteurs fois le cosinus de l'angle entre eux.
Donc, si vous normaliser les deux vecteurs de première (diviser les coordonnées de la longueur)
Puis vecteurs normés sont
Et produit scalaire de vecteurs normés (qui est le même que le cosinus de l'angle entre les vecteurs) serait
bien sûr, cela peut être tout aussi difficile de calcul calculer le cosinus
si vous avez besoin de calculer la racine carrée, alors envisager l'utilisation de la invsqrt hack.
La croix du produit est proportionnelle à l'angle entre deux vecteurs, et lorsque les vecteurs sont normalisés et l'angle est petit, le produit vectoriel est très proche de l'angle en radians en raison du faible angle de rapprochement.
spécifiquement:
I1Q2-I2Q1 est proportionnelle à l'angle entre I1Q1 et I2Q2.
La produit scalaire pourrait fonctionner dans votre cas. Ce n'est pas proportionnelle à l'angle, mais "liées".