2010-10-29 29 views
3

Je code un algorithme de flocage en Java mais je suis bloqué à un certain point (en utilisant les bibliothèques Ardor3D, en un plan 2D).Trouver l'angle delta à utiliser pour la rotation donnée avec la position, la rotation initiale et le point cible à 'face vers'

Fondamentalement, j'ai besoin de trouver la différence d'angle à ajouter à la rotation actuelle. Si vous ne pouvez obtenir que le point avec des coordonnées polaires avec 0 degs au nord et pas la différence, ne vous inquiétez pas - j'ai une méthode qui retourne la différence d'angle en tenant compte du bouclage sur l'angle et les angles négatifs.

alt text

En ce moment, je le code suivant, qui clairement ne pas fonctionner puisque l'algorithme n'a pas de référence à la rotation initiale:

long tpf = currUpdateTimeMS - lastUpdateTimeMS; 

    Vector2 pos = new Vector2(); 
    rt.getPosition(pos); 

    double rot = pos.angleBetween(app.getAvgBoidPos(new Vector2()).normalizeLocal()); 
    rt.setRotation(rot); 

    pos.addLocal(
    Math.cos((rot - MathUtils.HALF_PI)) * (tpf/10f), 
    Math.sin((rot - MathUtils.HALF_PI)) * (tpf/10f) 
); 
    rt.setPosition(pos); 

    super.updateLogic(); 

code mis à jour (ne fonctionne pas, de première réponse):

long tpf = currUpdateTimeMS - lastUpdateTimeMS; 
    //rt.setRotation(rt.getRotation() + ((tpf/(ROT_SPEED/2f)) % 360)); 

    Vector2 avgpos = app.getAvgBoidPos(new Vector2()); 
    Vector2 pos = rt.getPosition(new Vector2()); 
    avgpos.subtractLocal(pos); 

    double angleRads = rt.getRotation() * FastMath.DEG_TO_RAD; 
    double rot = MathUtils.acos((
     (avgpos.getX() * MathUtils.sin(angleRads) 
    ) + 
     (avgpos.getY() * MathUtils.cos(angleRads) 
    ))/((Math.pow(avgpos.getX(), 2) + Math.pow(avgpos.getY(), 2)) * 0.5)); 

    double adegdiff = rot * FastMath.RAD_TO_DEG; 

    rt.setRotation(rt.getRotation() - adegdiff); 
    double newrot = rt.getRotation(); 

    pos.addLocal(
     Math.cos((newrot - MathUtils.HALF_PI)) * (tpf/10f), 
     Math.sin((newrot - MathUtils.HALF_PI)) * (tpf/10f) 
    ); 
    rt.setPosition(pos); 

    super.updateLogic(); 

Une autre modification en fonction de l'autre réponse:

long tpf = currUpdateTimeMS - lastUpdateTimeMS; 
    //rt.setRotation(rt.getRotation() + ((tpf/(ROT_SPEED/2f)) % 360)); 

    Vector2 avgpos = app.getAvgBoidPos(new Vector2()); 
    Vector2 pos = rt.getPosition(new Vector2()); 
    avgpos.subtractLocal(pos); 

    double rot = pos.angleBetween(
     app.getAvgBoidPos(new Vector2()).normalizeLocal() 
    ) - (rt.getRotation() * MathUtils.DEG_TO_RAD); 

    rt.setRotation(rt.getRotation() - (rot * MathUtils.RAD_TO_DEG)); 
    double newrot = rt.getRotation(); 

    pos.addLocal(
     Math.cos((newrot - MathUtils.HALF_PI)) * (tpf/10f), 
     Math.sin((newrot - MathUtils.HALF_PI)) * (tpf/10f) 
    ); 
    rt.setPosition(pos); 

    super.updateLogic(); 

Je ne suis pas vraiment trop bon à des problèmes mathématiques, donc le code serait utile plutôt que des formules :)

Entrées

  • Position actuelle de l'entité
  • rotation actuelle de l'entité (polaire à orientation) en degrés

sortie

  • degrés ou radians pour ajouter ou soustraire à la rotation actuelle
  • ... ou degrés ou radians exprimés en angle polaire orienté

Merci à l'avance si vous pouvez aider :)

Chris

+0

Alors 'rt.getPosition' donne la position de l'entité et' app.getAvgBOIDPos' donne la position cible, est ce droit ? Et qu'est-ce qui donne l'orientation de l'entité? – Beta

+0

Ce serait rt.getRotation(), qui est exprimé en degrés polaires :) –

+0

Oups, vous avez oublié de dire que vous avez raison à propos de l'application, getAvgBoidPos() donnant l'emplacement moyen des entités pour que l'entité se déplace vers . –

Répondre

2

Vous pouvez utiliser le produit scalaire pour déterminer le cosinus de l'angle (en radians) entre l'orientation actuelle et le point auquel vous souhaitez faire face. Supposons que l'agent effectuant la visualisation est situé à l'origine et orienté pour faire face à une certaine direction donnée par l'angle θ par rapport à l'axe Y (c'est-à-dire 0 degrés est "haut" ou "nord"). Vous voulez trouver la différence angulaire θ 'entre cette direction et face à un point (x, y). Cela est donné par:

θ' = cos-1[(x*sin(θ) + y*cos(θ))/sqrt(x2 + y2)]

Soustraire θ 'de θ orientera l'agent vers la cible.

Si l'agent n'est pas à l'origine, il suffit de soustraire la position de l'agent de l'objet pour l'afficher sous la forme ci-dessus.

+0

J'ai compris. Je vais essayer de l'implémenter et de revenir vers vous s'il y a un problème :) –

+0

Je l'ai implémenté, mais ça ne semble pas fonctionner. Je pense que les éléments x et y de la position obtiennent NaN en raison de la division par zéro quelque part? Quoi qu'il en soit, j'ai mis à jour la question avec le nouveau code :) –

+0

@Chris Dennett: Je pense que j'ai essayé d'être trop intelligent pour mon propre bien. Vous avez multiplié le dénominateur par 1/2. J'essayais de l'exprimer en l'élevant à la puissance de 1/2 qui est la racine carrée. Pour certaines valeurs de x et y, cela pourrait résulter en ce que le quotient ne soit pas dans la plage de [-1, 1], ce qui se traduira par NaN lorsque vous en prenez l'acos. J'ai mis à jour mon équation pour mieux le montrer. – andand

0

Voici une implémentation sur la façon de trouver l'angle entre deux vecteurs d'origine commune.cela a été piraté ensemble basé sur l'algorithme décrit là: http://www.wikihow.com/Find-the-Angle-Between-Two-Vectors

public class DeltaDoodle { 

    private double delta(ColumnVector v1,ColumnVector v2) throws Exception{ 
     double sp=scalarProduct(v1,v2); 
     double magV1=magnitude(v1); 
     double magV2=magnitude(v2); 
     return Math.acos(sp/(magV1*magV2)) * (180/Math.PI); 
    } 

    private double scalarProduct(ColumnVector a, ColumnVector b) { 
     return (a.x*b.x) + (a.y*b.y); 
    } 
    private double magnitude(ColumnVector a){ 
     return Math.sqrt((a.x*a.x) + (a.y*a.y)); 
    } 

    public static void main(String[] args) { 
     DeltaDoodle v=new DeltaDoodle(); 
     try { 
      System.out.println("angle: " + v.delta(new ColumnVector(5, 5), new ColumnVector(1,1))); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

} 

public class ColumnVector { 
    public final double x, y; 

    public ColumnVector(double x1, double x2) { 
     this.x = x1; 
     this.y = x2; 
    } 
} 

espoir qui aide ...

0

Si je comprends ces fonctions correctement, cela pourrait fonctionner:

Vector2 pos = new Vector2(); 
rt.getPosition(pos); 

double rot = pos.angleBetween(app.getAvgBoidPos(new Vector2()).normalizeLocal()) - rt.getRotation(); 

PS Oublié de mentionner: ce rot est destiné à être la différence d'angle. Tournez l'entité par autant et il devrait pointer vers la cible.

EDIT:
Merci, le code ne aide (je l'avais mal interprété angleBetween). Permettez-moi d'essayer à nouveau:

Voici le vecteur de l'entité au point (pardonnez-moi si je reçois la syntaxe mal, je ne sais pas java):

Vector2 pos = new Vector2(); 
rt.getPosition(pos); 

Vector2 direction = app.getAvgBoidPos(new Vector2()); 
direction.subtractLocal(pos); 

Maintenant, on normalise pour obtenir un vecteur unitaire pointant vers le point et prendre la différence d'angle:

double rot = rt.getRotation().angleBetween(direction.normalizeLocal()) 
+0

Ne fonctionne pas:/Voici le code source Vector2 si cela aide: http://ardorlabs.trac.cvsdude.com/Ardor3Dv1/browser/trunk/ardor3d-core/src/main/java/com/ardor3d/math/Vector2 .java? rev = 152 –

1

légèrement hors sujet, mais vous trouverez peut-être l'essaim de particules et promenez code dans notre paquet d'effets (ardor3d effets) intéressants.

Ils se trouvent dans le svn ardeur, ou ici:

http://ardorlabs.trac.cvsdude.com/Ardor3Dv1/browser/trunk/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/

+0

Oh, bravo Renanse! : D –

+0

D'ailleurs, ce n'est pas vraiment hors-sujet car la chose que je voulais implémenter est de toute façon grouillante :) L'élément 'find average position' en fait partie, et je l'ai fait fonctionner. Mais il y a aussi d'autres éléments du problème, qui semblent avoir été résolus ici :) –

+0

Le seul problème est que le code de particules n'a pas de rotation et de vitesse que je pourrais faire - il a seulement la vitesse dans x , y et z. Mais cela ne devrait pas être si difficile à convertir entre eux.Si je fais de la vitesse un produit de la rotation et de la vitesse (j'ai déjà les formules), ça devrait aller. –