views:

77

answers:

3

Hi, I'm coding a flocking algorithm in Java but I'm stuck at a certain point (using the Ardor3D libraries, in a 2D plane).

Basically, I need to find the angle difference to add to the current rotation. If you can only get the way it should be pointing with polar coordinates with 0 degs at north and not the difference, not to worry -- I have a method which returns the angle difference taking into account the wraparound on the angle and negative angles.

alt text

At the moment, I have the following code, which clearly wouldn't work since the algorithm has no reference to the initial rotation:

  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();

Updated code (not working, from first answer):

    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();

Another modification based on the other answer:

    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();

I'm not really too good at Maths problems, so code would be helpful rather than formulas :)

Inputs

  • Current position of entity
  • Current rotation of entity (polar-oriented) in degrees

Output

  • Degrees or radians to add or subtract to current rotation
  • ... or degrees or radians expressed as polar-oriented angle

Thanks in advance if you can help :)

Chris

+2  A: 
andand
Got it. I'll try implementing this and come back to you if there's any problem :)
Chris Dennett
I implemented it, but it doesn't seem to be working. I think the x and y elements of position are getting NaN due to division by zero somewhere? Anyway, I updated the question with the new code :)
Chris Dennett
@Chris Dennett: I think I tried to be too clever for my own good. You multiplied the denominator by 1/2. I was trying to express it as raising it to the power of 1/2 which is the square root. For some values of x and y this could result in the quotient not being in the range of [-1, 1] which will result in NaN when you take the acos of it. I've updated my equation to better show this.
andand
Oh, oops :) Will fix the code and see if this works. Cheers!
Chris Dennett
A: 

heres an implementation on how to find the angle beetween two vectors with a common origin. this has been hacked together based on the algorithm described there: 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;
    }
}

hope that helps...

smeg4brains
A: 

If I understand these functions correctly, this might just work:

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

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

P.S. Forgot to mention: this rot is intended to be the angle difference. Rotate the entity by this much and it should be pointing toward the target.

EDIT:
Thanks, the code does help (I had misconstrued angleBetween). Let me try again:

Here is the vector from the entity to the point (pardon me if I get the syntax wrong, I don't know java):

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

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

Now we normalize it to get a unit vector pointing toward the point, and take the angle difference:

double rot = rt.getRotation().angleBetween(direction.normalizeLocal())
Beta
Not working :/ Here is the Vector2 source code if it helps: http://ardorlabs.trac.cvsdude.com/Ardor3Dv1/browser/trunk/ardor3d-core/src/main/java/com/ardor3d/math/Vector2.java?rev=152
Chris Dennett