#### Howdy, Stranger!

We are about to switch to a new forum software. Until then we have removed the registration on this forum.

# turn left or right

edited January 2014

Hi all, I am having some trouble with this:
I am using the PVector class to define some moving elements in a sketch.
So an entity has:

``````PVector pos; //position
PVector vel; //velocity
PVector tar; //target position
PVector towardsTar; //direction from element to target
``````

Basic calculations:

``````float heading = vel.heading(); //ok, I have the heading angle of my element
towardsTar.set(tar);
towardsTar.sub(pos); // pos + towardsTar = tar  -->  towardsTar = tar - pos so I have my desired direction
towardsTar.normalize();
``````

Now I have these two vectors (heading and towardsTar) and I want to find the angle between them, inorder to know if the element has to turn clockwise or counterclockwise inorder to head towards the target.
If I use this:

`float angle = PVector.angleBetween(heading, towardsTar);`

I will get the right angle, but it will always be positive.
So I will not know if the entity has to turn the one or the other way.
I have managed to make a workaround for that, but my algorithm is not so good...

Is there a good and elegant way to do that? Perhaps something I have missed from the PVector class?
Please do not refer me to a library, I am just looking for a simple way to do that by defining a small function at most.

Tagged:

• edited January 2014

Just check whether the dot product of towardsTar and the normal of heading is negative or positive:

``````if(towardsTar.dot(heading.y, -heading.x, 0) < 0) // By swapping x & y (and making x negative) you get the right hand normal
println("It's going right!"); // Replace with something useful
else
println("It's going left!"); // Replace with something useful
``````

And a small example sketch:

``````PVector pos = new PVector();
PVector towardsTar = new PVector();
float angle = 0;

void setup() {

size(400, 400);
strokeWeight(4);
stroke(#ffffff);

pos.set(width / 2, height / 2);

}

void draw() {

towardsTar.set(mouseX, mouseY);
towardsTar.sub(pos);

angle += 0.01;

background(#000000);

fill(#ffffff);
text("RIGHT", 10, 10 + textAscent());
else
text("LEFT", 10, 10 + textAscent());

fill(#999999);
ellipse(pos.x, pos.y, 200, 200);
line(pos.x, pos.y, pos.x + heading.x * 100, pos.y + heading.y * 100);

}
``````
• This would definately make sense, but unfortunately the PVector.angleBetween() function only returns positive values, and (I forgot to mention) also only values from 0 to PI. So if the anlge between them is 3*PI/2, then it will return PI/2 (instead of -PI/2). I dont know why that is, but this is my problem, actually... thanks anyway

Yeah, sorry - should test code before posting. :D I corrected my answer.

Very similar to the other solution but created a small function that accepts a heading and a target vector and calculates the 'nearest' side. Anyway play with the sketch it soon becomes obvious how it works.

``````final int CLOCKWISE = 1; // Left
final int ANTI_CLOCKWISE = -1; // Right

PVector h, t;
int cx, cy;

public void setup() {
size(400, 400);
cx = width/2;
cy = height/2;
h = PVector.random2D();
h.mult(150);
t = PVector.random2D();
}

public void draw() {
background(255);
stroke(100, 100, 255);
strokeWeight(2);
line(cx, cy, cx + h.x, cy + h.y);
ellipse(cx + h.x, cy + h.y, 4, 4);

if (sign(h, t) == CLOCKWISE)
stroke(100, 255, 100);
else
stroke(255, 100, 100);
strokeWeight(1);
line(cx, cy, cx + t.x, cy + t.y);
}

public void mouseMoved() {
t.x = mouseX - cx;
t.y = mouseY - cy;
}

public int sign(PVector heading, PVector target) {
return CLOCKWISE;
else
return ANTI_CLOCKWISE;
}
``````
• I still have to figure out how (why) your answers work... even though they do! Thanks alot, guys!

• edited January 2014

@quark: Haha nice! :D

Even shorter:

``````boolean isLeft(PVector heading, PVector target) {
}

boolean isRight(PVector heading, PVector target) {
}
``````
• edited January 2014

Well, made my own shorter version too: >:)

``````static final int sign(PVector head, PVector target) {
}
``````

And another 1: *-:)

``````void draw() {
// ...
stroke(sign(h, t) == CLOCKWISE ? #64FF64 : #FF6464);
// ...
}
``````
• Okay - the last one - I promise! :D

``````boolean isLeft(PVector heading, PVector target) {
return (Float.floatToRawIntBits(heading.y * target.x - heading.x * target.y) >> 31) == 0;
}
``````

Additionally one little reference that explains the dot product quite well.

• Sorry to bother again, but this doesn't work... Perhaps I am too tired to see why, but It has been a pain for sometime, so I thought to share once more...

``````FlockingGame g;

void setup(){
size(600,600);
g = new FlockingGame(20);
}

void draw(){
background(0);
g.update();
}

class FlockingGame{
ArrayList birds;
Target t;
FlockingGame(int num){
t = new Target();
birds = new ArrayList();
for(int i = 0; i <num; i++){
}
}
void update(){
t.update();
for(int i = 0; i<birds.size(); i++){
Bird b = (Bird) birds.get(i);
b.update(t.getPos());
}
}
}

class Bird{
PVector pos;
PVector vel; //velocity
PVector tar;
float tsa; //turn step angle
Bird(){
pos = new PVector();
tar = new PVector();
pos.x = random(0,600);
pos.y = random(0,600);
vel = PVector.random2D();
tsa = PI/50;
}
void update(PVector inTar){
tar.set(inTar);
float r = tsa * sign(vel,tar);
vel.rotate(r);
show();
}

int sign(PVector vel, PVector tar) {
int a = (int) Math.signum(vel.y*tar.x - vel.x*tar.y);
return a;
}

void show(){
pushMatrix();
translate(pos.x,pos.y);
beginShape();
vertex(-3,0);
vertex(0,-10);
vertex(3,0);
endShape(CLOSE);
popMatrix();
}
}

class Target{
PVector pos;
Target(){
pos = new PVector(mouseX,mouseY,0);
}
void update(){
/*pos.x = mouseX;
pos.y = mouseY;*/
pos.x = 300;
pos.y = 300;
pos.z = 0;
show();
}
PVector getPos(){
return pos;
}
void show(){
fill(255,0,0);
noStroke();
ellipse(pos.x,pos.y,10,10);
}
}
``````
• ok, I found out what was wrong...
I was comparing vel to tar, while I should be coparing vel to towardsTar (tar-pos)...
fixed it for now... thanks for all the help again